001 package edu.rice.cs.cunit; 002 003 import edu.rice.cs.cunit.instrumentors.IInstrumentationStrategy; 004 import edu.rice.cs.cunit.util.Debug; 005 006 import java.io.FileNotFoundException; 007 import java.io.FileOutputStream; 008 import java.io.PrintStream; 009 import java.lang.reflect.Method; 010 import java.util.ArrayList; 011 import java.util.List; 012 013 /** 014 * @author Mathias Ricken 015 */ 016 public abstract class ACUnitRun { 017 /** 018 * Class to load and execute. 019 */ 020 protected String _className; 021 022 /** 023 * Arguments to pass to the class main method. 024 */ 025 protected String[] _progArgs; 026 027 /** 028 * String with syntax description 029 */ 030 protected static final String OPTIONS_FORMAT = "[-h] [-d] [-output <txt>] [-ns] [-backup] [-i <iclass>] [-X <s>] <class> [args...]"; 031 032 /** 033 * Do not save instrumented class files? 034 */ 035 protected boolean _noSaveInstrumented = false; 036 037 /** 038 * Make backups of original files? 039 */ 040 protected boolean _makeBackups = false; 041 042 /** 043 * Instrumentor class name. 044 */ 045 protected String _instrumentorClassName = getDefaultInstrumentorName(); 046 047 /** 048 * List of parameters to the instrumentors. 049 */ 050 protected List<String> _parameters = new ArrayList<String>(); 051 052 /** 053 * Print a help message to the specified stream. 054 * @param out output stream 055 */ 056 protected static void help(PrintStream out) { 057 // ---------1---------2---------3---------4---------5---------6---------7---------8 058 out.println("Flags : "+ OPTIONS_FORMAT); 059 out.println("-h Show this help"); 060 out.println("-d Debug output"); 061 out.println("-output <txt> Debug output to file <txt>"); 062 out.println("-ns Do not save instrumented class files"); 063 out.println("-backup Make backups of original class files (only if no -nw)"); 064 out.println("-i <iclass> Specify <iclass> as instrumentor class name"); 065 out.println("-X <s> Pass <s> as parameter to instrumentors; may be repeated"); 066 out.println("<class> [args...] Class file whose main method to execute, and arguments."); 067 } 068 069 /** 070 * Read the command line arguments or ask for them in a dialog. 071 * 072 * @param args command line arguments 073 */ 074 protected void readArgs(String[] args) { 075 if (args.length == 0) { 076 help(System.err); 077 System.exit(1); 078 } 079 080 int argIndex = 0; 081 while((argIndex<args.length) && (args[argIndex].startsWith("-"))) { 082 final String a = args[argIndex]; 083 if (a.equalsIgnoreCase("-?") || a.equalsIgnoreCase("-h")) { 084 help(System.out); 085 System.exit(1); 086 } 087 else if (a.equals("-nw")) { 088 _noSaveInstrumented = true; 089 } 090 else if (a.equals("-backup")) { 091 _makeBackups = true; 092 } 093 else if (a.equals("-d")) { 094 Debug.out.setDebug(true); 095 } 096 else if (a.equals("-output")) { 097 if (argIndex + 1 > args.length) { 098 System.err.println("Error: <txt> file parameter missing."); 099 help(System.err); 100 System.exit(1); 101 } 102 String name = args[++argIndex]; 103 try { 104 FileOutputStream debugOut = new FileOutputStream(name); 105 Debug.out.setOutput(new PrintStream(debugOut, true)); 106 Debug.out.setDebug(true); 107 } 108 catch(FileNotFoundException e) { 109 System.err.println("Error: Could not open <txt> file " + name + " for output."); 110 System.exit(1); 111 } 112 } 113 else if (a.equals("-i")) { 114 if (argIndex + 1 > args.length) { 115 System.err.println("Error: <iclass> file parameter missing."); 116 help(System.err); 117 System.exit(1); 118 } 119 _instrumentorClassName = args[++argIndex]; 120 if (_instrumentorClassName.indexOf('.') < 0) { 121 _instrumentorClassName = FileInstrumentor.INSTRUMENTOR_PACKAGE_PREFIX + _instrumentorClassName; 122 } 123 } 124 else if (a.equals("-X")) { 125 if (argIndex + 1 > args.length) { 126 System.err.println("Error: <s> parameter missing."); 127 help(System.err); 128 System.exit(1); 129 } 130 _parameters.add(args[++argIndex]); 131 } 132 ++argIndex; 133 } 134 135 if (_noSaveInstrumented && _makeBackups) { 136 System.err.println("Error: -backup may only be specified without -ns."); 137 System.exit(1); 138 } 139 140 if (argIndex>=args.length) { 141 System.err.println("Error: <class> missing"); 142 System.exit(1); 143 } 144 145 _className = args[argIndex]; 146 147 _progArgs = new String[args.length - 1 - argIndex]; 148 System.arraycopy(args, 1, _progArgs, 0, _progArgs.length); 149 } 150 151 /** 152 * Main method. 153 * 154 * @param args command line arguments 155 */ 156 protected void run(String[] args) { 157 try { 158 readArgs(args); 159 160 IInstrumentationStrategy itor = null; 161 try { 162 @SuppressWarnings("unchecked") Class<IInstrumentationStrategy> c = (Class<IInstrumentationStrategy>)Class 163 .forName(_instrumentorClassName); 164 itor = c.getConstructor(List.class).newInstance(_parameters); 165 } 166 catch(NoSuchMethodException e) { 167 try { 168 @SuppressWarnings("unchecked") Class<IInstrumentationStrategy> c 169 = (Class<IInstrumentationStrategy>)Class.forName(_instrumentorClassName); 170 itor = c.getConstructor().newInstance(); 171 } 172 catch(Throwable e2) { 173 e2.printStackTrace(Debug.out); 174 System.exit(1); 175 } 176 } 177 catch(Throwable e2) { 178 e2.printStackTrace(Debug.out); 179 System.exit(1); 180 } 181 182 InstrumentingClassLoader classLoader = new InstrumentingClassLoader(new IInstrumentationStrategy[]{itor}); 183 classLoader.setSaveInstrumented(!_noSaveInstrumented); 184 classLoader.setMakeBackups(_makeBackups); 185 186 Class<?> cls = classLoader.loadClass(_className, true); 187 188 Debug.out.println(System.getProperty("line.separator") + System.getProperty("line.separator") + 189 System.getProperty("line.separator") + 190 "---------------------------------------------------------------------"); 191 192 cls.newInstance(); 193 194 Class mainArgType[] = {(new String[0]).getClass()}; 195 Method main = cls.getMethod("main", mainArgType); 196 197 Object argsArray[] = {_progArgs}; 198 199 main.invoke(null, argsArray); 200 } 201 catch(Exception e) { 202 e.printStackTrace(); 203 if (null!=e.getCause()) { 204 System.err.println("Cause:"); 205 e.getCause().printStackTrace(); 206 } 207 } 208 } 209 210 /** 211 * Abstract method deciding what instrumentor to run by default. 212 * @return the default name of the instrumentor. 213 */ 214 public abstract String getDefaultInstrumentorName(); 215 }