KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > jdiff > JDiff


1 package jdiff;
2
3 import com.sun.javadoc.*;
4
5 import java.util.*;
6 import java.io.*;
7 import java.lang.reflect.*; // Used for invoking Javadoc indirectly
8
import java.lang.Runtime JavaDoc;
9 import java.lang.Process JavaDoc;
10
11 /**
12  * Generates HTML describing the changes between two sets of Java source code.
13  *
14  * See the file LICENSE.txt for copyright details.
15  * @author Matthew Doar, doar@pobox.com.
16  */

17 public class JDiff extends Doclet {
18
19     /**
20      * Doclet-mandated start method. Everything begins here.
21      *
22      * @param root a RootDoc object passed by Javadoc
23      * @return true if document generation succeeds
24      */

25     public static boolean start(RootDoc root) {
26         if (root != null)
27             System.out.println("JDiff: doclet started ...");
28         JDiff jd = new JDiff();
29         return jd.startGeneration(root);
30     }
31
32     /**
33      * Generate the summary of the APIs.
34      *
35      * @param root the RootDoc object passed by Javadoc
36      * @return true if no problems encountered within JDiff
37      */

38     protected boolean startGeneration(RootDoc newRoot) {
39         long startTime = System.currentTimeMillis();
40
41         // Open the file where the XML representing the API will be stored.
42
// and generate the XML for the API into it.
43
if (writeXML) {
44             RootDocToXML.writeXML(newRoot);
45         }
46
47         if (compareAPIs) {
48         String JavaDoc tempOldFileName = oldFileName;
49         if (oldDirectory != null) {
50         tempOldFileName = oldDirectory;
51         if (!tempOldFileName.endsWith(JDiff.DIR_SEP)) {
52             tempOldFileName += JDiff.DIR_SEP;
53         }
54         tempOldFileName += oldFileName;
55         }
56
57             // Check the file for the old API exists
58
File f = new File(tempOldFileName);
59             if (!f.exists()) {
60                 System.out.println("Error: file '" + tempOldFileName + "' does not exist for the old API");
61                 return false;
62             }
63             // Check the file for the new API exists
64

65         String JavaDoc tempNewFileName = newFileName;
66             if (newDirectory != null) {
67         tempNewFileName = newDirectory;
68         if (!tempNewFileName.endsWith(JDiff.DIR_SEP)) {
69             tempNewFileName += JDiff.DIR_SEP;
70         }
71         tempNewFileName += newFileName;
72             }
73             f = new File(tempNewFileName);
74             if (!f.exists()) {
75                 System.out.println("Error: file '" + tempNewFileName + "' does not exist for the new API");
76                 return false;
77             }
78
79             // Read the file where the XML representing the old API is stored
80
// and create an API object for it.
81
System.out.print("JDiff: reading the old API in from file '" + tempOldFileName + "'...");
82             // Read the file in, but do not add any text to the global comments
83
API oldAPI = XMLToAPI.readFile(tempOldFileName, false, oldFileName);
84             
85             // Read the file where the XML representing the new API is stored
86
// and create an API object for it.
87
System.out.print("JDiff: reading the new API in from file '" + tempNewFileName + "'...");
88             // Read the file in, and do add any text to the global comments
89
API newAPI = XMLToAPI.readFile(tempNewFileName, true, newFileName);
90             
91             // Compare the old and new APIs.
92
APIComparator comp = new APIComparator();
93             
94             comp.compareAPIs(oldAPI, newAPI);
95             
96             // Read the file where the XML for comments about the changes between
97
// the old API and new API is stored and create a Comments object for
98
// it. The Comments object may be null if no file exists.
99
int suffix = oldFileName.lastIndexOf('.');
100             String JavaDoc commentsFileName = "user_comments_for_" + oldFileName.substring(0, suffix);
101             suffix = newFileName.lastIndexOf('.');
102             commentsFileName += "_to_" + newFileName.substring(0, suffix) + ".xml";
103             commentsFileName = commentsFileName.replace(' ', '_');
104             if (HTMLReportGenerator.outputDir != null)
105                 commentsFileName = HTMLReportGenerator.outputDir + DIR_SEP + commentsFileName;
106             System.out.println("JDiff: reading the comments in from file '" + commentsFileName + "'...");
107             Comments existingComments = Comments.readFile(commentsFileName);
108             if (existingComments == null)
109                 System.out.println(" (this will be created)");
110             
111             // Generate an HTML report which summarises all the API differences.
112
HTMLReportGenerator reporter = new HTMLReportGenerator();
113             reporter.generate(comp, existingComments);
114             
115             // Emit messages about which comments are now unused and
116
// which are new.
117
Comments newComments = reporter.getNewComments();
118             Comments.noteDifferences(existingComments, newComments);
119             
120             // Write the new comments out to the same file, with unused comments
121
// now commented out.
122
System.out.println("JDiff: writing the comments out to file '" + commentsFileName + "'...");
123             Comments.writeFile(commentsFileName, newComments);
124         }
125
126         System.out.print("JDiff: finished (took " + (System.currentTimeMillis() - startTime)/1000 + "s");
127         if (writeXML)
128             System.out.println(", not including scanning the source files).");
129         else if (compareAPIs)
130             System.out.println(").");
131        return true;
132     }
133
134 //
135
// Option processing
136
//
137

138     /**
139      * This method is called by Javadoc to
140      * parse the options it does not recognize. It then calls
141      * {@link #validOptions} to validate them.
142      *
143      * @param option a String containing an option
144      * @return an int telling how many components that option has
145      */

146     public static int optionLength(String JavaDoc option) {
147         return Options.optionLength(option);
148     }
149
150     /**
151      * After parsing the available options using {@link #optionLength},
152      * Javadoc invokes this method with an array of options-arrays.
153      *
154      * @param options an array of String arrays, one per option
155      * @param reporter a DocErrorReporter for generating error messages
156      * @return true if no errors were found, and all options are
157      * valid
158      */

159     public static boolean validOptions(String JavaDoc[][] options,
160                                        DocErrorReporter reporter) {
161         return Options.validOptions(options, reporter);
162     }
163     
164     /**
165      * This method is only called when running JDiff as a standalone
166      * application, and uses ANT to execute the build configuration in the
167      * XML configuration file passed in.
168      */

169     public static void main(String JavaDoc[] args) {
170         if (args.length == 0) {
171             //showUsage();
172
System.out.println("Looking for a local 'build.xml' configuration file");
173         } else if (args.length == 1) {
174             if (args[0].compareTo("-help") == 0 ||
175                 args[0].compareTo("-h") == 0 ||
176                 args[0].compareTo("?") == 0) {
177                 showUsage();
178             } else if (args[0].compareTo("-version") == 0) {
179                 System.out.println("JDiff version: " + JDiff.version);
180             }
181             return;
182         }
183         int rc = runAnt(args);
184         return;
185     }
186
187     /**
188      * Display usage information for JDiff.
189      */

190     public static void showUsage() {
191         System.out.println("usage: java jdiff.JDiff [-version] [-buildfile <XML configuration file>]");
192         System.out.println("If no build file is specified, the local build.xml file is used.");
193     }
194
195     /**
196      * Invoke ANT by reflection.
197      *
198      * @return The integer return code from running ANT.
199      */

200     public static int runAnt(String JavaDoc[] args) {
201         String JavaDoc className = null;
202         Class JavaDoc c = null;
203         try {
204             className = "org.apache.tools.ant.Main";
205             c = Class.forName(className);
206         } catch (ClassNotFoundException JavaDoc e1) {
207             System.err.println("Error: ant.jar not found on the classpath");
208             return -1;
209         }
210         try {
211             Class JavaDoc[] methodArgTypes = new Class JavaDoc[1];
212             methodArgTypes[0] = args.getClass();
213             Method mainMethod = c.getMethod("main", methodArgTypes);
214             Object JavaDoc[] methodArgs = new Object JavaDoc[1];
215             methodArgs[0] = args;
216             // The object can be null because the method is static
217
Integer JavaDoc res = (Integer JavaDoc)mainMethod.invoke(null, methodArgs);
218             System.gc(); // Clean up after running ANT
219
return res.intValue();
220         } catch (NoSuchMethodException JavaDoc e2) {
221             System.err.println("Error: method \"main\" not found");
222             e2.printStackTrace();
223         } catch (IllegalAccessException JavaDoc e4) {
224             System.err.println("Error: class not permitted to be instantiated");
225             e4.printStackTrace();
226         } catch (InvocationTargetException e5) {
227             System.err.println("Error: method \"main\" could not be invoked");
228             e5.printStackTrace();
229         } catch (Exception JavaDoc e6) {
230             System.err.println("Error: ");
231             e6.printStackTrace();
232         }
233         System.gc(); // Clean up after running ANT
234
return -1;
235     }
236
237     /**
238      * The name of the file where the XML representing the old API is
239      * stored.
240      */

241     static String JavaDoc oldFileName = "old_java.xml";
242
243     /**
244      * The name of the directory where the XML representing the old API is
245      * stored.
246      */

247     static String JavaDoc oldDirectory = null;
248
249     /**
250      * The name of the file where the XML representing the new API is
251      * stored.
252      */

253     static String JavaDoc newFileName = "new_java.xml";
254
255     /**
256      * The name of the directory where the XML representing the new API is
257      * stored.
258      */

259     static String JavaDoc newDirectory = null;
260
261     /** If set, then generate the XML for an API and exit. */
262     static boolean writeXML = false;
263
264     /** If set, then read in two XML files and compare their APIs. */
265     static boolean compareAPIs = false;
266
267     /**
268      * The file separator for the local filesystem, forward or backward slash.
269      */

270     static String JavaDoc DIR_SEP = System.getProperty("file.separator");
271
272     /** Details for where to find JDiff. */
273     static final String JavaDoc jDiffLocation = "http://www.jdiff.org";
274     /** Contact email address for the JDiff maintainer. */
275     static final String JavaDoc authorEmail = "doar@pobox.com";
276
277     /** A description for HTML META tags. */
278     static final String JavaDoc jDiffDescription = "JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared.";
279     /** Keywords for HTML META tags. */
280     static final String JavaDoc jDiffKeywords = "diff, jdiff, javadiff, java diff, java difference, API difference, difference between two APIs, API diff, Javadoc, doclet";
281
282     /** The current JDiff version. */
283     static final String JavaDoc version = "1.0.10";
284
285     /** The current JVM version. */
286     static String JavaDoc javaVersion = System.getProperty("java.version");
287
288     /** Set to enable increased logging verbosity for debugging. */
289     private static boolean trace = false;
290
291 } //JDiff
292
Popular Tags