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 }