// The object that will store and convert the DJ // traversal object to the AspectJ aspect code. import edu.neu.ccs.demeter.dj.*; import edu.neu.ccs.demeter.aplib.EdgeI; import edu.neu.ccs.demeter.aplib.TraversalGraph; import edu.neu.ccs.demeter.aplib.TraversalCombination; import java.util.*; import java.io.*; class AspectJTraversal { // the traversal that we have translated Traversal traversal; // the name of the traversal String traversalName; // the name of the aspect String aspectName; // the buffer containing the traversal code in aspectj StringBuffer aspectjTraversalCode; // the debug mode static boolean debug=false; static boolean debug2=false; static boolean addPrintingAdvice=false; public AspectJTraversal(String tn, Traversal tg) throws edu.neu.ccs.demeter.aplib.NoSuchClassGraphNodeException{ traversal = tg; traversalName = tn; aspectjTraversalCode = traversal2AspectJ(tn, tg); aspectName = tn; makeTraversalSourceWrappers(tn, tg.getStartSet()); } public AspectJTraversal(ClassGraph cg, String tn, String st) throws edu.neu.ccs.demeter.aplib.NoSuchClassGraphNodeException{ this(tn, new Traversal(st, cg)); } private String processTraversal(ClassGraph cg, String tn, String st) throws edu.neu.ccs.demeter.aplib.NoSuchClassGraphNodeException{ return this.processTraversal(tn, new Traversal(st, cg)); } private String processTraversal(String tn, Traversal tg) throws edu.neu.ccs.demeter.aplib.NoSuchClassGraphNodeException{ traversal = tg; traversalName = tn; appendToTraversalCode(" /* strategy: " + tn + ": " + tg.getStrategy() + "\n"); appendToTraversalCode(" traversal:\n" + tg.toCompactString() + "\n */\n"); if (debug) { System.out.println("----------------------------------"); System.out.println("Processing " + tn + ":" + tg.getStrategy()); System.out.println(tg.toCompactString()); } makeTraversalSourceWrappers(tn, tg.getStartSet()); StringBuffer newCode = traversal2AspectJ(tn, tg); aspectjTraversalCode.append(newCode); aspectName = tn; return newCode.toString(); } AspectJTraversal() { traversal = null; traversalName = null; aspectjTraversalCode = new StringBuffer(); } private void makeTraversalSourceWrappers(String tname, List startSets) { for (Iterator it = startSets.iterator(); it.hasNext();) makeTraversalSourceWrapper(tname, (Traversal.NodeSet) it.next()); } private void makeTraversalSourceWrapper(String tname, Traversal.NodeSet startSet) { Object startNode = startSet.getNode(); List graphSets = getGraphSets(startSet); int n = graphSets.size(); String wrapper = " void " + startNode + "." + tname + "() {\n" + " java.util.BitSet[] tokens = { "; for (int i = 0; i < n; i++) { if (i > 0) wrapper += ", "; wrapper += "new java.util.BitSet()"; } wrapper += " };\n"; for (int i = 0; i < n; i++) { TraversalGraph.NodeSet ns = (TraversalGraph.NodeSet) graphSets.get(i); List indices = ns.getIndices(); for (Iterator it = indices.iterator(); it.hasNext();) { wrapper += " tokens[" + i + "].set(" + it.next() + ");\n"; } } wrapper += " " + tname + "(tokens);\n }\n"; appendToTraversalCode(wrapper); } private static List getGraphSets(Traversal.NodeSet s) { List l = new ArrayList(); if (s instanceof TraversalGraph.NodeSet) l.add(s); else if (s instanceof TraversalCombination.NodeSet) { TraversalCombination.NodeSet cs = (TraversalCombination.NodeSet) s; l.addAll(getGraphSets(cs.getLeftNodeSet())); l.addAll(getGraphSets(cs.getRightNodeSet())); } else throw new RuntimeException("Unknown NodeSet type: " + s); return l; } private static List getGraphSets(Traversal.EdgeSet s) { List l = new ArrayList(); if (s instanceof TraversalGraph.EdgeSet) l.add(s); else if (s instanceof TraversalCombination.EdgeSet) { TraversalCombination.EdgeSet cs = (TraversalCombination.EdgeSet) s; l.addAll(getGraphSets(cs.getLeftEdgeSet())); l.addAll(getGraphSets(cs.getRightEdgeSet())); } else throw new RuntimeException("Unknown EdgeSet type: " + s); return l; } private void appendToTraversalCode(String code) { aspectjTraversalCode.append(code); } private void setAspectName(String an) { aspectName = an ; } // get the aspect name private String getAspectName() { return aspectName; } // get the name of the traversal public String getTraversalName() { return traversalName; } // get the traversal string public String toString() { return "// This file was generated by DAJ from " + aspectName + ".trv.\n" + "\n" + "import edu.neu.ccs.demeter.*;\n" + "\n" + "public aspect " + aspectName + " {\n" + aspectjTraversalCode + "} // " + aspectName + "\n"; } // output the generated code to file public String toFile(File f) throws IOException { String outString = toString(); PrintWriter pw = new PrintWriter(new BufferedWriter(new FileWriter(f))); pw.print(outString); pw.close(); return outString; } // Convert the traversal to AspectJ code protected StringBuffer traversal2AspectJ(String tn, Traversal tg) throws edu.neu.ccs.demeter.aplib.NoSuchClassGraphNodeException{ // the string buffers StringBuffer returnBuffer = new StringBuffer(); ClassGraph cg = (ClassGraph) tg.getClassGraph(); // set up the node sets List nodeSets = tg.getNodeSets(); if (debug) System.out.println("nodesets: " + nodeSets); // loop through each node in the traversal graph for (Iterator iter = nodeSets.iterator(); iter.hasNext(); ) { Traversal.NodeSet nodeset = (Traversal.NodeSet) iter.next(); Object node = nodeset.getNode(); List graphNodeSets = getGraphSets(nodeset); if (debug) System.out.println("processing node: " + node + " nodeset=" + nodeset); // set up the buffers for the code that we'll be adding StringBuffer travBody = new StringBuffer(); String travBodyHeader = " void " + node + "." + tn + "(java.util.BitSet[] tokens) {\n"; StringBuffer travWrapperMethods = new StringBuffer(); List incomingEdgeSets = nodeset.getIncomingEdgeSets(); List outgoingEdgeSets = nodeset.getOutgoingEdgeSets(); if (debug) System.out.println(" outgoing edges:\n " + outgoingEdgeSets); if (incomingEdgeSets.isEmpty() && outgoingEdgeSets.isEmpty()) { if (debug) System.out.println(" Skipping..."); continue; } // loop through each outgoing edge and process it for (Iterator iterEdge = outgoingEdgeSets.iterator(); iterEdge.hasNext(); ) { Traversal.EdgeSet edgeset = (Traversal.EdgeSet)iterEdge.next(); edu.neu.ccs.demeter.aplib.EdgeI edge = edgeset.getEdge(); if (edge.isAlternationEdge()) continue; // FIXME: workaround for bug 29959 in ajc 1.1beta4 if (edge.isInheritanceEdge()) continue; if (debug) System.out.println(" Processing edge: " + edgeset); List graphEdgeSets = getGraphSets(edgeset); int n = graphEdgeSets.size(); travBody.append(" { " + "java.util.BitSet[] newTokens" + " = { "); for (int i = 0; i < n; i++) { if (i > 0) travBody.append(", "); travBody.append("new java.util.BitSet()"); } travBody.append(" };\n"); for (int i = 0; i < n; i++) { TraversalGraph.NodeSet ns = (TraversalGraph.NodeSet) graphNodeSets.get(i); TraversalGraph.EdgeSet es = (TraversalGraph.EdgeSet) graphEdgeSets.get(i); for (Iterator it = ns.getIndices().iterator(); it.hasNext();) { Integer s = (Integer) it.next(); List tl = es.getTargetIndices(s.intValue()); if (!tl.isEmpty()) { travBody.append(" if (tokens[" + i + "]." + "get(" + s + ")) {\n"); for (Iterator it2 = tl.iterator(); it2.hasNext();) travBody.append(" newTokens[" + i + "]." + "set(" + it2.next() + ");\n"); travBody.append(" }\n"); } } } travBody.append(" if ("); boolean first = true; for (int i = 0; i < n; i++) { if (first) first = false; else travBody.append(" && "); travBody.append("!newTokens[" + i + "].isEmpty()"); } travBody.append(")\n"); if (cg.isRepetitionEdge(edge)) { String label = edge.getLabel(); Object target = edge.getTarget(); travBody.append(" " + "for (java.util.Iterator it = iterator();" + " it.hasNext();)\n" + " " + " " + tn + "_crossing_" + label + "((" + target + ") it.next()," + " newTokens);\n"); travWrapperMethods.append(" void " + node + "." + tn + "_crossing_" + label + "(" + target + " it," + " java.util.BitSet[] tokens) {\n" + " it." + tn + "(tokens);\n }\n"); } else if (edge.isConstructionEdge()) { String label = edge.getLabel(); travBody.append(" if (" + label + " != null)\n" + " " + tn + "_crossing_" + label + "(newTokens);\n"); travWrapperMethods.append(" void " + node + "." + tn + "_crossing_" + label + "(java.util.BitSet[] tokens) {\n" + " this." + label + "." + tn + "(tokens);\n }\n"); } else if (edge.isInheritanceEdge()) { travBody.append(" super." + tn + "(tokens);\n"); } travBody.append(" }\n"); } // now add all the traversal code into the string buffer // that we're going to return travBody.append(" }\n"); if (debug) { System.out.println(" Adding generated code...."); System.out.println(travBodyHeader + travBody + travWrapperMethods); } returnBuffer.append(travBodyHeader); returnBuffer.append(travBody); returnBuffer.append(travWrapperMethods); } // add code for the point cut and advice that will print out // the traversal as it goes along if (addPrintingAdvice) { returnBuffer.append(" before(java.util.BitSet[] tokens):" + " call(void " + tn + "*(..))" + " && args(.., tokens) {\n"); returnBuffer.append(" System.out.println(thisJoinPoint + \" \"" + " + java.util.Arrays.asList(tokens));\n"); returnBuffer.append(" }\n"); } if (debug) { System.out.println("+++++++++Generated Code+++++++++++++++++"); System.out.println(returnBuffer); System.out.println("+++++++++Generated Code End+++++++++++++"); } return returnBuffer; } }