]> gitweb.fperrin.net Git - Dictionary.git/blob - jars/icu4j-4_4_2-src/tools/build/src/com/ibm/icu/dev/tool/docs/GatherAPIDataOld.java
go
[Dictionary.git] / jars / icu4j-4_4_2-src / tools / build / src / com / ibm / icu / dev / tool / docs / GatherAPIDataOld.java
1 /**\r
2  *******************************************************************************\r
3  * Copyright (C) 2004-2010, International Business Machines Corporation and    *\r
4  * others. All Rights Reserved.                                                *\r
5  *******************************************************************************\r
6  */\r
7 \r
8 /**\r
9  * Generate a list of ICU's public APIs, sorted by qualified name and signature\r
10  * public APIs are all non-internal, non-package apis in com.ibm.icu.[lang|math|text|util].\r
11  * For each API, list\r
12  * - public, package, protected, or private (PB PK PT PR)\r
13  * - static or non-static (STK NST)\r
14  * - final or non-final (FN NF)\r
15  * - synchronized or non-synchronized (SYN NSY)\r
16  * - stable, draft, deprecated, obsolete (ST DR DP OB)\r
17  * - abstract or non-abstract (AB NA)\r
18  * - constructor, member, field (C M F)\r
19  *\r
20  * Requires JDK 1.4.2 or later\r
21  * \r
22  * Sample compilation:\r
23  * c:/doug/java/jdk1.4.2/build/windows-i586/bin/javac *.java\r
24  *\r
25  * Sample execution\r
26  * c:/j2sdk1.4.2/bin/javadoc\r
27  *   -classpath c:/jd2sk1.4.2/lib/tools.jar \r
28  *   -doclet com.ibm.icu.dev.tool.docs.GatherAPIData\r
29  *   -docletpath c:/doug/cvsproj/icu4j/src \r
30  *   -sourcepath c:/doug/cvsproj/icu4j/src \r
31  *   -name "ICU4J 3.0"\r
32  *   -output icu4j30.api\r
33  *   -gzip\r
34  *   -source 1.4\r
35  *   com.ibm.icu.lang com.ibm.icu.math com.ibm.icu.text com.ibm.icu.util\r
36  *\r
37  * todo: provide command-line control of filters of which subclasses/packages to process\r
38  * todo: record full inheritance heirarchy, not just immediate inheritance \r
39  * todo: allow for aliasing comparisons (force (pkg.)*class to be treated as though it \r
40  *       were in a different pkg/class heirarchy (facilitates comparison of icu4j and java)\r
41  */\r
42 \r
43 package com.ibm.icu.dev.tool.docs;\r
44 \r
45 // standard release sdk won't work, need internal build to get access to javadoc\r
46 import java.io.BufferedWriter;\r
47 import java.io.FileOutputStream;\r
48 import java.io.IOException;\r
49 import java.io.OutputStream;\r
50 import java.io.OutputStreamWriter;\r
51 import java.util.Collection;\r
52 import java.util.Iterator;\r
53 import java.util.TreeSet;\r
54 import java.util.regex.Pattern;\r
55 import java.util.zip.GZIPOutputStream;\r
56 import java.util.zip.ZipEntry;\r
57 import java.util.zip.ZipOutputStream;\r
58 \r
59 import com.sun.javadoc.ClassDoc;\r
60 import com.sun.javadoc.ConstructorDoc;\r
61 import com.sun.javadoc.Doc;\r
62 import com.sun.javadoc.ExecutableMemberDoc;\r
63 import com.sun.javadoc.FieldDoc;\r
64 import com.sun.javadoc.MethodDoc;\r
65 import com.sun.javadoc.ProgramElementDoc;\r
66 import com.sun.javadoc.RootDoc;\r
67 import com.sun.javadoc.Tag;\r
68 \r
69 public class GatherAPIDataOld {\r
70     RootDoc root;\r
71     TreeSet results;\r
72     String srcName = "Current"; // default source name\r
73     String output; // name of output file to write\r
74     String base; // strip this prefix\r
75     Pattern pat;\r
76     boolean zip;\r
77     boolean gzip;\r
78     boolean internal;\r
79     boolean version;\r
80 \r
81     public static int optionLength(String option) {\r
82         if (option.equals("-name")) {\r
83             return 2;\r
84         } else if (option.equals("-output")) {\r
85             return 2;\r
86         } else if (option.equals("-base")) {\r
87             return 2;\r
88         } else if (option.equals("-filter")) {\r
89             return 2;\r
90         } else if (option.equals("-zip")) {\r
91             return 1;\r
92         } else if (option.equals("-gzip")) {\r
93             return 1;\r
94         } else if (option.equals("-internal")) {\r
95             return 1;\r
96         } else if (option.equals("-version")) {\r
97             return 1;\r
98         }\r
99         return 0;\r
100     }\r
101 \r
102     public static boolean start(RootDoc root) {\r
103         return new GatherAPIDataOld(root).run();\r
104     }\r
105 \r
106     GatherAPIDataOld(RootDoc root) {\r
107         this.root = root;\r
108 \r
109         String[][] options = root.options();\r
110         for (int i = 0; i < options.length; ++i) {\r
111             String opt = options[i][0];\r
112             if (opt.equals("-name")) {\r
113                 this.srcName = options[i][1];\r
114             } else if (opt.equals("-output")) {\r
115                 this.output = options[i][1];\r
116             } else if (opt.equals("-base")) {\r
117                 this.base = options[i][1]; // should not include '.'\r
118             } else if (opt.equals("-filter")) {\r
119                 this.pat = Pattern.compile(options[i][1], Pattern.CASE_INSENSITIVE);\r
120             } else if (opt.equals("-zip")) {\r
121                 this.zip = true;\r
122             } else if (opt.equals("-gzip")) {\r
123                 this.gzip = true;\r
124             } else if (opt.equals("-internal")) {\r
125                 this.internal = true;\r
126             } else if (opt.equals("-version")) {\r
127                 this.version = true;\r
128             }\r
129         }\r
130 \r
131         results = new TreeSet(APIInfo.defaultComparator());\r
132     }\r
133 \r
134     private boolean run() {\r
135         doDocs(root.classes());\r
136 \r
137         OutputStream os = System.out;\r
138         if (output != null) {\r
139             try {\r
140                 if (zip) {\r
141                     ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(output + ".zip"));\r
142                     zos.putNextEntry(new ZipEntry(output));\r
143                     os = zos;\r
144                 } else if (gzip) {\r
145                     os = new GZIPOutputStream(new FileOutputStream(output + ".gz"));\r
146                 } else {\r
147                     os = new FileOutputStream(output);\r
148                 }\r
149             }\r
150             catch (IOException e) {\r
151                 RuntimeException re = new RuntimeException(e.getMessage());\r
152                 re.initCause(e);\r
153                 throw re;\r
154             }\r
155         }\r
156 \r
157         BufferedWriter bw = null;\r
158         try {\r
159             OutputStreamWriter osw = new OutputStreamWriter(os, "UTF-8");\r
160             bw = new BufferedWriter(osw);\r
161 \r
162             // writing data file\r
163             bw.write(String.valueOf(APIInfo.VERSION) + APIInfo.SEP); // header version\r
164             bw.write(srcName + APIInfo.SEP); // source name\r
165             bw.write((base == null ? "" : base) + APIInfo.SEP); // base\r
166             bw.newLine();\r
167             writeResults(results, bw);\r
168             bw.close(); // should flush, close all, etc\r
169         } catch (IOException e) {\r
170             try { bw.close(); } catch (IOException e2) {}\r
171             RuntimeException re = new RuntimeException("write error: " + e.getMessage());\r
172             re.initCause(e);\r
173             throw re;\r
174         }\r
175 \r
176         return false;\r
177     }\r
178 \r
179     private void doDocs(ProgramElementDoc[] docs) {\r
180         if (docs != null && docs.length > 0) {\r
181             for (int i = 0; i < docs.length; ++i) {\r
182                 doDoc(docs[i]);\r
183             }\r
184         }\r
185     }\r
186 \r
187     private void doDoc(ProgramElementDoc doc) {\r
188         if (ignore(doc)) return;\r
189 \r
190         if (doc.isClass() || doc.isInterface()) {\r
191             ClassDoc cdoc = (ClassDoc)doc;\r
192             doDocs(cdoc.fields());\r
193             doDocs(cdoc.constructors());\r
194             doDocs(cdoc.methods());\r
195             doDocs(cdoc.innerClasses());\r
196         }\r
197 \r
198         APIInfo info = createInfo(doc);\r
199         if (info != null) {\r
200             results.add(info);\r
201         }\r
202     }\r
203 \r
204     private boolean ignore(ProgramElementDoc doc) {\r
205         if (doc == null) return true;\r
206         if (doc.isPrivate() || doc.isPackagePrivate()) return true;\r
207         if (doc instanceof ConstructorDoc && ((ConstructorDoc)doc).isSynthetic()) return true;\r
208         if (doc.qualifiedName().indexOf(".misc") != -1) { \r
209             System.out.println("misc: " + doc.qualifiedName()); return true; \r
210         }\r
211         if (!internal) { // debug\r
212             Tag[] tags = doc.tags();\r
213             for (int i = 0; i < tags.length; ++i) {\r
214                 if (tagKindIndex(tags[i].kind()) == INTERNAL) { return true; }\r
215             }\r
216         }\r
217         if (pat != null && (doc.isClass() || doc.isInterface())) {\r
218             if (!pat.matcher(doc.name()).matches()) {\r
219                 return true;\r
220             }\r
221         }\r
222         return false;\r
223     }\r
224 \r
225     private static void writeResults(Collection c, BufferedWriter w) {\r
226         Iterator iter = c.iterator();\r
227         while (iter.hasNext()) {\r
228             APIInfo info = (APIInfo)iter.next();\r
229             info.writeln(w);\r
230         }\r
231     }\r
232 \r
233     private String trimBase(String arg) {\r
234         if (base != null) {\r
235             for (int n = arg.indexOf(base); n != -1; n = arg.indexOf(base, n)) {\r
236                 arg = arg.substring(0, n) + arg.substring(n+base.length());\r
237             }\r
238         }\r
239         return arg;\r
240     }\r
241 \r
242     public APIInfo createInfo(ProgramElementDoc doc) {\r
243 \r
244         // Doc. name\r
245         // Doc. isField, isMethod, isConstructor, isClass, isInterface\r
246         // ProgramElementDoc. containingClass, containingPackage\r
247         // ProgramElementDoc. isPublic, isProtected, isPrivate, isPackagePrivate\r
248         // ProgramElementDoc. isStatic, isFinal\r
249         // MemberDoc.isSynthetic\r
250         // ExecutableMemberDoc isSynchronized, signature\r
251         // Type.toString() // e.g. "String[][]"\r
252         // ClassDoc.isAbstract, superClass, interfaces, fields, methods, constructors, innerClasses\r
253         // FieldDoc type\r
254         // ConstructorDoc qualifiedName\r
255         // MethodDoc isAbstract, returnType\r
256 \r
257         APIInfo info = new APIInfo();\r
258         if (version) {\r
259             info.includeStatusVersion(true);\r
260         }\r
261             \r
262         // status\r
263         String[] version = new String[1];\r
264         info.setType(APIInfo.STA, tagStatus(doc, version));\r
265         info.setStatusVersion(version[0]);\r
266 \r
267         // visibility\r
268         if (doc.isPublic()) {\r
269             info.setPublic();\r
270         } else if (doc.isProtected()) {\r
271             info.setProtected();\r
272         } else if (doc.isPrivate()) {\r
273             info.setPrivate();\r
274         } else {\r
275             // default is package\r
276         }\r
277 \r
278         // static\r
279         if (doc.isStatic()) {\r
280             info.setStatic();\r
281         } else {\r
282             // default is non-static\r
283         }\r
284 \r
285         // final\r
286         if (doc.isFinal()) {\r
287             info.setFinal();\r
288         } else {\r
289             // default is non-final\r
290         }\r
291 \r
292         // type\r
293         if (doc.isField()) {\r
294             info.setField();\r
295         } else if (doc.isMethod()) {\r
296             info.setMethod();\r
297         } else if (doc.isConstructor()) {\r
298             info.setConstructor();\r
299         } else if (doc.isClass() || doc.isInterface()) {\r
300             info.setClass();\r
301         }\r
302 \r
303         info.setPackage(trimBase(doc.containingPackage().name()));\r
304         info.setClassName((doc.isClass() || doc.isInterface() || (doc.containingClass() == null)) \r
305                           ? "" \r
306                           : trimBase(doc.containingClass().name()));\r
307         info.setName(trimBase(doc.name()));\r
308 \r
309         if (doc instanceof FieldDoc) {\r
310             FieldDoc fdoc = (FieldDoc)doc;\r
311             info.setSignature(trimBase(fdoc.type().toString()));\r
312         } else if (doc instanceof ClassDoc) {\r
313             ClassDoc cdoc = (ClassDoc)doc;\r
314 \r
315             if (cdoc.isClass() && cdoc.isAbstract()) { \r
316                 // interfaces are abstract by default, don't mark them as abstract\r
317                 info.setAbstract();\r
318             }\r
319 \r
320             StringBuffer buf = new StringBuffer();\r
321             if (cdoc.isClass()) {\r
322                 buf.append("extends ");\r
323                 buf.append(cdoc.superclass().qualifiedName());\r
324             }\r
325             ClassDoc[] imp = cdoc.interfaces();\r
326             if (imp != null && imp.length > 0) {\r
327                 if (buf.length() > 0) {\r
328                     buf.append(" ");\r
329                 }\r
330                 buf.append("implements");\r
331                 for (int i = 0; i < imp.length; ++i) {\r
332                     if (i != 0) {\r
333                         buf.append(",");\r
334                     }\r
335                     buf.append(" ");\r
336                     buf.append(imp[i].qualifiedName());\r
337                 }\r
338             }\r
339             info.setSignature(trimBase(buf.toString()));\r
340         } else {\r
341             ExecutableMemberDoc emdoc = (ExecutableMemberDoc)doc;\r
342             if (emdoc.isSynchronized()) {\r
343                 info.setSynchronized();\r
344             }\r
345 \r
346             if (doc instanceof MethodDoc) {\r
347                 MethodDoc mdoc = (MethodDoc)doc;\r
348                 if (mdoc.isAbstract()) {\r
349                     info.setAbstract();\r
350                 }\r
351                 info.setSignature(trimBase(mdoc.returnType().toString() + emdoc.signature()));\r
352             } else {\r
353                 // constructor\r
354                 info.setSignature(trimBase(emdoc.signature()));\r
355             }\r
356         }\r
357 \r
358         return info;\r
359     }\r
360 \r
361     private int tagStatus(final Doc doc, String[] version) {\r
362         class Result {\r
363             int res = -1;\r
364             void set(int val) { \r
365                 if (res != -1) {\r
366                     if (val == APIInfo.STA_DEPRECATED) {\r
367                         // ok to have both a 'standard' tag and deprecated\r
368                         return;\r
369                     } else if (res != APIInfo.STA_DEPRECATED) {\r
370                         // if already not deprecated, this is an error\r
371                         System.err.println("bad doc: " + doc + " both: " + APIInfo.getTypeValName(APIInfo.STA, res) + " and: " + APIInfo.getTypeValName(APIInfo.STA, val)); \r
372                         return;\r
373                     }\r
374                 }\r
375                 // ok to replace with new tag\r
376                 res = val;\r
377             }\r
378             int get() {\r
379                 if (res == -1) {\r
380                     System.err.println("warning: no tag for " + doc);\r
381                     return 0;\r
382                 }\r
383                 return res;\r
384             }\r
385         }\r
386 \r
387         Tag[] tags = doc.tags();\r
388         Result result = new Result();\r
389         String statusVer = "";\r
390         for (int i = 0; i < tags.length; ++i) {\r
391             Tag tag = tags[i];\r
392 \r
393             String kind = tag.kind();\r
394             int ix = tagKindIndex(kind);\r
395 \r
396             switch (ix) {\r
397             case INTERNAL:\r
398                 result.set(internal ? APIInfo.STA_INTERNAL : -2); // -2 for legacy compatibility\r
399                 statusVer = getStatusVersion(tag);\r
400                 break;\r
401 \r
402             case DRAFT:\r
403                 result.set(APIInfo.STA_DRAFT);\r
404                 statusVer = getStatusVersion(tag);\r
405                 break;\r
406 \r
407             case STABLE:\r
408                 result.set(APIInfo.STA_STABLE);\r
409                 statusVer = getStatusVersion(tag);\r
410                 break;\r
411 \r
412             case DEPRECATED:\r
413                 result.set(APIInfo.STA_DEPRECATED);\r
414                 statusVer = getStatusVersion(tag);\r
415                 break;\r
416 \r
417             case OBSOLETE:\r
418                 result.set(APIInfo.STA_OBSOLETE);\r
419                 statusVer = getStatusVersion(tag);\r
420                 break;\r
421 \r
422             case SINCE:\r
423             case EXCEPTION:\r
424             case VERSION:\r
425             case UNKNOWN:\r
426             case AUTHOR:\r
427             case SEE:\r
428             case PARAM:\r
429             case RETURN:\r
430             case THROWS:\r
431             case SERIAL:\r
432                 break;\r
433 \r
434             default:\r
435                 throw new RuntimeException("unknown index " + ix + " for tag: " + kind);\r
436             }\r
437         }\r
438 \r
439         if (version != null) {\r
440             version[0] = statusVer;\r
441         }\r
442         return result.get();\r
443     }\r
444 \r
445     private String getStatusVersion(Tag tag) {\r
446         String text = tag.text();\r
447         if (text != null && text.length() > 0) {\r
448             // Extract version string\r
449             int start = -1;\r
450             int i = 0;\r
451             for (; i < text.length(); i++) {\r
452                 char ch = text.charAt(i);\r
453                 if (ch == '.' || (ch >= '0' && ch <= '9')) {\r
454                     if (start == -1) {\r
455                         start = i;\r
456                     }\r
457                 } else if (start != -1) {\r
458                     break;\r
459                 }\r
460             }\r
461             if (start != -1) {\r
462                 return text.substring(start, i);\r
463             }\r
464         }\r
465         return "";\r
466     }\r
467 \r
468     private static final int UNKNOWN = -1;\r
469     private static final int INTERNAL = 0;\r
470     private static final int DRAFT = 1;\r
471     private static final int STABLE = 2;\r
472     private static final int SINCE = 3;\r
473     private static final int DEPRECATED = 4;\r
474     private static final int AUTHOR = 5;\r
475     private static final int SEE = 6;\r
476     private static final int VERSION = 7;\r
477     private static final int PARAM = 8;\r
478     private static final int RETURN = 9;\r
479     private static final int THROWS = 10;\r
480     private static final int OBSOLETE = 11;\r
481     private static final int EXCEPTION = 12;\r
482     private static final int SERIAL = 13;\r
483 \r
484     private static int tagKindIndex(String kind) {\r
485         final String[] tagKinds = {\r
486             "@internal", "@draft", "@stable", "@since", "@deprecated", "@author", "@see", "@version",\r
487             "@param", "@return", "@throws", "@obsolete", "@exception", "@serial"\r
488         };\r
489 \r
490         for (int i = 0; i < tagKinds.length; ++i) {\r
491             if (kind.equals(tagKinds[i])) {\r
492                 return i;\r
493             }\r
494         }\r
495         return UNKNOWN;\r
496     }\r
497 }\r