1
2
3 package org.virtualmock.taskdef;
4
5 import java.io.File;
6 import java.util.StringTokenizer;
7 import org.apache.tools.ant.BuildException;
8 import org.apache.tools.ant.Task;
9 import org.apache.tools.ant.taskdefs.Delete;
10 import org.apache.tools.ant.taskdefs.Java;
11 import org.apache.tools.ant.taskdefs.Zip;
12 import org.apache.tools.ant.types.Commandline.Argument;
13 import org.apache.tools.ant.types.CommandlineJava;
14 import org.apache.tools.ant.types.FileSet;
15 import org.apache.tools.ant.types.Path;
16
17
18 /***
19 * Task to perform transformation of class or jar files to be executed with
20 * VirtualMock.
21 *
22 * @author Chad Woolley
23 * @version $Revision: 1.18 $
24 */
25 public class VMTransformTask extends Task {
26 private CommandlineJava commandline = null;
27 private Path classpath = null;
28 private String aspectWerkzClassname =
29 "org.codehaus.aspectwerkz.compiler.AspectWerkzC";
30 private String aspectjClassname = "org.aspectj.tools.ajc.Main";
31 private String aspectpath = null;
32 private String aspectpathJarPrefix = "virtualmock-aspect-";
33 private String injars = null;
34 private String outjar = null;
35 private boolean useAspectJ = true;
36 private boolean useAspectWerkz = false;
37
38 /***
39 * Creates a new VMTransformTask object.
40 */
41 public VMTransformTask() {
42 super();
43 this.setTaskName("vmtransform");
44 commandline = new CommandlineJava();
45 }
46
47 /***
48 * Sets the classname for the AspectWerkz compiler.
49 *
50 * @param aspectWerkzClassname The aspectWerkzClassname to set.
51 */
52 public void setAspectWerkzClassname(String aspectWerkzClassname) {
53 this.aspectWerkzClassname = aspectWerkzClassname;
54 }
55
56 /***
57 * Gets the classname for the AspectWerkz compiler.
58 *
59 * @return Returns the aspectWerkzClassname.
60 */
61 public String getAspectWerkzClassname() {
62 return aspectWerkzClassname;
63 }
64
65 /***
66 * Sets the classname for the AspectJ compiler.
67 *
68 * @param aspectjClassname The aspectjClassname to set.
69 */
70 public void setAspectjClassname(String aspectjClassname) {
71 this.aspectjClassname = aspectjClassname;
72 }
73
74 /***
75 * Gets the classname for the AspectJ compiler.
76 *
77 * @return Returns the aspectjClassname.
78 */
79 public String getAspectjClassname() {
80 return aspectjClassname;
81 }
82
83 /***
84 * Sets jar containing VirtualMock aspect classes to weave. If this is not
85 * specified, then the aspectpathJarPrefix will be used to search for the
86 * aspectjar on the classpath.
87 *
88 * @param aspectpath the aspectpath to set
89 */
90 public void setAspectpath(String aspectpath) {
91 this.aspectpath = aspectpath;
92 }
93
94 /***
95 * Gets jar containing VirtualMock aspect classes to weave. If this is not
96 * specified, then the aspectpathJarPrefix will be used to search for the
97 * aspectjar on the classpath.
98 *
99 * @return Returns the aspectpath.
100 */
101 public String getAspectpath() {
102 return aspectpath;
103 }
104
105 /***
106 * Sets string which will be used to search the classpath for the
107 * aspectpath jar (using String.indexOf(String)). If this is not
108 * specified, it will default to "virtualmock-aspect-".
109 *
110 * @param aspectpathJarPrefix the aspectpathJarPrefix to set
111 */
112 public void setAspectpathJarPrefix(String aspectpathJarPrefix) {
113 this.aspectpathJarPrefix = aspectpathJarPrefix;
114 }
115
116 /***
117 * Gets string which will be used to search the classpath for the
118 * aspectpath jar (using String.indexOf(String)). If this is not
119 * specified, it will default to "virtualmock-aspect-".
120 *
121 * @return Returns the aspectpathJarPrefix.
122 */
123 public String getAspectpathJarPrefix() {
124 return aspectpathJarPrefix;
125 }
126
127 /***
128 * Sets the classpath to use.
129 *
130 * @param classpath The classpath to set.
131 */
132 public void setClasspath(Path classpath) {
133 this.classpath = classpath;
134 }
135
136 /***
137 * Gets the currently set classpath.
138 *
139 * @return Returns the classpath.
140 */
141 public Path getClasspath() {
142 return classpath;
143 }
144
145 /***
146 * Sets the command line.
147 *
148 * @param commandline The commandline to set.
149 */
150 public void setCommandline(CommandlineJava commandline) {
151 this.commandline = commandline;
152 }
153
154 /***
155 * Gets the command line.
156 *
157 * @return Returns the commandline.
158 */
159 public CommandlineJava getCommandline() {
160 return commandline;
161 }
162
163 /***
164 * Setter for the input jars. Accept as source bytecode any .class files
165 * inside the specified .jar files. The output will include these classes,
166 * possibly as woven with any applicable aspects. Like classpath, this is
167 * a single argument containing a list of paths to jar files, delimited by
168 * the platform- specific classpath delimiter.
169 *
170 * @param injars the injars to set
171 */
172 public void setInjars(String injars) {
173 this.injars = injars;
174 }
175
176 /***
177 * The input jars which will be woven.
178 *
179 * @return Returns the injars.
180 */
181 public String getInjars() {
182 return injars;
183 }
184
185 /***
186 * Sets the output jar. This is the transformed jar which will be created
187 * by this task.
188 *
189 * @param outjar the outjar to set
190 */
191 public void setOutjar(String outjar) {
192 this.outjar = outjar;
193 }
194
195 /***
196 * Gets the output jar. This is the transformed jar which will be created
197 * by this task.
198 *
199 * @return Returns the outjar.
200 */
201 public String getOutjar() {
202 return outjar;
203 }
204
205 /***
206 * Indicates whether AspectJ should be used as the Aspect-Oriented
207 * Programming (AOP) framework.
208 *
209 * @param useAspectJ flag indicating whether AspectJ should be used.
210 */
211 public void setUseAspectJ(boolean useAspectJ) {
212 this.useAspectJ = useAspectJ;
213 useAspectWerkz = !useAspectJ;
214 }
215
216 /***
217 * Returns flag which indicates whether AspectJ should be used to weave.
218 *
219 * @return Returns the flag which indicates whether AspectJ should be used
220 * to weave.
221 */
222 public boolean isUseAspectJ() {
223 return useAspectJ;
224 }
225
226 /***
227 * Sets the flag which indicates whether AspectWerkz should be used to
228 * weave.
229 *
230 * @param useAspectWerkz flag indicating whether AspectWerkz should be used
231 * to weave.
232 */
233 public void setUseAspectWerkz(boolean useAspectWerkz) {
234 this.useAspectWerkz = useAspectWerkz;
235 useAspectJ = !useAspectWerkz;
236 }
237
238 /***
239 * Returns the flag which indicates whether AspectWerkz should be used to
240 * weave.
241 *
242 * @return Returns the flag indicating whether AspectWerkz should be used
243 * to weave.
244 */
245 public boolean isUseAspectWerkz() {
246 return useAspectWerkz;
247 }
248
249 /***
250 * Overridden method to handle classpath. It will take the classpath that
251 * is currently specified, and append all elements required to support
252 * the VirtualMock environment.
253 *
254 * @return the modified classpath
255 *
256 * @todo Do we need to add anything to the classpath? If so, what?
257 * @todo What about forked mode?
258 */
259 public Path createClasspath() {
260
261 classpath = commandline.createClasspath(getProject()).createPath();
262
263 return classpath;
264 }
265
266 /***
267 * Perform execution of the task, first performing necessary setup to run
268 * VirtualMock unit tests.
269 *
270 * @throws BuildException DOCUMENT ME! (Constructor Exception)
271 */
272 public void execute() throws BuildException {
273 File outjarFile = new File(outjar);
274
275 deleteOutjarFile(outjarFile);
276
277 String className = null;
278 String args = null;
279
280 if (useAspectJ) {
281
282 className = aspectjClassname;
283
284 performAspectjPreProcessing();
285
286
287 args =
288 "-outjar " + outjar + " -injars " + injars + " -aspectpath "
289 + aspectpath;
290 }
291
292 if (useAspectWerkz) {
293
294 className = aspectWerkzClassname;
295
296
297 args = "-haltOnError " + outjar;
298
299 performAspectwerkzPreProcessing(outjarFile);
300 }
301
302
303 Java java = new Java();
304
305
306 java.setFork(false);
307
308
309 java.setClassname(className);
310
311
312 java.setFailonerror(true);
313
314 Argument arg = java.createArg();
315 arg.setLine(args);
316
317 java.setClasspath(classpath);
318
319
320 int returnCode = -1;
321
322 java.setProject(project);
323
324 java.setFork(true);
325 returnCode = java.executeJava();
326
327 if (returnCode != 0) {
328 throw new BuildException(
329 "VirtualMock transformation failed, return code = "
330 + returnCode + ". Command executed was '" + className
331 + "' with arguments '" + args + "'");
332 }
333 }
334
335 /***
336 * If aspectpath was not set by user, search the classpath for the jar
337 * containing the virtualmock aspects and set it in the aspectpath
338 * variable.
339 */
340 protected void setDefaultAspectPath() {
341 String[] classpathElements = classpath.list();
342
343 for (int i = 0; i < classpathElements.length; i++) {
344 if (classpathElements[i].indexOf(aspectpathJarPrefix) != -1) {
345 aspectpath = classpathElements[i];
346 }
347 }
348 }
349
350 /***
351 * Delete the output jar, if it exists.
352 *
353 * @param outjarFile the File object representing the outjar
354 */
355 protected void deleteOutjarFile(File outjarFile) {
356
357 Delete delete = new Delete();
358 delete.setProject(project);
359
360 delete.setFile(outjarFile);
361 delete.setFailOnError(false);
362 delete.execute();
363 }
364
365 /***
366 * Performs preprocessing that is specific to AspectJ.
367 */
368 protected void performAspectjPreProcessing() {
369
370 if (aspectpath == null) {
371 setDefaultAspectPath();
372 }
373 }
374
375 /***
376 * Performs preprocessing that is specific to AspectWerkz.
377 *
378 * @param outjarFile the File object represented by outjar
379 */
380 protected void performAspectwerkzPreProcessing(File outjarFile) {
381
382
383 Zip zip = new Zip();
384 zip.setProject(project);
385 zip.setDestFile(outjarFile);
386
387
388 StringTokenizer stringTokenizer =
389 new StringTokenizer(injars, File.pathSeparator);
390
391 while (stringTokenizer.hasMoreTokens()) {
392
393
394 String injarFileStringFull = stringTokenizer.nextToken();
395 File injarFile = new File(injarFileStringFull);
396 String parentDir = injarFile.getParent();
397 File parentDirFile = new File(parentDir);
398 String injarFileString =
399 injarFileStringFull.substring(parentDir.length() + 1);
400
401 FileSet fileSet = new FileSet();
402 fileSet.setIncludes(injarFileString);
403 fileSet.setDir(parentDirFile);
404 zip.addZipGroupFileset(fileSet);
405 }
406
407
408 Zip.Duplicate duplicate = new Zip.Duplicate();
409 duplicate.setValue("preserve");
410 zip.setDuplicate(duplicate);
411
412
413 zip.execute();
414 }
415 }