package com.google.code.joto.ui.tree;
import java.awt.event.ActionEvent;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import javax.swing.JPopupMenu;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeNode;
import org.apache.commons.collections.Predicate;
import org.apache.commons.collections.PredicateUtils;
import org.apache.commons.collections.iterators.IteratorEnumeration;
import com.google.code.joto.eventrecorder.RecordEventSummary;
import com.google.code.joto.eventrecorder.predicate.RecordEventSummaryPredicateUtils;
import com.google.code.joto.eventrecorder.spy.calls.MethodCallEventUtils;
import com.google.code.joto.ui.JotoContext;
import com.google.code.joto.ui.filter.RecordEventFilterFile;
import com.google.code.joto.util.CompoundEnumeration;
import com.google.code.joto.util.SortedListTreeMap;
import com.google.code.joto.util.ui.JMenuItemUtils;
/**
*
*/
public class AggrRecordEventTemplateTreeNodeAST {
/**
*
*/
public static abstract class AbstractAggrEventTreeNode implements TreeNode, Serializable {
/** internal for java.io.Serializable */
private static final long serialVersionUID = 1L;
private AbstractAggrEventTreeNode parent;
private String name;
protected AbstractAggrEventTreeNode(AbstractAggrEventTreeNode parent, String name) {
this.parent = parent;
this.name = name;
}
public AbstractAggrEventTreeNode getParent() {
return parent;
}
public String getName() {
return name;
}
@Override
public boolean getAllowsChildren() {
return true;
}
@Override
public boolean isLeaf() {
return false;
}
/** used by CellRenderer */
public String getDisplayLabel() {
return getName();
}
@Override
public String toString() {
return name;
}
protected RootPackageAggrEventTreeNode getRootTreeNode() {
RootPackageAggrEventTreeNode res = null;
for(AbstractAggrEventTreeNode p = this; p != null; p = p.parent) {
if (p instanceof RootPackageAggrEventTreeNode) {
res = (RootPackageAggrEventTreeNode) p;
break;
}
}
return res;
}
public int getChildDepth(AbstractAggrEventTreeNode node) {
int res = 0;
for(AbstractAggrEventTreeNode p = node; p != null; p = p.parent) {
if (p instanceof RootPackageAggrEventTreeNode) {
break;
}
res++;
}
return res;
}
protected DefaultTreeModel getRootTreeModel() {
RootPackageAggrEventTreeNode rootNode = getRootTreeNode();
return (rootNode != null)? rootNode.treeModel : null;
}
public JotoContext getContext() {
RootPackageAggrEventTreeNode rootNode = getRootTreeNode();
return (rootNode != null)? rootNode.getContext() : null;
}
protected void fireNodeAdded(AbstractAggrEventTreeNode node, int childIndex) {
DefaultTreeModel treeModel = getRootTreeModel();
if (treeModel == null) return;
int[] childIndices = new int[] { childIndex };
treeModel.nodesWereInserted(node.getParent(), childIndices);
}
protected void fireNodeRemoved(AbstractAggrEventTreeNode node, int childIndex) {
DefaultTreeModel treeModel = getRootTreeModel();
if (treeModel == null) return;
int[] childIndices = new int[] { childIndex };
treeModel.nodesWereRemoved(node.getParent(), childIndices, new TreeNode[] { node });
}
protected void fireNodeChanged(AbstractAggrEventTreeNode node, int childIndex) {
DefaultTreeModel treeModel = getRootTreeModel();
if (treeModel == null) return;
int[] childIndices = new int[] { childIndex };
treeModel.nodesChanged(node, childIndices);
}
// public void fillCtxMenu(JPopupMenu ctxMenu) {
// // do nothing, cf overriden methods
// }
public abstract void fillCtxMenu(JPopupMenu ctxMenu);
}
/**
*
*/
public static class PackageAggrEventTreeNode extends AbstractAggrEventTreeNode {
/** internal for java.io.Serializable */
private static final long serialVersionUID = 1L;
private String fullPackageName;
private SortedListTreeMap<String,PackageAggrEventTreeNode> childPackageTreeNode = new SortedListTreeMap<String,PackageAggrEventTreeNode>();
private SortedListTreeMap<String,ClassAggrEventTreeNode> childClassTreeNode = new SortedListTreeMap<String,ClassAggrEventTreeNode>();
// ------------------------------------------------------------------------
public PackageAggrEventTreeNode(PackageAggrEventTreeNode parent, String packageName) {
super(parent, packageName);
this.fullPackageName = (parent != null && !(parent instanceof RootPackageAggrEventTreeNode))?
parent.getFullPackageName() + "." + packageName : packageName;
}
// ------------------------------------------------------------------------
public String getFullPackageName() {
return fullPackageName;
}
public String getChildPackageName() {
return super.getName();
}
public PackageAggrEventTreeNode getOrCreateChildPackage(String childPackageName) {
if (childPackageName.contains(".")) {
throw new IllegalArgumentException("bad sub package name '" + childPackageName + "', should not contains '.'");
}
PackageAggrEventTreeNode res = childPackageTreeNode.get(childPackageName);
if (res == null) {
res = new PackageAggrEventTreeNode(this, childPackageName);
childPackageTreeNode.put(childPackageName, res);
int childIndex = childPackageTreeNode.indexOf(res);
fireNodeAdded(res, childIndex);
}
return res;
}
public PackageAggrEventTreeNode getOrCreateRecursiveChildPackage(String fullPackageName) {
PackageAggrEventTreeNode res;
int indexDot = fullPackageName.indexOf('.');
if (indexDot != -1) {
String immediatePackageName = fullPackageName.substring(0, indexDot);
String remainingPackages = fullPackageName.substring(indexDot + 1);
PackageAggrEventTreeNode immediatePackage = getOrCreateChildPackage(immediatePackageName);
res = immediatePackage.getOrCreateRecursiveChildPackage(remainingPackages); // recursive call
} else {
res = getOrCreateChildPackage(fullPackageName);
}
return res;
}
public ClassAggrEventTreeNode getOrCreateChildClass(String simpleClassName) {
ClassAggrEventTreeNode res = childClassTreeNode.get(simpleClassName);
if (res == null) {
res = new ClassAggrEventTreeNode(this, simpleClassName);
childClassTreeNode.put(simpleClassName, res);
int childIndex = childClassTreeNode.indexOf(res);
fireNodeAdded(res, childIndex);
}
return res;
}
public ClassAggrEventTreeNode getOrCreateRecursiveChildClass(String fullClassName) {
int indexLastDot = fullClassName.lastIndexOf('.');
if (indexLastDot == -1) {
return getOrCreateChildClass(fullClassName);
}
String simpleClassName = fullClassName.substring(indexLastDot + 1);
String packageFullName = fullClassName.substring(0, indexLastDot);
PackageAggrEventTreeNode pck = getOrCreateRecursiveChildPackage(packageFullName);
ClassAggrEventTreeNode res = pck.getOrCreateChildClass(simpleClassName);
return res;
}
// implements TreeNode
// ------------------------------------------------------------------------
@Override
public TreeNode getChildAt(int childIndex) {
TreeNode res;
if (childIndex < childPackageTreeNode.size()) {
res = childPackageTreeNode.getAt(childIndex);
} else {
int classIndex = childIndex - childPackageTreeNode.size();
if (classIndex >= 0 && classIndex < childClassTreeNode.size()) {
res = childClassTreeNode.getAt(classIndex);
} else {
res = null; // should not occur?!
}
}
return res;
}
@Override
public int getChildCount() {
return childPackageTreeNode.size() + childClassTreeNode.size();
}
@Override
public int getIndex(TreeNode node) {
int res = -1;
if (node instanceof PackageAggrEventTreeNode) {
res = childPackageTreeNode.indexOf(node);
} else if (node instanceof ClassAggrEventTreeNode) {
res = childClassTreeNode.indexOf(node);
}
return res;
}
@SuppressWarnings({ "unchecked", "rawtypes" })
@Override
public Enumeration<AbstractAggrEventTreeNode> children() {
return new CompoundEnumeration(
childPackageTreeNode.enumeration(),
childClassTreeNode.enumeration());
}
public void fillCtxMenu(JPopupMenu ctxMenu) {
ctxMenu.add(JMenuItemUtils.snew("create exclude quick filter ~Package", this, "onCtxMenuItemCreateQuickFilter"));
}
public void onCtxMenuItemCreateQuickFilter(ActionEvent event) {
JotoContext context = getContext();
String fullPackageName = getFullPackageName();
RecordEventFilterFile filter = new RecordEventFilterFile();
filter.setDescription("package~ " + fullPackageName);
filter.setActive(true);
// TODO filter is not created as persistent yet...
// filter.setPersistentFile(persistentFile);
Predicate eventIncludePredicate =
RecordEventSummaryPredicateUtils.snewDefaultClassMethodPredicate(fullPackageName + ".*", null);
Predicate eventPredicate = PredicateUtils.notPredicate(eventIncludePredicate);
filter.setEventPredicate(eventPredicate);
filter.setEventTypePredicateDescription(MethodCallEventUtils.METHODCALL_EVENT_TYPE);
filter.setEventClassNamePredicateDescription(fullPackageName + ".**");
context.addMethodCallFilter(filter);
}
public String toString() {
return "PackageNode[" + fullPackageName + "]";
}
}
/**
*
*/
public static class RootPackageAggrEventTreeNode extends PackageAggrEventTreeNode {
/** internal for java.io.Serializable */
private static final long serialVersionUID = 1L;
private JotoContext context;
private DefaultTreeModel treeModel;
/** param ... DefaultTreeModel treeModel can not be set here .... chicken-egg pb => set init() next !*/
public RootPackageAggrEventTreeNode(JotoContext context) {
super(null, "");
this.context = context;
}
public JotoContext getContext() {
return context;
}
public void setInit(DefaultTreeModel treeModel) {
this.treeModel = treeModel;
}
public String toString() {
return "(root package)";
}
}
/**
* TreeNode corresponding to a java.lang.Class
*/
public static class ClassAggrEventTreeNode extends AbstractAggrEventTreeNode {
/** internal for java.io.Serializable */
private static final long serialVersionUID = 1L;
// private String className; ... implicit from parent fullPackageName + simpleClassName
private SortedListTreeMap<String,MethodAggrEventTreeNode> childMethods = new SortedListTreeMap<String,MethodAggrEventTreeNode>();
// ------------------------------------------------------------------------
public ClassAggrEventTreeNode(PackageAggrEventTreeNode parentPackage, String simpleClassName) {
super(parentPackage, simpleClassName);
}
// ------------------------------------------------------------------------
public String getSimpleClassName() {
return super.getName();
}
public PackageAggrEventTreeNode getParentPackageNode() {
return (PackageAggrEventTreeNode) super.getParent();
}
public String getFullClassName() {
return getParentPackageNode().getFullPackageName() + "." + getSimpleClassName();
}
public MethodAggrEventTreeNode getOrCreateMethod(String methodName) {
MethodAggrEventTreeNode res = childMethods.get(methodName);
if (res == null) {
res = new MethodAggrEventTreeNode(this, methodName);
childMethods.put(methodName, res);
int childIndex = childMethods.indexOf(res);
fireNodeAdded(res, childIndex);
}
return res;
}
// implements TreeNode
// ------------------------------------------------------------------------
@Override
public TreeNode getChildAt(int childIndex) {
return childMethods.getAt(childIndex);
}
@Override
public int getChildCount() {
return childMethods.size();
}
@Override
public int getIndex(TreeNode node) {
return childMethods.indexOf(node);
}
@Override
public Enumeration<MethodAggrEventTreeNode> children() {
return childMethods.enumeration();
}
public String toString() {
return "ClassNode[" + getSimpleClassName() + "]";
}
public void fillCtxMenu(JPopupMenu ctxMenu) {
ctxMenu.add(JMenuItemUtils.snew("create exclude quick filter ~Class", this, "onCtxMenuItemCreateQuickFilter"));
}
public void onCtxMenuItemCreateQuickFilter(ActionEvent event) {
JotoContext context = getContext();
ClassAggrEventTreeNode classNode = this;
String className = classNode.getFullClassName();
String simpleClassName = classNode.getSimpleClassName();
RecordEventFilterFile filter = new RecordEventFilterFile();
filter.setDescription("class ~ " + simpleClassName);
filter.setActive(true);
// TODO filter is not created as persistent yet...
// filter.setPersistentFile(persistentFile);
Predicate eventIncludePredicate =
RecordEventSummaryPredicateUtils.snewDefaultClassMethodPredicate(className, null);
Predicate eventPredicate = PredicateUtils.notPredicate(eventIncludePredicate);
filter.setEventPredicate(eventPredicate);
filter.setEventTypePredicateDescription(MethodCallEventUtils.METHODCALL_EVENT_TYPE);
filter.setEventClassNamePredicateDescription(className);
context.addMethodCallFilter(filter);
}
}
/**
* TreeNode corresponding to a class java.lang.reflect.Method
*/
public static class MethodAggrEventTreeNode extends AbstractAggrEventTreeNode {
/** internal for java.io.Serializable */
private static final long serialVersionUID = 1L;
// implicit from super.getName() ... private String methodSignature;
private SortedListTreeMap<String,TemplateMethodCallAggrEventTreeNode> childTemplateCalls = new SortedListTreeMap<String,TemplateMethodCallAggrEventTreeNode>();
private static final String OTHERS_TEMPLATES_KEY = "others";
private int maxTemplateCount = 10;
// ------------------------------------------------------------------------
public MethodAggrEventTreeNode(ClassAggrEventTreeNode parent, String methodName) {
super(parent, methodName);
}
// ------------------------------------------------------------------------
public String getMethodName() {
return super.getName();
}
public ClassAggrEventTreeNode getParentClassNode() {
return (ClassAggrEventTreeNode) super.getParent();
}
public TemplateMethodCallAggrEventTreeNode getOrCreateTemplateCall(String templateCallKey) {
boolean isOtherTemplates = false;
if (childTemplateCalls.size() >= maxTemplateCount) {
templateCallKey = OTHERS_TEMPLATES_KEY;
isOtherTemplates = true;
}
TemplateMethodCallAggrEventTreeNode res = childTemplateCalls.get(templateCallKey);
if (res == null) {
res = new TemplateMethodCallAggrEventTreeNode(this, templateCallKey);
if (isOtherTemplates) {
res.maxRequestResponsesCount = res.maxRequestResponsesCount * 3;
}
childTemplateCalls.put(templateCallKey, res);
int childIndex = childTemplateCalls.indexOf(res);
fireNodeAdded(res, childIndex);
}
return res;
}
// implements TreeNode
// ------------------------------------------------------------------------
@Override
public TreeNode getChildAt(int childIndex) {
return childTemplateCalls.getAt(childIndex);
}
@Override
public int getChildCount() {
return childTemplateCalls.size();
}
@Override
public int getIndex(TreeNode node) {
return childTemplateCalls.indexOf(node);
}
@Override
public Enumeration<TemplateMethodCallAggrEventTreeNode> children() {
return childTemplateCalls.enumeration();
}
public String toString() {
return "MethodNode[" + getMethodName() + "]";
}
public void fillCtxMenu(JPopupMenu ctxMenu) {
ctxMenu.add(JMenuItemUtils.snew("create exclude quick filter ~Method", this, "onCtxMenuItemCreateQuickFilter"));
}
public void onCtxMenuItemCreateQuickFilter(ActionEvent event) {
JotoContext context = getContext();
ClassAggrEventTreeNode classNode = getParentClassNode();
String className = classNode.getFullClassName();
String simpleClassName = classNode.getSimpleClassName();
String methodName = getMethodName();
RecordEventFilterFile filter = new RecordEventFilterFile();
filter.setDescription("method ~ " + simpleClassName + "." + methodName);
filter.setActive(true);
// TODO filter is not created as persistent yet...
// filter.setPersistentFile(persistentFile);
Predicate eventIncludePredicate =
RecordEventSummaryPredicateUtils.snewDefaultClassMethodPredicate(className, methodName);
Predicate eventPredicate = PredicateUtils.notPredicate(eventIncludePredicate);
filter.setEventPredicate(eventPredicate);
filter.setEventTypePredicateDescription(MethodCallEventUtils.METHODCALL_EVENT_TYPE);
filter.setEventClassNamePredicateDescription(className);
filter.setEventMethodNamePredicateDescription(methodName);
context.addMethodCallFilter(filter);
}
}
/**
* TreeNode corresponding to a list of templatized method invocation with request-response events
*/
public static class TemplateMethodCallAggrEventTreeNode extends AbstractAggrEventTreeNode {
/** internal for java.io.Serializable */
private static final long serialVersionUID = 1L;
// implicit from super.getName() ... private String methodSignature;
private int maxRequestResponsesCount = 5;
private List<MethodCallRequestResponseEventTreeNode> purgedFifoRequestResponses = new ArrayList<MethodCallRequestResponseEventTreeNode>();
// ------------------------------------------------------------------------
public TemplateMethodCallAggrEventTreeNode(MethodAggrEventTreeNode parent, String templateKey) {
super(parent, templateKey);
}
// ------------------------------------------------------------------------
public void addRequestEvent(RecordEventSummary event) {
MethodCallRequestResponseEventTreeNode e = new MethodCallRequestResponseEventTreeNode(this, event);
if (purgedFifoRequestResponses.size() >= maxRequestResponsesCount) {
MethodCallRequestResponseEventTreeNode purged = (MethodCallRequestResponseEventTreeNode) purgedFifoRequestResponses.remove(0);
fireNodeRemoved(purged, 0);
}
purgedFifoRequestResponses.add(e);
int childIndex = purgedFifoRequestResponses.size() -1;
fireNodeAdded(e, childIndex);
}
public MethodCallRequestResponseEventTreeNode addResponseEvent(RecordEventSummary event) {
MethodCallRequestResponseEventTreeNode res = null;
int reqEventId = event.getCorrelatedEventId();
if (reqEventId == -1) {
return null; // should not occur : not linked to a reqest? => ignore this response
}
for (Iterator<MethodCallRequestResponseEventTreeNode> iter = purgedFifoRequestResponses.iterator(); iter.hasNext(); ) {
MethodCallRequestResponseEventTreeNode reqResp = iter.next();
if (reqResp.requestEvent.getEventId() == reqEventId) {
reqResp.responseEvent = event;
res = reqResp;
break;
}
}
return res;
}
// implements TreeNode
// ------------------------------------------------------------------------
@Override
public TreeNode getChildAt(int childIndex) {
return purgedFifoRequestResponses.get(childIndex);
}
@Override
public int getChildCount() {
return purgedFifoRequestResponses.size();
}
@Override
public int getIndex(TreeNode node) {
return purgedFifoRequestResponses.indexOf(node);
}
@Override
public Enumeration<?> children() {
return new IteratorEnumeration(purgedFifoRequestResponses.iterator());
}
public void fillCtxMenu(JPopupMenu ctxMenu) {
// ctxMenu.add(JMenuItemUtils.snew("create exclude quick filter ~TemplateMethodCall", this, "onCtxMenuItemCreateQuickFilter"));
}
public String toString() {
return "TemplateMethodCallNode[" + purgedFifoRequestResponses.size() + "]";
}
}
/**
* TreeNode corresponding to a method invocation with request-response events
*/
public static class MethodCallRequestResponseEventTreeNode extends AbstractAggrEventTreeNode {
/** internal for java.io.Serializable */
private static final long serialVersionUID = 1L;
private RecordEventSummary requestEvent;
private RecordEventSummary responseEvent;
public MethodCallRequestResponseEventTreeNode(AbstractAggrEventTreeNode parent, RecordEventSummary requestEvent) {
super(parent, "req#" + requestEvent.getEventId());
this.requestEvent = requestEvent;
}
public RecordEventSummary getRequestEvent() {
return requestEvent;
}
public RecordEventSummary getResponseEvent() {
return responseEvent;
}
public void setResponseEvent(RecordEventSummary p) {
this.responseEvent = p;
}
// implements TreeNode
// ------------------------------------------------------------------------
@Override
public boolean getAllowsChildren() {
return false;
}
@Override
public boolean isLeaf() {
return true;
}
@Override
public TreeNode getChildAt(int childIndex) {
return null;
}
@Override
public int getChildCount() {
return 0;
}
@Override
public int getIndex(TreeNode node) {
return -1;
}
@Override
public Enumeration<?> children() {
return null;
}
public void fillCtxMenu(JPopupMenu ctxMenu) {
// ctxMenu.add(JMenuItemUtils.snew("create exclude quick filter ~MethodCall", this, "onCtxMenuItemCreateQuickFilter"));
}
public String toString() {
return "MethodCallRequestResponseNode["
// + requestEvent
+ "]";
}
}
}