KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > jdiff > JDiffAntTask


1 package jdiff;
2
3 import java.io.File JavaDoc;
4 import java.io.InputStream JavaDoc;
5 import java.io.OutputStream JavaDoc;
6 import java.io.FileInputStream JavaDoc;
7 import java.io.FileOutputStream JavaDoc;
8 import java.util.Vector JavaDoc;
9
10 import org.apache.tools.ant.BuildException;
11 import org.apache.tools.ant.DirectoryScanner;
12 import org.apache.tools.ant.Project;
13 import org.apache.tools.ant.taskdefs.Javadoc;
14 import org.apache.tools.ant.taskdefs.Javadoc.DocletInfo;
15 import org.apache.tools.ant.taskdefs.Javadoc.DocletParam;
16 import org.apache.tools.ant.types.FileSet;
17 import org.apache.tools.ant.types.DirSet;
18 import org.apache.tools.ant.types.Path;
19
20 /**
21  * An Ant task to produce a simple JDiff report. More complex reports still
22  * need parameters that are controlled by the Ant Javadoc task.
23  */

24 public class JDiffAntTask {
25
26     public void execute() throws BuildException {
27     jdiffHome = project.getProperty("JDIFF_HOME");
28     if (jdiffHome == null || jdiffHome.compareTo("") == 0 |
29         jdiffHome.compareTo("(not set)") == 0) {
30         throw new BuildException("Error: invalid JDIFF_HOME property. Set it in the build file to the directory where jdiff is installed");
31     }
32
33     jdiffClassPath = jdiffHome + DIR_SEP + "lib" + DIR_SEP + "jdiff.jar" +
34         System.getProperty("path.separator") +
35         jdiffHome + DIR_SEP + "lib" + DIR_SEP + "xerces.jar";
36
37     // TODO detect and set verboseAnt
38

39     // Create, if necessary, the directory for the JDiff HTML report
40
if (!destdir.mkdir() && !destdir.exists()) {
41         throw new BuildException(getDestdir() + " is not a valid directory");
42     } else {
43         project.log(" Report location: " + getDestdir() + DIR_SEP
44             + "changes.html", Project.MSG_INFO);
45     }
46     // Could also output the other parameters used for JDiff here
47

48     // Check that there are indeed two projects to compare. If there
49
// are no directories in the project, let Javadoc do the complaining
50
if (oldProject == null || newProject == null) {
51         throw new BuildException("Error: two projects are needed, one <old> and one <new>");
52     }
53
54     /*
55     // Display the directories being compared, and some name information
56     if (getVerbose()) {
57         project.log("Older version: " + oldProject.getName(),
58             Project.MSG_INFO);
59         project.log("Included directories for older version:",
60             Project.MSG_INFO);
61         DirectoryScanner ds =
62         oldProject.getDirset().getDirectoryScanner(project);
63         String[] files = ds.getIncludedDirectories();
64         for (int i = 0; i < files.length; i++) {
65         project.log(" " + files[i], Project.MSG_INFO);
66         }
67         ds = null;
68         
69         project.log("Newer version: " + newProject.getName(),
70             Project.MSG_INFO);
71         project.log("Included directories for newer version:",
72             Project.MSG_INFO);
73         ds = newProject.getDirset().getDirectoryScanner(project);
74         files = ds.getIncludedDirectories();
75         for (int i = 0; i < files.length; i++) {
76         project.log(" " + files[i], Project.MSG_INFO);
77         }
78     }
79     */

80
81     // Call Javadoc twice to generate Javadoc for each project
82
generateJavadoc(oldProject);
83     generateJavadoc(newProject);
84
85     // Call Javadoc three times for JDiff.
86
generateXML(oldProject);
87     generateXML(newProject);
88     compareXML(oldProject.getName(), newProject.getName());
89
90     // Repeat some useful information
91
project.log(" Report location: " + getDestdir() + DIR_SEP
92             + "changes.html", Project.MSG_INFO);
93     }
94
95     /**
96      * Convenient method to create a Javadoc task, configure it and run it
97      * to generate the XML representation of a project's source files.
98      *
99      * @param proj The current Project
100      */

101     protected void generateXML(ProjectInfo proj) {
102     String JavaDoc apiname = proj.getName();
103     Javadoc jd = initJavadoc("Analyzing " + apiname);
104     jd.setDestdir(getDestdir());
105     addSourcePaths(jd, proj);
106
107     // Tell Javadoc which packages we want to scan.
108
// JDiff works with packagenames, not sourcefiles.
109
jd.setPackagenames(getPackageList(proj));
110     
111     // Create the DocletInfo first so we have a way to use it to add params
112
DocletInfo dInfo = jd.createDoclet();
113     jd.setDoclet("jdiff.JDiff");
114     jd.setDocletPath(new Path(project, jdiffClassPath));
115     
116     // Now set up some parameters for the JDiff doclet.
117
DocletParam dp1 = dInfo.createParam();
118     dp1.setName("-apiname");
119     dp1.setValue(apiname);
120     DocletParam dp2 = dInfo.createParam();
121     dp2.setName("-baseURI");
122     dp2.setValue("http://www.w3.org");
123     // Put the generated file in the same directory as the report
124
DocletParam dp3 = dInfo.createParam();
125     dp3.setName("-apidir");
126     dp3.setValue(getDestdir().toString());
127     
128     // Execute the Javadoc command to generate the XML file.
129
jd.perform();
130     }
131
132     /**
133      * Convenient method to create a Javadoc task, configure it and run it
134      * to compare the XML representations of two instances of a project's
135      * source files, and generate an HTML report summarizing the differences.
136      *
137      * @param oldapiname The name of the older version of the project
138      * @param newapiname The name of the newer version of the project
139      */

140     protected void compareXML(String JavaDoc oldapiname, String JavaDoc newapiname) {
141     Javadoc jd = initJavadoc("Comparing versions");
142     jd.setDestdir(getDestdir());
143     jd.setPrivate(true);
144
145     // Tell Javadoc which files we want to scan - a dummy file in this case
146
jd.setSourcefiles(jdiffHome + DIR_SEP + "lib" + DIR_SEP + "Null.java");
147     
148     // Create the DocletInfo first so we have a way to use it to add params
149
DocletInfo dInfo = jd.createDoclet();
150     jd.setDoclet("jdiff.JDiff");
151     jd.setDocletPath(new Path(project, jdiffClassPath));
152     
153     // Now set up some parameters for the JDiff doclet.
154
DocletParam dp1 = dInfo.createParam();
155     dp1.setName("-oldapi");
156     dp1.setValue(oldapiname);
157     DocletParam dp2 = dInfo.createParam();
158     dp2.setName("-newapi");
159     dp2.setValue(newapiname);
160     // Get the generated XML files from the same directory as the report
161
DocletParam dp3 = dInfo.createParam();
162     dp3.setName("-oldapidir");
163     dp3.setValue(getDestdir().toString());
164     DocletParam dp4 = dInfo.createParam();
165     dp4.setName("-newapidir");
166     dp4.setValue(getDestdir().toString());
167
168     // Assume that Javadoc reports already exist in ../"apiname"
169
DocletParam dp5 = dInfo.createParam();
170     dp5.setName("-javadocold");
171     dp5.setValue(".." + DIR_SEP + oldapiname + DIR_SEP);
172     DocletParam dp6 = dInfo.createParam();
173     dp6.setName("-javadocnew");
174     dp6.setValue(".." + DIR_SEP + newapiname + DIR_SEP);
175     
176     if (getStats()) {
177         // There are no arguments to this argument
178
dInfo.createParam().setName("-stats");
179         // We also have to copy two image files for the stats pages
180
copyFile(jdiffHome + DIR_SEP + "lib" + DIR_SEP + "black.gif",
181              getDestdir().toString() + DIR_SEP + "black.gif");
182         copyFile(jdiffHome + DIR_SEP + "lib" + DIR_SEP + "background.gif",
183              getDestdir().toString() + DIR_SEP + "background.gif");
184     }
185     
186     if (getDocchanges()) {
187         // There are no arguments to this argument
188
dInfo.createParam().setName("-docchanges");
189     }
190
191     // Execute the Javadoc command to compare the two XML files
192
jd.perform();
193     }
194
195     /**
196      * Generate the Javadoc for the project. If you want to generate
197      * the Javadoc report for the project with different parameters from the
198      * simple ones used here, then use the Javadoc Ant task directly, and
199      * set the javadoc attribute to the "old" or "new" element.
200      *
201      * @param proj The current Project
202      */

203     protected void generateJavadoc(ProjectInfo proj) {
204     String JavaDoc javadoc = proj.getJavadoc();
205     if (javadoc != null && javadoc.compareTo("generated") != 0) {
206         project.log("Configured to use existing Javadoc located in " +
207             javadoc, Project.MSG_INFO);
208         return;
209     }
210
211     String JavaDoc apiname = proj.getName();
212     Javadoc jd = initJavadoc("Javadoc for " + apiname);
213     jd.setDestdir(new File JavaDoc(getDestdir().toString() + DIR_SEP + apiname));
214     addSourcePaths(jd, proj);
215
216     jd.setPrivate(true);
217     jd.setPackagenames(getPackageList(proj));
218
219     // Execute the Javadoc command to generate a regular Javadoc report
220
jd.perform();
221     }
222
223     /**
224      * Create a fresh new Javadoc task object and initialize it.
225      *
226      * @param logMsg String which appears as a prefix in the Ant log
227      * @return The new task.Javadoc object
228      */

229     protected Javadoc initJavadoc(String JavaDoc logMsg) {
230     Javadoc jd = new Javadoc();
231     jd.setProject(project); // Vital, otherwise Ant crashes
232
jd.setTaskName(logMsg);
233     jd.init();
234
235     // Set up some common parameters for the Javadoc task
236
if (verboseAnt) {
237         jd.setVerbose(true);
238     }
239     return jd;
240     }
241
242     /**
243      * Add the root directories for the given project to the Javadoc
244      * sourcepath.
245      */

246     protected void addSourcePaths(Javadoc jd, ProjectInfo proj) {
247     Vector JavaDoc dirSets = proj.getDirsets();
248     int numDirSets = dirSets.size();
249     for (int i = 0; i < numDirSets; i++) {
250         DirSet dirSet = (DirSet)dirSets.elementAt(i);
251         jd.setSourcepath(new Path(project, dirSet.getDir(project).toString()));
252     }
253     }
254
255     /**
256      * Return the comma-separated list of packages. The list is
257      * generated from Ant DirSet tasks, and includes all directories
258      * in a hierarchy, e.g. com, com/acme. com/acme/foo. Duplicates are
259      * ignored.
260      */

261     protected String JavaDoc getPackageList(ProjectInfo proj) throws BuildException {
262     String JavaDoc packageList = "";
263     java.lang.StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
264     Vector JavaDoc dirSets = proj.getDirsets();
265     int numDirSets = dirSets.size();
266     boolean addComma = false;
267     for (int i = 0; i < numDirSets; i++) {
268         DirSet dirSet = (DirSet)dirSets.elementAt(i);
269         DirectoryScanner dirScanner = dirSet.getDirectoryScanner(project);
270         String JavaDoc[] files = dirScanner.getIncludedDirectories();
271         for (int j = 0; j < files.length; j++) {
272         if (!addComma){
273             addComma = true;
274         } else {
275             sb.append(",");
276         }
277         sb.append(files[j]);
278         }
279     }
280     packageList = sb.toString();
281     if (packageList.compareTo("") == 0) {
282         throw new BuildException("Error: no packages found to scan");
283     }
284     project.log(" Package list: " + packageList, Project.MSG_INFO);
285     
286     return packageList;
287     }
288
289     /**
290      * Copy a file from src to dst. Also checks that "destdir/changes" exists
291      */

292     protected void copyFile(String JavaDoc src, String JavaDoc dst){
293     File JavaDoc srcFile = new File JavaDoc(src);
294     File JavaDoc dstFile = new File JavaDoc(dst);
295     try {
296         File JavaDoc reportSubdir = new File JavaDoc(getDestdir().toString() +
297                      DIR_SEP + "changes");
298         if (!reportSubdir.mkdir() && !reportSubdir.exists()) {
299         project.log("Warning: unable to create " + reportSubdir,
300                 Project.MSG_WARN);
301         }
302
303         InputStream JavaDoc in = new FileInputStream JavaDoc(src);
304         OutputStream JavaDoc out = new FileOutputStream JavaDoc(dst);
305         
306         // Transfer bytes from in to out
307
byte[] buf = new byte[1024];
308         int len;
309         while ((len = in.read(buf)) > 0) {
310         out.write(buf, 0, len);
311         }
312         in.close();
313         out.close();
314     } catch (java.io.FileNotFoundException JavaDoc fnfe) {
315         project.log("Warning: unable to copy " + src.toString() +
316             " to " + dst.toString(), Project.MSG_WARN);
317         // Discard the exception
318
} catch (java.io.IOException JavaDoc ioe) {
319         project.log("Warning: unable to copy " + src.toString() +
320             " to " + dst.toString(), Project.MSG_WARN);
321         // Discard the exception
322
}
323     }
324
325     /**
326      * The JDiff Ant task does not inherit from an Ant task, such as the
327      * Javadoc task, though this is usually how most Tasks are
328      * written. This is because JDiff needs to run Javadoc three times
329      * (twice for generating XML, once for generating HTML). The
330      * Javadoc task has not easy way to reset its list of packages, so
331      * we needed to be able to crate new Javadoc task objects.
332      *
333      * Note: Don't confuse this class with the ProjectInfo used by JDiff.
334      * This Project class is from Ant.
335      */

336     private Project project;
337
338     /**
339      * Used as part of Ant's startup.
340      */

341     public void setProject(Project proj) {
342         project = proj;
343     }
344
345     /**
346      * Ferward or backward slash, as appropriate.
347      */

348     static String JavaDoc DIR_SEP = System.getProperty("file.separator");
349
350     /**
351      * JDIFF_HOME must be set as a property in the Ant build file.
352      * It should be set to the root JDiff directory, ie. the one above
353      * wherever jdiff/lib/jdiff.jar is found.
354      */

355     private String JavaDoc jdiffHome = "(not set)";
356
357     /**
358      * The classpath used by Javadoc to find jdiff.jar and xerces.jar.
359      */

360     private String JavaDoc jdiffClassPath = "(not set)";
361
362     /* ***************************************************************** */
363     /* * Objects and methods which are related to attributes * */
364     /* ***************************************************************** */
365
366     /**
367      * The destination directory for the generated report.
368      * The default is "./jdiff_report".
369      */

370     private File JavaDoc destdir = new File JavaDoc("jdiff_report");
371
372     /**
373      * Used to store the destdir attribute of the JDiff task XML element.
374      */

375     public void setDestdir(File JavaDoc value) {
376     this.destdir = value;
377     }
378
379     public File JavaDoc getDestdir() {
380     return this.destdir;
381     }
382
383     /**
384      * Increases the JDiff Ant task logging verbosity if set with "yes", "on"
385      * or true". Default has to be false.
386      * To increase verbosity of Javadoc, start Ant with -v or -verbose.
387      */

388     private boolean verbose = false;
389
390     public void setVerbose(boolean value) {
391     this.verbose = value;
392     }
393
394     public boolean getVerbose() {
395     return this.verbose;
396     }
397
398     /**
399      * Set if ant was started with -v or -verbose
400      */

401     private boolean verboseAnt = false;
402
403     /**
404      * Add the -docchanges argument, to track changes in Javadoc documentation
405      * as well as changes in classes etc.
406      */

407     private boolean docchanges = false;
408
409     public void setDocchanges(boolean value) {
410     this.docchanges = value;
411     }
412
413     public boolean getDocchanges() {
414     return this.docchanges;
415     }
416
417     /**
418      * Add statistics to the report if set. Default can only be false.
419      */

420     private boolean stats = false;
421
422     public void setStats(boolean value) {
423     this.stats = value;
424     }
425
426     public boolean getStats() {
427     return this.stats;
428     }
429
430     /* ***************************************************************** */
431     /* * Classes and objects which are related to elements * */
432     /* ***************************************************************** */
433
434     /**
435      * A ProjectInfo-derived object for the older version of the project
436      */

437     private ProjectInfo oldProject = null;
438
439     /**
440      * Used to store the child element named "old", which is under the
441      * JDiff task XML element.
442      */

443     public void addConfiguredOld(ProjectInfo projInfo) {
444     oldProject = projInfo;
445     }
446
447     /**
448      * A ProjectInfo-derived object for the newer version of the project
449      */

450     private ProjectInfo newProject = null;
451
452     /**
453      * Used to store the child element named "new", which is under the
454      * JDiff task XML element.
455      */

456     public void addConfiguredNew(ProjectInfo projInfo) {
457     newProject = projInfo;
458     }
459
460     /**
461      * This class handles the information about a project, whether it is
462      * the older or newer version.
463      *
464      * Note: Don't confuse this class with the Project used by Ant.
465      * This ProjectInfo class is from local to this task.
466      */

467     public static class ProjectInfo {
468     /**
469      * The name of the project. This is used (without spaces) as the
470      * base of the name of the file which contains the XML representing
471      * the project.
472      */

473     private String JavaDoc name;
474
475     public void setName(String JavaDoc value) {
476         name = value;
477     }
478
479     public String JavaDoc getName() {
480         return name;
481     }
482
483     /**
484      * The location of the Javadoc HTML for this project. Default value
485      * is "generate", which will cause the Javadoc to be generated in
486      * a subdirectory named "name" in the task's destdir directory.
487      */

488     private String JavaDoc javadoc;
489
490     public void setJavadoc(String JavaDoc value) {
491         javadoc = value;
492     }
493
494     public String JavaDoc getJavadoc() {
495         return javadoc;
496     }
497
498     /**
499      * These are the directories which contain the packages which make
500      * up the project. Filesets are not supported by JDiff.
501      */

502     private Vector JavaDoc dirsets = new Vector JavaDoc();
503
504     public void setDirset(DirSet value) {
505         dirsets.add(value);
506     }
507
508     public Vector JavaDoc getDirsets() {
509         return dirsets;
510     }
511
512     /**
513      * Used to store the child element named "dirset", which is under the
514      * "old" or "new" XML elements.
515      */

516     public void addDirset(DirSet aDirset) {
517         setDirset(aDirset);
518     }
519     
520     }
521 }
522
Popular Tags