001: package org.drools.reteoo;
002:
003: import java.util.Arrays;
004: import java.util.HashMap;
005: import java.util.List;
006: import java.util.Map;
007:
008: import org.drools.common.BaseNode;
009: import org.drools.eclipse.editors.rete.model.Connection;
010: import org.drools.eclipse.editors.rete.model.ReteGraph;
011: import org.drools.util.Iterator;
012: import org.drools.util.ObjectHashMap;
013: import org.drools.util.ReflectiveVisitor;
014: import org.drools.util.ObjectHashMap.ObjectEntry;
015:
016: /**
017: * Produces a graph in GraphViz DOT format.
018: *
019: * @see http://www.research.att.com/sw/tools/graphviz/
020: * @see http://www.pixelglow.com/graphviz/
021: *
022: * @author Andy Barnett
023: */
024: public class ReteooVisitor extends ReflectiveVisitor {
025:
026: private static final String PACKAGE_NAME = "org.drools.reteoo.";
027:
028: /**
029: * Keeps track of visited JoinNode DOT IDs. This mapping allows the visitor
030: * to recognize JoinNodes it has already visited and as a consequence link
031: * existing nodes back together. This is vital to the Visitor being able to
032: * link two JoinNodeInputs together through their common JoinNode.
033: */
034: private final Map visitedNodes = new HashMap();
035:
036: private ReteGraph graph;
037:
038: private BaseVertex rootVertex;
039:
040: private BaseVertex parentVertex;
041:
042: /**
043: * Constructor.
044: */
045: public ReteooVisitor(final ReteGraph graph) {
046: this .graph = graph;
047: }
048:
049: public ReteGraph getGraph() {
050: return this .graph;
051: }
052:
053: public BaseVertex getRootVertex() {
054: return this .rootVertex;
055: }
056:
057: /**
058: * RuleBaseImpl visits its Rete.
059: */
060: public void visitReteooRuleBase(final ReteooRuleBase ruleBase) {
061: visit((ruleBase).getRete());
062: }
063:
064: /**
065: * Rete visits each of its ObjectTypeNodes.
066: */
067: public void visitRete(final Rete rete) {
068: this .rootVertex = (ReteVertex) this .visitedNodes
069: .get(dotId(rete));
070: if (this .rootVertex == null) {
071: this .rootVertex = new ReteVertex(rete);
072: this .visitedNodes.put(dotId(rete), this .rootVertex);
073: }
074:
075: this .graph.addChild(this .rootVertex);
076: this .parentVertex = this .rootVertex;
077:
078: final ObjectHashMap map = rete.getObjectTypeNodes();
079:
080: final Iterator it = map.iterator();
081: for (ObjectEntry entry = (ObjectEntry) it.next(); entry != null; entry = (ObjectEntry) it
082: .next()) {
083: visit(entry.getValue());
084: }
085:
086: }
087:
088: public void visitBaseNode(final BaseNode node) {
089: BaseVertex vertex = (BaseVertex) this .visitedNodes
090: .get(dotId(node));
091: if (vertex == null) {
092: try {
093: String name = node.getClass().getName();
094: name = name.substring(name.lastIndexOf('.') + 1)
095: + "Vertex";
096: final Class clazz = Class.forName(PACKAGE_NAME + name);
097: vertex = (BaseVertex) clazz.getConstructor(
098: new Class[] { node.getClass() }).newInstance(
099: new Object[] { node });
100: } catch (final Exception e) {
101: throw new RuntimeException("problem visiting vertex "
102: + node.getClass().getName(), e);
103: }
104: this .graph.addChild(vertex);
105: this .visitedNodes.put(dotId(node), vertex);
106:
107: new Connection(this .parentVertex, vertex);
108:
109: final BaseVertex oldParentVertex = this .parentVertex;
110: this .parentVertex = vertex;
111:
112: List list = null;
113: if (node instanceof ObjectSource) {
114: list = Arrays.asList(((ObjectSource) node)
115: .getSinkPropagator().getSinks());
116: } else if (node instanceof TupleSource) {
117: list = Arrays.asList(((TupleSource) node)
118: .getSinkPropagator().getSinks());
119: }
120:
121: if (list != null) {
122: for (final java.util.Iterator it = list.iterator(); it
123: .hasNext();) {
124: final Object nextNode = it.next();
125: visitNode(nextNode);
126: }
127: }
128: this .parentVertex = oldParentVertex;
129: } else {
130: new Connection(this .parentVertex, vertex);
131: }
132: }
133:
134: /**
135: * Helper method to ensure nodes are not visited more than once.
136: */
137: private void visitNode(final Object node) {
138: Object realNode = node;
139: if (node instanceof ObjectHashMap.ObjectEntry) {
140: ObjectHashMap.ObjectEntry entry = (ObjectHashMap.ObjectEntry) node;
141: realNode = entry.getValue();
142: }
143: visit(realNode);
144: }
145:
146: /**
147: * The identity hashCode for the given object is used as its unique DOT
148: * identifier.
149: */
150: private static String dotId(final Object object) {
151: return Integer.toHexString(System.identityHashCode(object))
152: .toUpperCase();
153: }
154:
155: }
|