• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package jdiff;
2 
3 import java.io.*;
4 import java.util.*;
5 
6 /**
7  * The internal representation of an API.
8  *
9  * RootDoc could have been used for representing this, but
10  * you cannot serialize a RootDoc object - see
11  *  http://developer.java.sun.com/developer/bugParade/bugs/4125581.html
12  * You might be able use Javadoc.Main() to create another RootDoc, but the
13  * methods are package private. You can run javadoc in J2SE1.4, see:
14  *  http://java.sun.com/j2se/1.4/docs/tooldocs/javadoc/standard-doclet.html#runningprogrammatically
15  * but you still can't get the RootDoc object.
16  *
17  * The advantage of writing out an XML representation of each API is that
18  * later runs of JDiff don't have to have Javadoc scan all the files again,
19  * a possibly lengthy process. XML also permits other source code in
20  * languages other than Java to be scanned to produce XML, and then versions
21  * of JDiff can be used to create documents describing the difference in those
22  * APIs.
23  *
24  * See the file LICENSE.txt for copyright details.
25  * @author Matthew Doar, mdoar@pobox.com
26  */
27 public class API {
28 
29     /**
30      * The list of all the top-level packages.
31      * Each package contains classes, each class contains members, and so on.
32      */
33     public List packages_; // PackageAPI[]
34 
35     /**
36      * The list of all the classes.
37      * This is used to generate the methods and fields which are inherited,
38      * rather than storing them in the XML file.
39      */
40     public Hashtable classes_;
41 
42     /**
43      * The String which identifies this API, e.g. &quotSuperProduct 1.3".
44      */
45     public String name_ = null;
46 
47     /** The current package being added to during parsing. */
48     public PackageAPI currPkg_ = null;
49     /** The current class being added to during parsing. */
50     public ClassAPI currClass_ = null;
51     /** The current constructor being added to during parsing. */
52     public ConstructorAPI currCtor_ = null;
53     /** The current method being added to during parsing. */
54     public MethodAPI currMethod_ = null;
55     /** The current field being added to during parsing. */
56     public FieldAPI currField_ = null;
57 
58     /** Default constructor. */
API()59     public API() {
60         packages_ = new ArrayList(); //PackageAPI[]
61         classes_ = new Hashtable(); //ClassAPI
62     }
63 
64 //
65 // Methods to display the contents of an API object.
66 //
67 
68     /** Amount by which to increment each indentation. */
69     public static final int indentInc = 2;
70 
71     /** Display the contents of the API object. */
dump()72     public void dump() {
73         int indent = 0;
74         Iterator iter = packages_.iterator();
75         while (iter.hasNext()) {
76             dumpPackage((PackageAPI)(iter.next()), indent);
77         }
78     }
79 
80     /**
81      * Display the contents of a PackageAPI object.
82      *
83      * @param pkg The given PackageAPI object.
84      * @param indent The number of spaces to indent the output.
85      */
dumpPackage(PackageAPI pkg, int indent)86     public void dumpPackage(PackageAPI pkg, int indent) {
87         for (int i = 0; i < indent; i++) System.out.print(" ");
88         System.out.println("Package Name: " + pkg.name_);
89         Iterator iter = pkg.classes_.iterator();
90         while (iter.hasNext()) {
91             dumpClass((ClassAPI)(iter.next()), indent + indentInc);
92         }
93         // Display documentation
94         if (pkg.doc_ != null) {
95             System.out.print("Package doc block:");
96             System.out.println("\"" + pkg.doc_ + "\"");
97         }
98     }
99 
100     /**
101      * Display the contents of a ClassAPI object.
102      *
103      * @param c The given ClassAPI object.
104      * @param indent The number of spaces to indent the output.
105      */
dumpClass(ClassAPI c, int indent)106     public static void dumpClass(ClassAPI c, int indent) {
107         for (int i = 0; i < indent; i++) System.out.print(" ");
108         if (c.isInterface_)
109             System.out.println("Interface name: " + c.name_);
110         else
111             System.out.println("Class Name: " + c.name_);
112         if (c.extends_ != null) {
113             for (int i = 0; i < indent; i++) System.out.print(" ");
114             System.out.println("Extends: " + c.extends_);
115         }
116         if (c.implements_.size() != 0) {
117             for (int i = 0; i < indent; i++) System.out.print(" ");
118             System.out.println("Implements: ");
119             Iterator iter = c.implements_.iterator();
120             while (iter.hasNext()) {
121                 String interfaceImpl = (String)(iter.next());
122                 for (int i = 0; i < indent + 2; i++) System.out.print(" ");
123                 System.out.println("  " + interfaceImpl);
124             }
125         }
126         // Dump modifiers specific to a class
127         if (c.isAbstract_)
128             System.out.print("abstract ");
129         // Dump modifiers common to all
130         dumpModifiers(c.modifiers_, indent);
131         // Dump ctors
132         Iterator iter = c.ctors_.iterator();
133         while (iter.hasNext()) {
134             dumpCtor((ConstructorAPI)(iter.next()), indent + indentInc);
135         }
136         // Dump methods
137         iter = c.methods_.iterator();
138         while (iter.hasNext()) {
139             dumpMethod((MethodAPI)(iter.next()), indent + indentInc);
140         }
141         // Dump fields
142         iter = c.fields_.iterator();
143         while (iter.hasNext()) {
144             dumpField((FieldAPI)(iter.next()), indent + indentInc);
145         }
146         // Display documentation
147         if (c.doc_ != null) {
148             System.out.print("Class doc block:");
149             System.out.println("\"" + c.doc_ + "\"");
150         } else
151             System.out.println();
152     }
153 
154     /**
155      * Display the contents of the Modifiers object.
156      *
157      * @param c The given Modifiers object.
158      * @param indent The number of spaces to indent the output.
159      */
dumpModifiers(Modifiers m, int indent)160     public static void dumpModifiers(Modifiers m, int indent) {
161         for (int i = 0; i < indent; i++) System.out.print(" ");
162         if (m.isStatic)
163             System.out.print("static ");
164         if (m.isFinal)
165             System.out.print("final ");
166         if (m.visibility != null)
167             System.out.print("visibility = " + m.visibility + " ");
168         // Flush the line
169         System.out.println();
170     }
171 
172     /**
173      * Display the contents of a constructor.
174      *
175      * @param c The given constructor object.
176      * @param indent The number of spaces to indent the output.
177      */
dumpCtor(ConstructorAPI c, int indent)178     public static void dumpCtor(ConstructorAPI c, int indent) {
179         for (int i = 0; i < indent; i++) System.out.print(" ");
180         System.out.println("Ctor type: " + c.type_);
181         // Display exceptions
182         System.out.print("exceptions: " + c.exceptions_ + " ");
183         // Dump modifiers common to all
184         dumpModifiers(c.modifiers_, indent);
185         // Display documentation
186         if (c.doc_ != null) {
187             System.out.print("Ctor doc block:");
188             System.out.println("\"" + c.doc_ + "\"");
189         }
190     }
191 
192     /**
193      * Display the contents of a MethodAPI object.
194      *
195      * @param m The given MethodAPI object.
196      * @param indent The number of spaces to indent the output.
197      */
dumpMethod(MethodAPI m, int indent)198     public static void dumpMethod(MethodAPI m, int indent) {
199         if (m.inheritedFrom_ != null)
200             return;
201         for (int i = 0; i < indent; i++) System.out.print(" ");
202         System.out.print("Method Name: " + m.name_);
203         if (m.inheritedFrom_ != null)
204             System.out.println(", inherited from: " + m.inheritedFrom_);
205         if (m.returnType_ != null)
206             System.out.println(", return type: " + m.returnType_);
207         else
208             System.out.println();
209         // Dump modifiers specific to a method
210         if (m.isAbstract_)
211             System.out.print("abstract ");
212         if (m.isNative_)
213             System.out.print("native ");
214         if (m.isSynchronized_)
215             System.out.print("synchronized ");
216         // Display exceptions
217         System.out.print("exceptions: " + m.exceptions_ + " ");
218         // Dump modifiers common to all
219         dumpModifiers(m.modifiers_, indent);
220 
221         Iterator iter = m.params_.iterator();
222         while (iter.hasNext()) {
223             dumpParam((ParamAPI)(iter.next()), indent + indentInc);
224         }
225         // Display documentation
226         if (m.doc_ != null) {
227             System.out.print("Method doc block:");
228             System.out.println("\"" + m.doc_ + "\"");
229         }
230     }
231 
232     /**
233      * Display the contents of a field.
234      * Does not show inherited fields.
235      *
236      * @param f The given field object.
237      * @param indent The number of spaces to indent the output.
238      */
dumpField(FieldAPI f, int indent)239     public static void dumpField(FieldAPI f, int indent) {
240         if (f.inheritedFrom_ != null)
241             return;
242         for (int i = 0; i < indent; i++) System.out.print(" ");
243         System.out.println("Field Name: " + f.name_ + ", type: " + f.type_);
244         if (f.inheritedFrom_ != null)
245             System.out.println(", inherited from: " + f.inheritedFrom_);
246         if (f.isTransient_)
247             System.out.print("transient ");
248         if (f.isVolatile_)
249             System.out.print("volatile ");
250         // Dump modifiers common to all
251         dumpModifiers(f.modifiers_, indent);
252         // Display documentation
253         if (f.doc_ != null)
254             System.out.print("Field doc block:");
255             System.out.println("\"" + f.doc_ + "\"");
256     }
257 
258     /**
259      * Display the contents of a parameter.
260      *
261      * @param p The given parameter object.
262      * @param indent The number of spaces to indent the output.
263      */
dumpParam(ParamAPI p, int indent)264     public static void dumpParam(ParamAPI p, int indent) {
265         for (int i = 0; i < indent; i++) System.out.print(" ");
266         System.out.println("Param Name: " + p.name_ + ", type: " + p.type_);
267     }
268 
269     /**
270      * Convert all HTML tags to text by placing them inside a CDATA element.
271      * Characters still have to be valid Unicode characters as defined by the
272      * parser.
273      */
stuffHTMLTags(String htmlText)274     public static String stuffHTMLTags(String htmlText) {
275         if (htmlText.indexOf("]]>") != -1) {
276             System.out.println("Warning: illegal string ]]> found in text. Ignoring the comment.");
277             return "";
278         }
279         return "<![CDATA[" + htmlText + "]]>";
280     }
281 
282     /**
283      * Convert all HTML tags to text by stuffing text into the HTML tag
284      * to stop it being an HTML or XML tag. E.g. &quot;<code>foo</code>&quot;
285      * becomes &quot;lEsS_tHaNcode>foolEsS_tHaN/code>&quot;. Replace all &lt;
286      * characters
287      * with the string "lEsS_tHaN". Also replace &amp; character with the
288      * string "aNd_cHaR" to avoid text entities. Also replace &quot;
289      * character with the
290      * string "qUoTe_cHaR".
291      */
hideHTMLTags(String htmlText)292     public static String hideHTMLTags(String htmlText) {
293         StringBuffer sb = new StringBuffer(htmlText);
294         int i = 0;
295         while (i < sb.length()) {
296             if (sb.charAt(i) == '<') {
297                 sb.setCharAt(i ,'l');
298                 sb.insert(i+1, "EsS_tHaN");
299             } else if (sb.charAt(i) == '&') {
300                 sb.setCharAt(i ,'a');
301                 sb.insert(i+1, "Nd_cHaR");
302             } else if (sb.charAt(i) == '"') {
303                 sb.setCharAt(i ,'q');
304                 sb.insert(i+1, "uote_cHaR");
305             }
306             i++;
307         }
308         return sb.toString();
309     }
310 
311     /**
312      * Convert text with stuffed HTML tags ("lEsS_tHaN", etc) into HTML text.
313      */
showHTMLTags(String text)314     public static String showHTMLTags(String text) {
315         StringBuffer sb = new StringBuffer(text);
316         StringBuffer res = new StringBuffer();
317         int len = sb.length();
318         res.setLength(len);
319         int i = 0;
320         int resIdx = 0;
321         while (i < len) {
322             char c = sb.charAt(i);
323             if (len - i > 8 && c == 'l' &&
324                 sb.charAt(i+1) == 'E' &&
325                 sb.charAt(i+2) == 's' &&
326                 sb.charAt(i+3) == 'S' &&
327                 sb.charAt(i+4) == '_' &&
328                 sb.charAt(i+5) == 't' &&
329                 sb.charAt(i+6) == 'H' &&
330                 sb.charAt(i+7) == 'a' &&
331                 sb.charAt(i+8) == 'N') {
332                 res.setCharAt(resIdx ,'<');
333                 i += 8;
334             } else if (len - i > 9 && c == 'q' &&
335                 sb.charAt(i+1) == 'U' &&
336                 sb.charAt(i+2) == 'o' &&
337                 sb.charAt(i+3) == 'T' &&
338                 sb.charAt(i+4) == 'e' &&
339                 sb.charAt(i+5) == '_' &&
340                 sb.charAt(i+6) == 'c' &&
341                 sb.charAt(i+7) == 'H' &&
342                 sb.charAt(i+8) == 'a' &&
343                 sb.charAt(i+9) == 'R') {
344                 res.setCharAt(resIdx ,'"');
345                 i += 9;
346             } else if (len - i > 7 && c == 'a' &&
347                 sb.charAt(i+1) == 'N' &&
348                 sb.charAt(i+2) == 'd' &&
349                 sb.charAt(i+3) == '_' &&
350                 sb.charAt(i+4) == 'c' &&
351                 sb.charAt(i+5) == 'H' &&
352                 sb.charAt(i+6) == 'a' &&
353                 sb.charAt(i+7) == 'R') {
354                 res.setCharAt(resIdx ,'&');
355                 i += 7;
356             } else {
357                 res.setCharAt(resIdx, c);
358             }
359             i++;
360             resIdx++;
361         }
362         res.setLength(resIdx);
363         return res.toString();
364     }
365 
366     /**
367      * <b>NOT USED</b>.
368      *
369      * Replace all instances of <p> with <p/>. Just for the small number
370      * of HMTL tags which don't require a matching end tag.
371      * Also make HTML conform to the simple HTML requirements such as
372      * no double hyphens. Double hyphens are replaced by - and the character
373      * entity for a hyphen.
374      *
375      * Cases where this fails and has to be corrected in the XML by hand:
376      *  Attributes' values missing their double quotes , e.g. size=-2
377      *  Mangled HTML tags e.g. &lt;ttt>
378      *
379      * <p><b>NOT USED</b>. There is often too much bad HTML in
380      * doc blocks to try to handle every case correctly. Better just to
381      * stuff the *lt; and &amp: characters with stuffHTMLTags(). Though
382      * the resulting XML is not as elegant, it does the job with less
383      * intervention by the user.
384      */
convertHTMLTagsToXHTML(String htmlText)385     public static String convertHTMLTagsToXHTML(String htmlText) {
386         StringBuffer sb = new StringBuffer(htmlText);
387         int i = 0;
388         boolean inTag = false;
389         String tag = null;
390         // Needs to re-evaluate this length at each loop
391         while (i < sb.length()) {
392             char c = sb.charAt(i);
393             if (inTag) {
394                 if (c == '>') {
395                     // OPTION Could fail at or fix some errorneous tags here
396                     // Make the best guess as to whether this tag is terminated
397                     if (Comments.isMinimizedTag(tag) &&
398                         htmlText.indexOf("</" + tag + ">", i) == -1)
399                         sb.insert(i, "/");
400                     inTag = false;
401                 } else {
402                     // OPTION could also make sure that attribute values are
403                     // surrounded by quotes.
404                     tag += c;
405                 }
406             }
407             if (c == '<') {
408                 inTag = true;
409                 tag = "";
410             }
411             // -- is not allowed in XML, but !-- is part of an comment,
412             // and --> is also part of a comment
413             if (c == '-' && i > 0 && sb.charAt(i-1) == '-') {
414                 if (!(i > 1 && sb.charAt(i-2) == '!')) {
415                     sb.setCharAt(i, '&');
416                     sb.insert(i+1, "#045;");
417                     i += 5;
418                 }
419             }
420             i++;
421         }
422         if (inTag) {
423             // Oops. Someone forgot to close their HTML tag, e.g. "<code."
424             // Close it for them.
425             sb.insert(i, ">");
426         }
427         return sb.toString();
428     }
429 }
430