package edu.neu.ccs.demeter.tools.daj; import edu.neu.ccs.demeter.dj.*; import java.io.*; import java.util.*; /** The main DAJ functionality. */ public class DAJ { // There's no need to instantiate this class. DAJ() { } /** Compile a DAJ project, then exit the VM. @param args command line arguments */ public static void main(String args[]) { if (args.length == 0) { CommandLine.printUsage(); System.exit(-1); } System.exit(compile(args)); } /** Compile a DAJ project. @param args command line arguments @return the exit code */ public static int compile(String args[]) { // parse the command line so that we can process this compilation CommandLine cmdLine; try { cmdLine = new CommandLine(args); } catch (CommandLineException e) { System.out.println("Error: " + e.getMessage()); return -1; } return compile(cmdLine); } static int compile(CommandLine cmdLine) { // generate some stubs for traversal generation compilation if (!generateStubs(cmdLine)) return -1; if (cmdLine.isTraversalGenerationOption()) return 0; // run the ajc compiler to compile the code // to generate the traversals if (!compileStubs(cmdLine)) return -1; if (cmdLine.isTraversalGenerationCompilationOption()) return 0; // run traversalj to generate the traversal files if (!generateTraversals(cmdLine)) return -1; if (cmdLine.isTraversalCompilationOption()) return 0; // compile the generated traversal code with original if (!compileTraversals(cmdLine)) return -1; return 0; } static boolean generateStubs(CommandLine cmdLine) { return generateStubs(cmdLine.getTraversalFiles(), cmdLine.getTraversalDestinationOption()); } /** Generate a stub aspect file to the current directory for each traversal file. @param traversalFiles a list of .trv files @return false if there are any errors */ public static boolean generateStubs(List traversalFiles) { return generateStubs(traversalFiles, null); } /** Generate a stub aspect file for each traversal file. @param traversalFiles a list of .trv files @param destinationDirectory the output directory for the stubs @return false if there are any errors */ public static boolean generateStubs(List traversalFiles, File destinationDirectory) { boolean returnVal = true; System.out.println("\n%I - Generating Stubs"); for (Iterator it = traversalFiles.iterator(); it.hasNext();) { File f = (File) it.next(); try { Reader in = new BufferedReader(new FileReader(f)); TraversalAspectList tal = TraversalAspectList.parse(in); returnVal = tal.generateStubs(destinationDirectory, getRootName(f)) && returnVal; } catch (Exception e) { System.out.println(e); returnVal = false; } } return returnVal; } static boolean compileStubs(CommandLine cmdLine) { return compileStubs(cmdLine.getAJC(), cmdLine.getTraversalFiles(), cmdLine.getTraversalDestinationOption(), cmdLine.getJavaFiles(), cmdLine.getAJCOptions(), cmdLine.getTempFileDirOption()); } /** Compile the generated stub aspects along with the source aspects. @param ajc the aspect compiler executable, or null to invoke ajc on the class path @param traversalFiles a list of .trv files @param stubsDirectory the directory the stubs were generated into @param aspectFiles a list of aspect source files @param AJCOptions a list of options for the aspect compiler @param destinationDirectory the output directory for the class files */ public static boolean compileStubs(String ajc, List traversalFiles, File stubsDirectory, List aspectFiles, List AJCOptions, File destinationDirectory) { List args = new ArrayList(); if (destinationDirectory != null) { args.add("-d"); args.add(destinationDirectory); } if (AJCOptions != null) args.addAll(AJCOptions); if (aspectFiles != null) args.addAll(aspectFiles); args.addAll(getGeneratedFiles(traversalFiles, stubsDirectory)); System.out.println("\n%I - traversal generation compilation\n" + (ajc == null ? "ajc" : ajc) + " " + toStringWithSpaces(args)); return compileAspects(ajc, args); } static boolean generateTraversals(CommandLine cmdLine) { return generateTraversals(cmdLine.getTraversalFiles(), cmdLine.getTempFileDirOption(), cmdLine.getGeneratePrintingAdviceOption(), cmdLine.getGenerationClassPathOption(), cmdLine.getTraversalDestinationOption()); } /** Generate a traversal aspect file for each traversal file. @param traversalFiles a list of .trv files @param stubClassesDirectory the directory the stubs were compiled into @param generatePrintingAdvice should printing advice be generated? @param classPath the class path to be used for invoking DJ @param destinationDirectory the output directory for the traversal aspects */ public static boolean generateTraversals(List traversalFiles, File stubClassesDirectory, boolean generatePrintingAdvice, String classPath, File destinationDirectory) { if (stubClassesDirectory != null) { if (classPath == null) classPath = System.getProperty("java.class.path"); classPath = stubClassesDirectory + File.pathSeparator + classPath; } List args = new ArrayList(); if (generatePrintingAdvice) args.add("-gpa"); if (destinationDirectory != null) { args.add("-d"); args.add(destinationDirectory); } args.addAll(traversalFiles); // return generateTraversals(classPath, args); return generateTraversalsExec(classPath, args); } // This doesn't work, because the current ClassLoader ignores the new // class path. static boolean generateTraversals(String classPath, List args) { System.out.println("\n%I - traversal generation"); if (classPath != null) { System.out.println("CLASSPATH = " + classPath); System.setProperty("java.class.path", classPath); } System.out.println("CreateClassGraph " + toStringWithSpaces(args)); CreateClassGraph.main(toStringArray(args)); return true; } static boolean generateTraversalsExec(String classPath, List args) { List cmd = new ArrayList(); cmd.add("java"); if (classPath != null) { cmd.add("-cp"); cmd.add(classPath); } cmd.add("edu.neu.ccs.demeter.tools.daj.CreateClassGraph"); cmd.addAll(args); System.out.println("\n%I - traversal generation\n" + toStringWithSpaces(cmd)); return executeCommand(cmd); } static boolean compileTraversals(CommandLine cmdLine) { return compileTraversals(cmdLine.getAJC(), cmdLine.getTraversalFiles(), cmdLine.getTraversalDestinationOption(), cmdLine.getJavaFiles(), cmdLine.getAJCOptions(), cmdLine.getTempFileDirOption()); } /** Compile the generated traversal aspects along with the source aspects. @param ajc the aspect compiler executable, or null to invoke ajc on the class path @param traversalFiles a list of .trv files @param traversalsDirectory the directory the traversal aspects were generated into @param aspectFiles a list of aspect source files @param AJCOptions a list of options for the aspect compiler @param destinationDirectory the output directory for the class files */ public static boolean compileTraversals(String ajc, List traversalFiles, File traversalsDirectory, List aspectFiles, List AJCOptions, File destinationDirectory) { List args = new ArrayList(); if (destinationDirectory != null) { args.add("-d"); args.add(destinationDirectory); } if (AJCOptions != null) args.addAll(AJCOptions); if (aspectFiles != null) args.addAll(aspectFiles); args.addAll(getGeneratedFiles(traversalFiles, traversalsDirectory)); System.out.println("\n%I - traversal compilation\n" + (ajc == null ? "ajc" : ajc) + " " + toStringWithSpaces(args)); return compileAspects(ajc, args); } /** Compile a list of aspects. @param ajc the aspect compiler executable, or null to invoke ajc on the class path @param argList the command line arguments to the aspect compiler @return false if there are any errors */ public static boolean compileAspects(String ajc, List argList) { if (ajc == null) { String args[] = toStringArray(argList); return (new org.aspectj.tools.ajc.Main().compile(args) == 0); } List cmd = new ArrayList(); cmd.add(ajc); cmd.addAll(argList); return executeCommand(cmd); } static boolean executeCommand(List cmdList) { return executeCommand(toStringArray(cmdList)); } static boolean executeCommand(String cmd[]) { Process cmdProc = null; try { cmdProc = Runtime.getRuntime().exec(cmd); InputStream err = cmdProc.getErrorStream(); //forwardOutputStream(System.out, err); InputStream in = cmdProc.getInputStream(); //forwardOutputStream(System.out, in); StreamFunnel sf = new StreamFunnel(err, in, System.out); sf.run(); cmdProc.waitFor(); // System.out.println("exit value = " + cmdProc.exitValue()); if (cmdProc.exitValue() != 0) { System.out.println("Error executing command: " + toStringWithSpaces(cmd)); } cmdProc.destroy(); } catch (IllegalThreadStateException e) { e.printStackTrace(System.out); cmdProc.destroy(); return false; } catch (java.io.IOException e) { System.out.print("%ERROR : "); System.out.println(e); System.out.println("\n%Information : \n " + "You might need to specify -ajc ajc.bat or some other\n" + "string as the command to execute the AspectJ Compiler.\n" + "DAJ is not smart enough to know that you're using windows\n" + "and need to have ajc.bat instead of ajc."); return false; } catch (Exception e) { System.out.println(e); e.printStackTrace(System.out); return false; } return true; } static void forwardOutputStream(OutputStream out, InputStream in) throws IOException{ int read = in.read(); while (read > 0) { out.write((byte) read); read = in.read(); } } /** A list of generated aspect files. @param traversalFiles a list of .trv files @param destinationDirectory the directory the aspects are generated into */ public static List getGeneratedFiles(List traversalFiles, File destinationDirectory) { List files = new ArrayList(); Iterator it = traversalFiles.iterator(); while (it.hasNext()) { File f = (File) it.next(); files.add(new File(destinationDirectory, getRootName(f) + ".java")); } return files; } /** The file name without its final ".xxx" extension. */ static String getRootName(File f) { return getRootName(f.getName()); } /** The file name without its final ".xxx" extension. */ static String getRootName(String fname) { return fname.substring(0, fname.lastIndexOf(".")); } static String[] toStringArray(List list) { String array[] = new String[list.size()]; int i = 0; for (Iterator it = list.iterator(); it.hasNext(); i++) array[i] = it.next().toString(); return array; } static String toStringWithSpaces(Object x[]) { return toStringWithSpaces(Arrays.asList(x)); } static String toStringWithSpaces(List x) { String s = ""; Iterator it = x.iterator(); while (it.hasNext()) { s += it.next(); if (it.hasNext()) s += " "; } return s; } }