package rocks.inspectit.ui.rcp.editor.tree.input;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.collections.CollectionUtils;
import org.eclipse.jface.viewers.IContentProvider;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerFilter;
import rocks.inspectit.shared.all.communication.data.InvocationSequenceData;
import rocks.inspectit.shared.all.tracing.data.Span;
import rocks.inspectit.shared.cs.communication.data.InvocationSequenceDataHelper;
import rocks.inspectit.ui.rcp.editor.tree.util.TraceTreeData;
import rocks.inspectit.ui.rcp.util.ElementOccurrenceCount;
import rocks.inspectit.ui.rcp.util.OccurrenceFinderFactory;
/**
* Controller that combines all invocations belonging to one trace into a tree representing complete
* trace call hierarchy.
*
* @author Ivan Senic
*
*/
public class TraceInvocDetailsInputController extends SteppingInvocDetailInputController {
/**
* Current view input.
*/
private TraceTreeData currentInput;
/**
* Default constructor.
*/
public TraceInvocDetailsInputController() {
super(false);
}
/**
* {@inheritDoc}
*/
@Override
public boolean canOpenInput(List<? extends Object> data) {
if (null == data) {
return false;
}
if (CollectionUtils.isEmpty(data)) {
return true;
}
// we expect one trace tree data object
return data.get(0) instanceof TraceTreeData;
}
/**
* {@inheritDoc}
*/
@Override
public Object getTreeInput() {
return currentInput;
}
/**
* {@inheritDoc}
*/
@Override
public ElementOccurrenceCount countOccurrences(Object element, ViewerFilter[] filters) {
if (null != currentInput) {
return OccurrenceFinderFactory.getOccurrenceCount(TraceTreeData.collectInvocations(currentInput, new ArrayList<InvocationSequenceData>()), element, filters);
}
return ElementOccurrenceCount.emptyElement();
}
/**
* {@inheritDoc}
*/
@Override
public Object getElement(Object template, int occurance, ViewerFilter[] filters) {
if (currentInput != null) {
InvocationSequenceData found = OccurrenceFinderFactory.getOccurrence(TraceTreeData.collectInvocations(currentInput, new ArrayList<InvocationSequenceData>()), template, occurance, filters);
if (null != found) {
if (InvocationSequenceDataHelper.hasSpanIdent(found) && (template instanceof Span)) {
return spanService.get(found.getSpanIdent());
} else {
return found;
}
}
}
return null;
}
/**
* {@inheritDoc}
*/
@Override
public IContentProvider getContentProvider() {
return new ContentProvider();
}
/**
* {@inheritDoc}
*/
@SuppressWarnings("unchecked")
@Override
public Object[] getObjectsToSearch(Object treeInput) {
ArrayList<Object> objects = new ArrayList<>();
TraceTreeData data = (TraceTreeData) ((List<Object>) treeInput).get(0);
extractAllChildren(objects, data);
return objects.toArray();
}
/**
* Extracts all children from the trace tree data that can be searched for.
*
* @param objects
* list to extract to
* @param data
* trace data
*/
public void extractAllChildren(List<Object> objects, TraceTreeData data) {
objects.add(data.getSpan());
if (CollectionUtils.isNotEmpty(data.getInvocations())) {
objects.addAll(data.getInvocations());
}
for (TraceTreeData child : data.getChildren()) {
extractAllChildren(objects, child);
}
}
/**
* The content provider for this view.
*
* @author Ivan Senic
*
*/
private final class ContentProvider extends InvocDetailContentProvider {
/**
* {@inheritDoc}
*/
@SuppressWarnings("unchecked")
@Override
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
List<Object> inputList = (List<Object>) newInput;
if (CollectionUtils.isNotEmpty(inputList)) {
Object first = inputList.get(0);
if (first instanceof TraceTreeData) {
currentInput = (TraceTreeData) first;
return;
}
}
currentInput = null; // NOPMD
}
/**
* {@inheritDoc}
*/
@SuppressWarnings("unchecked")
@Override
public Object[] getElements(Object inputElement) {
List<Object> inputList = (List<Object>) inputElement;
if (CollectionUtils.isNotEmpty(inputList)) {
Object first = inputList.get(0);
if (first instanceof TraceTreeData) {
TraceTreeData data = (TraceTreeData) first;
return new Object[] { data.getSpan() };
}
}
return new Object[0];
}
/**
* {@inheritDoc}
*/
@Override
public Object[] getChildren(Object parentElement) {
if (parentElement instanceof InvocationSequenceData) {
return super.getChildren((InvocationSequenceData) parentElement);
}
if (parentElement instanceof Span) {
Span span = (Span) parentElement;
TraceTreeData traceData = TraceTreeData.getForSpanIdent(currentInput, span.getSpanIdent());
if (null != traceData) {
List<Object> objects = new ArrayList<>();
if (!span.isCaller()) {
objects.addAll(traceData.getInvocations());
// also all children that don't have invocations
for (TraceTreeData child : traceData.getChildren()) {
if (!child.getSpan().isCaller()) {
objects.add(child.getSpan());
}
}
} else {
for (TraceTreeData child : traceData.getChildren()) {
objects.add(child.getSpan());
}
}
return objects.toArray();
}
}
return new Object[0];
}
/**
* {@inheritDoc}
*/
@Override
public Object getParent(Object element) {
if ((element instanceof InvocationSequenceData)) {
return super.getParent((InvocationSequenceData) element);
}
if (element instanceof Span) {
Span span = (Span) element;
TraceTreeData traceData = TraceTreeData.getForSpanIdent(currentInput, span.getSpanIdent());
if (!span.isCaller()) {
TraceTreeData parent = traceData.getParent();
if (null != parent) {
return parent.getSpan();
}
} else {
TraceTreeData parent = traceData.getParent();
while (null != parent) {
InvocationSequenceData invoc = getForSpanIdent(parent.getInvocations(), span.getSpanIdent());
if (null != invoc) {
return invoc;
}
parent = parent.getParent();
}
}
}
return null;
}
/**
* {@inheritDoc}
*/
@Override
public boolean hasChildren(Object element) {
if (element instanceof InvocationSequenceData) {
return super.hasChildren((InvocationSequenceData) element);
}
if (element instanceof Span) {
Span span = (Span) element;
TraceTreeData traceData = TraceTreeData.getForSpanIdent(currentInput, span.getSpanIdent());
if (null != traceData) {
if (!span.isCaller()) {
return (CollectionUtils.isNotEmpty(traceData.getChildren())) || CollectionUtils.isNotEmpty(traceData.getInvocations());
} else {
return CollectionUtils.isNotEmpty(traceData.getChildren());
}
}
}
return false;
}
}
}