]> gitweb.fperrin.net Git - Dictionary.git/blob - jars/icu4j-4_4_2-src/tools/build/src/com/ibm/icu/dev/tool/docs/APIInfo.java
go
[Dictionary.git] / jars / icu4j-4_4_2-src / tools / build / src / com / ibm / icu / dev / tool / docs / APIInfo.java
1 /**\r
2  *******************************************************************************\r
3  * Copyright (C) 2005-2010, International Business Machines Corporation and    *\r
4  * others. All Rights Reserved.                                                *\r
5  *******************************************************************************\r
6  */\r
7 \r
8 /**\r
9  * Represents the API information on a doc element.\r
10  */\r
11 \r
12 package com.ibm.icu.dev.tool.docs;\r
13 \r
14 import java.io.BufferedReader;\r
15 import java.io.BufferedWriter;\r
16 import java.io.IOException;\r
17 import java.io.PrintWriter;\r
18 import java.util.Comparator;\r
19 \r
20 class APIInfo {\r
21     // version id for the format of the APIInfo data\r
22 \r
23     public static final int VERSION = 2;\r
24 \r
25     // public keys and values for queries on info\r
26 \r
27     public static final int STA = 0, STA_DRAFT = 0, STA_STABLE = 1, STA_DEPRECATED = 2,\r
28       STA_OBSOLETE = 3, STA_INTERNAL = 4;\r
29     public static final int VIS = 1, VIS_PACKAGE = 0, VIS_PUBLIC= 1, VIS_PROTECTED = 2,\r
30       VIS_PRIVATE = 3;\r
31     public static final int STK = 2, STK_STATIC = 1;\r
32     public static final int FIN = 3, FIN_FINAL = 1;\r
33     public static final int SYN = 4, SYN_SYNCHRONIZED = 1;\r
34     public static final int ABS = 5, ABS_ABSTRACT = 1;\r
35     public static final int CAT = 6, CAT_CLASS = 0, CAT_FIELD = 1, CAT_CONSTRUCTOR = 2,\r
36       CAT_METHOD = 3;\r
37     public static final int PAK = 7;\r
38     public static final int CLS = 8;\r
39     public static final int NAM = 9;\r
40     public static final int SIG = 10;\r
41     public static final int EXC = 11;\r
42     public static final int NUM_TYPES = 11;\r
43 \r
44     // the separator between tokens in the data file\r
45     public int[] masks = { 0x7, 0x3, 0x1, 0x1, 0x1, 0x1, 0x3 };\r
46     public int[] shifts = { 0, 3, 5, 6, 7, 8, 9 };\r
47 \r
48     public static final char SEP = ';';\r
49 \r
50     // Internal State\r
51 \r
52     private int    info;       // information about numeric values packed into an int\r
53                                // as variable-length nibbles\r
54     private String pack = "";  // package\r
55     private String cls  = "";  // enclosing class\r
56     private String name = "";  // name\r
57     private String sig  = "";  // signature, class: inheritance, method: signature,\r
58                                // field: type, const: signature\r
59     private String exc  = "";  // throws\r
60     private String stver = ""; // status version\r
61 \r
62     private boolean includeStatusVer = false;\r
63 \r
64     public int hashCode() {\r
65         return (((pack.hashCode() << 3) ^ cls.hashCode()) << 3) ^ name.hashCode();\r
66     }\r
67 \r
68     public boolean equals(Object rhs) {\r
69         if (rhs == this) return true;\r
70         if (rhs == null) return false;\r
71         try {\r
72             APIInfo that = (APIInfo)rhs;\r
73             return this.info == that.info &&\r
74                 this.pack.equals(that.pack) &&\r
75                 this.cls.equals(that.cls) &&\r
76                 this.name.equals(that.name) &&\r
77                 this.sig.equals(that.sig) &&\r
78                 this.exc.equals(that.exc) &&\r
79                 this.stver.equals(this.stver);\r
80         }\r
81         catch (ClassCastException e) {\r
82             return false;\r
83         }\r
84     }\r
85 \r
86     public void setDraft() { setType(STA, STA_DRAFT); }\r
87     public void setStable() { setType(STA, STA_STABLE); }\r
88     public void setDeprecated() { setType(STA, STA_DEPRECATED); }\r
89     public void setObsolete() { setType(STA, STA_OBSOLETE); }\r
90     public void setInternal() { setType(STA, STA_INTERNAL); }\r
91     public void setPackage() { setType(VIS, VIS_PACKAGE); }\r
92     public void setPublic() { setType(VIS, VIS_PUBLIC); }\r
93     public void setProtected() { setType(VIS, VIS_PROTECTED); }\r
94     public void setPrivate() { setType(VIS, VIS_PRIVATE); }\r
95     public void setStatic() { setType(STK, STK_STATIC); }\r
96     public void setFinal() { setType(FIN, FIN_FINAL); }\r
97     public void setSynchronized() { setType(SYN, SYN_SYNCHRONIZED); }\r
98     public void setAbstract() { setType(ABS, ABS_ABSTRACT); }\r
99     public void setClass() { setType(CAT, CAT_CLASS); }\r
100     public void setField() { setType(CAT, CAT_FIELD); }\r
101     public void setConstructor() { setType(CAT, CAT_CONSTRUCTOR); }\r
102     public void setMethod() { setType(CAT, CAT_METHOD); }\r
103 \r
104     public void setPackage(String val) { setType(PAK, val); }\r
105     public void setClassName(String val) { setType(CLS, val); }\r
106     public void setName(String val) { setType(NAM, val); }\r
107     public void setSignature(String val) { setType(SIG, val); }\r
108     public void setExceptions(String val) { setType(EXC, val); }\r
109 \r
110     public boolean isDraft() { return getVal(STA) == STA_DRAFT; }\r
111     public boolean isStable() { return getVal(STA) == STA_STABLE; }\r
112     public boolean isDeprecated() { return getVal(STA) == STA_DEPRECATED; }\r
113     public boolean isObsolete() { return getVal(STA) == STA_OBSOLETE; }\r
114     public boolean isInternal() { return getVal(STA) == STA_INTERNAL; }\r
115     public boolean isPackage() { return getVal(VIS) == VIS_PACKAGE; }\r
116     public boolean isPublic() { return getVal(VIS) == VIS_PUBLIC; }\r
117     public boolean isProtected() { return getVal(VIS) == VIS_PROTECTED; }\r
118     public boolean isPrivate() { return getVal(VIS) == VIS_PRIVATE; }\r
119     public boolean isStatic() { return getVal(STK) == STK_STATIC; }\r
120     public boolean isFinal() { return getVal(FIN) == FIN_FINAL; }\r
121     public boolean isSynchronized() { return getVal(SYN) == SYN_SYNCHRONIZED; }\r
122     public boolean isAbstract() { return getVal(ABS) == ABS_ABSTRACT; }\r
123     public boolean isClass() { return getVal(CAT) == CAT_CLASS; }\r
124     public boolean isField() { return getVal(CAT) == CAT_FIELD; }\r
125     public boolean isConstructor() { return getVal(CAT) == CAT_CONSTRUCTOR; }\r
126     public boolean isMethod() { return getVal(CAT) == CAT_METHOD; }\r
127 \r
128     public String getPackageName() { return get(PAK, true); }\r
129     public String getClassName() { return get(CLS, true); }\r
130     public String getName() { return get(NAM, true); }\r
131     public String getSignature() { return get(SIG, true); }\r
132     public String getExceptions() { return get(EXC, true); }\r
133 \r
134     public void setStatusVersion(String v) { stver = v; }\r
135     public String getStatusVersion() { return stver; }\r
136 \r
137     /**\r
138      * Return the integer value for the provided type.  The type\r
139      * must be one of the defined type names.  The return value\r
140      * will be one of corresponding values for that type.\r
141      */\r
142     public int getVal(int typ) {\r
143         validateType(typ);\r
144         if (typ >= shifts.length) {\r
145             return 0;\r
146         }\r
147         return (info >>> shifts[typ]) & masks[typ];\r
148     }\r
149 \r
150     /**\r
151      * Return the string value for the provided type.  The type\r
152      * must be one of the defined type names.  The return value\r
153      * will be one of corresponding values for that type.  Brief\r
154      * should be true for writing data files, false for presenting\r
155      * information to the user.\r
156      */\r
157     public String get(int typ, boolean brief) {\r
158         validateType(typ);\r
159         String[] vals = brief ? shortNames[typ] : names[typ];\r
160         if (vals == null) {\r
161             switch (typ) {\r
162             case PAK: return pack;\r
163             case CLS: return cls;\r
164             case NAM: return name;\r
165             case SIG: return sig;\r
166             case EXC: return exc;\r
167             }\r
168         }\r
169         int val = (info >>> shifts[typ]) & masks[typ];\r
170         return vals[val];\r
171     }\r
172 \r
173     /**\r
174      * Set the numeric value for the type.  The value should be a\r
175      * value corresponding to the type.  Only the lower two bits\r
176      * of the value are used.\r
177      */\r
178     public void setType(int typ, int val) {\r
179         validateType(typ);\r
180         if (typ < masks.length) {\r
181             info &= ~(masks[typ] << shifts[typ]);\r
182             info |= (val&masks[typ]) << shifts[typ];\r
183         }\r
184     }\r
185 \r
186     /**\r
187      * Set the string value for the type.  For numeric types,\r
188      * the value should be a string in 'brief' format.  For\r
189      * non-numeric types, the value can be any\r
190      * string.\r
191      */\r
192     private void setType(int typ, String val) {\r
193         validateType(typ);\r
194         String[] vals = shortNames[typ];\r
195         if (vals == null) {\r
196             if (val == null) {\r
197                 val = "";\r
198             }\r
199             switch (typ) {\r
200             case PAK: pack = val; break;\r
201             case CLS: cls = val; break;\r
202             case NAM: name = val; break;\r
203             case SIG: sig = val; break;\r
204             case EXC: exc = val; break;\r
205             }\r
206             return;\r
207         }\r
208 \r
209         for (int i = 0; i < vals.length; ++i) {\r
210             if (val.equalsIgnoreCase(vals[i])) {\r
211                 info &= ~(masks[typ] << shifts[typ]);\r
212                 info |= i << shifts[typ];\r
213                 return;\r
214             }\r
215         }\r
216 \r
217         throw new IllegalArgumentException(\r
218             "unrecognized value '" + val + "' for type '" + typeNames[typ] + "'");\r
219     }\r
220 \r
221     /**\r
222      * Enable status version included in input/output\r
223      */\r
224     public void includeStatusVersion(boolean include) {\r
225         includeStatusVer = include;\r
226     }\r
227 \r
228     /**\r
229      * Write the information out as a single line in brief format.\r
230      * If there are IO errors, throws a RuntimeException.\r
231      */\r
232     public void writeln(BufferedWriter w) {\r
233         try {\r
234             for (int i = 0; i < NUM_TYPES; ++i) {\r
235                 String s = get(i, true);\r
236                 if (s != null) {\r
237                     w.write(s);\r
238                 }\r
239                 if (includeStatusVer && i == STA) {\r
240                     String ver = getStatusVersion();\r
241                     if (ver.length() > 0) {\r
242                         w.write("@");\r
243                         w.write(getStatusVersion());\r
244                     }\r
245                 }\r
246                 w.write(SEP);\r
247             }\r
248             w.newLine();\r
249         }\r
250         catch (IOException e) {\r
251             RuntimeException re = new RuntimeException("IO Error");\r
252             re.initCause(e);\r
253             throw re;\r
254         }\r
255     }\r
256 \r
257     /**\r
258      * Read a record from the input and initialize this APIInfo.\r
259      * Return true if successful, false if EOF, otherwise throw\r
260      * a RuntimeException.\r
261      */\r
262     public boolean read(BufferedReader r) {\r
263         int i = 0;\r
264         try {\r
265             for (; i < NUM_TYPES; ++i) {\r
266                 setType(i, readToken(r));\r
267             }\r
268             r.readLine(); // swallow line end sequence\r
269         }\r
270         catch (IOException e) {\r
271             if (i == 0) { // assume if first read returns error, we have reached end of input\r
272                 return false;\r
273             }\r
274             RuntimeException re = new RuntimeException("IO Error");\r
275             re.initCause(e);\r
276             throw re;\r
277         }\r
278 \r
279         return true;\r
280     }\r
281 \r
282     /**\r
283      * Read one token from input, which should have been written by\r
284      * APIInfo.  Throws IOException if EOF is encountered before the\r
285      * token is complete (i.e. before the separator character is\r
286      * encountered) or if the token exceeds the maximum length of\r
287      * 255 chars.\r
288      */\r
289     public static String readToken(BufferedReader r) throws IOException {\r
290         char[] buf = new char[256];\r
291         int i = 0;\r
292         for (; i < buf.length; ++i) {\r
293             int c = r.read();\r
294             if (c == -1) {\r
295                 throw new IOException("unexpected EOF");\r
296             } else if (c == SEP) {\r
297                 break;\r
298             }\r
299             buf[i] = (char)c;\r
300         }\r
301         if (i == buf.length) {\r
302             throw new IOException("unterminated token" + new String(buf));\r
303         }\r
304 \r
305         return new String(buf, 0, i);\r
306     }\r
307 \r
308     /**\r
309      * The default comparator for APIInfo.  This compares packages, class/name\r
310      * (as the info represents a class or other object), category, name,\r
311      * and signature.\r
312      */\r
313     public static Comparator defaultComparator() {\r
314         final Comparator c = new Comparator() {\r
315                 public int compare(Object lhs, Object rhs) {\r
316                     APIInfo lhi = (APIInfo)lhs;\r
317                     APIInfo rhi = (APIInfo)rhs;\r
318                     int result = lhi.pack.compareTo(rhi.pack);\r
319                     if (result == 0) {\r
320                         result = (lhi.getVal(CAT) == CAT_CLASS ? lhi.name : lhi.cls)\r
321                             .compareTo(rhi.getVal(CAT) == CAT_CLASS ? rhi.name : rhi.cls);\r
322                         if (result == 0) {\r
323                             result = lhi.getVal(CAT)- rhi.getVal(CAT);\r
324                             if (result == 0) {\r
325                                 result = lhi.name.compareTo(rhi.name);\r
326                                 if (result == 0) {\r
327                                     result = lhi.sig.compareTo(rhi.sig);\r
328                                 }\r
329                             }\r
330                         }\r
331                     }\r
332                     return result;\r
333                 }\r
334             };\r
335         return c;\r
336     }\r
337 \r
338     /**\r
339      * This compares two APIInfos by package, class/name, category, name, and then if\r
340      * the APIInfo does not represent a class, by signature.  The difference between\r
341      * this and the default comparator is that APIInfos representing classes are considered\r
342      * equal regardless of their signatures (which represent inheritance for classes).\r
343      */\r
344     public static Comparator changedComparator() {\r
345         final Comparator c = new Comparator() {\r
346                 public int compare(Object lhs, Object rhs) {\r
347                     APIInfo lhi = (APIInfo)lhs;\r
348                     APIInfo rhi = (APIInfo)rhs;\r
349                     int result = lhi.pack.compareTo(rhi.pack);\r
350                     if (result == 0) {\r
351                         result = (lhi.getVal(CAT) == CAT_CLASS ? lhi.name : lhi.cls)\r
352                             .compareTo(rhi.getVal(CAT) == CAT_CLASS ? rhi.name : rhi.cls);\r
353                         if (result == 0) {\r
354                             result = lhi.getVal(CAT)- rhi.getVal(CAT);\r
355                             if (result == 0) {\r
356                                 result = lhi.name.compareTo(rhi.name);\r
357                                 if (result == 0 && lhi.getVal(CAT) != CAT_CLASS) {\r
358                                     // signature change on fields ignored\r
359                                     if (lhi.getVal(CAT) != CAT_FIELD) {\r
360                                         result = lhi.sig.compareTo(rhi.sig);\r
361                                     }\r
362                                 }\r
363                             }\r
364                         }\r
365                     }\r
366                     return result;\r
367                 }\r
368             };\r
369         return c;\r
370     }\r
371 \r
372     /**\r
373      * This compares two APIInfos by package, then sorts classes before non-classes, then\r
374      * by class/name, category, name, and signature.\r
375      */\r
376     public static Comparator classFirstComparator() {\r
377         final Comparator c = new Comparator() {\r
378                 public int compare(Object lhs, Object rhs) {\r
379                     APIInfo lhi = (APIInfo)lhs;\r
380                     APIInfo rhi = (APIInfo)rhs;\r
381                     int result = lhi.pack.compareTo(rhi.pack);\r
382                     if (result == 0) {\r
383                         boolean lcls = lhi.getVal(CAT) == CAT_CLASS;\r
384                         boolean rcls = rhi.getVal(CAT) == CAT_CLASS;\r
385                         result = lcls == rcls ? 0 : (lcls ? -1 : 1);\r
386                         if (result == 0) {\r
387                             result = (lcls ? lhi.name : lhi.cls).compareTo(\r
388                                 rcls ? rhi.name : rhi.cls);\r
389                             if (result == 0) {\r
390                                 result = lhi.getVal(CAT)- rhi.getVal(CAT);\r
391                                 if (result == 0) {\r
392                                     result = lhi.name.compareTo(rhi.name);\r
393                                     if (result == 0 && !lcls) {\r
394                                         result = lhi.sig.compareTo(rhi.sig);\r
395                                     }\r
396                                 }\r
397                             }\r
398                         }\r
399                     }\r
400                     return result;\r
401                 }\r
402             };\r
403         return c;\r
404     }\r
405 \r
406     /**\r
407      * Write the data in report format.\r
408      */\r
409     public void print(PrintWriter pw, boolean detail, boolean html) {\r
410         StringBuffer buf = new StringBuffer();\r
411 \r
412         // remove all occurrences of icu packages from the param string\r
413         // fortunately, all the packages have 4 chars (lang, math, text, util).\r
414         String xsig = sig;\r
415         if (!detail) {\r
416             final String ICUPACK = "com.ibm.icu.";\r
417             StringBuffer tbuf = new StringBuffer();\r
418             for (int i = 0; i < sig.length();) {\r
419                 int n = sig.indexOf(ICUPACK, i);\r
420                 if (n == -1) {\r
421                     tbuf.append(sig.substring(i));\r
422                     break;\r
423                 }\r
424                 tbuf.append(sig.substring(i, n));\r
425                 i = n + ICUPACK.length() + 5; // trailing 'xxxx.'\r
426             }\r
427             xsig = tbuf.toString();\r
428         }\r
429 \r
430         // construct signature\r
431         for (int i = STA; i < CAT; ++i) { // include status\r
432             String s = get(i, false);\r
433             if (s != null && s.length() > 0) {\r
434                 if (html && s.indexOf("internal") != -1) {\r
435                     buf.append("<span style='color:red'>");\r
436                     buf.append(s);\r
437                     buf.append("</span>");\r
438                 } else {\r
439                     buf.append(s);\r
440                     buf.append(' ');\r
441                 }\r
442             }\r
443         }\r
444 \r
445         int val = getVal(CAT);\r
446         switch (val) {\r
447         case CAT_CLASS:\r
448             if (sig.indexOf("extends") == -1) {\r
449                 buf.append("interface ");\r
450             } else {\r
451                 buf.append("class ");\r
452             }\r
453         if (html) {\r
454         buf.append("<i>");\r
455         }\r
456             if (cls.length() > 0) {\r
457                 buf.append(cls);\r
458                 buf.append('.');\r
459             }\r
460             buf.append(name);\r
461         if (html) {\r
462         buf.append("</i>");\r
463         }\r
464             if (detail) {\r
465                 buf.append(' ');\r
466                 buf.append(sig);\r
467             }\r
468             break;\r
469 \r
470         case CAT_FIELD:\r
471             buf.append(xsig);\r
472             buf.append(' ');\r
473             buf.append(name);\r
474             break;\r
475 \r
476         case CAT_METHOD:\r
477         case CAT_CONSTRUCTOR:\r
478             int n = xsig.indexOf('(');\r
479             if (n > 0) {\r
480                 buf.append(xsig.substring(0, n));\r
481                 buf.append(' ');\r
482             } else {\r
483                 n = 0;\r
484             }\r
485         if (html) {\r
486         buf.append("<i>" + name + "</i>");\r
487         } else {\r
488         buf.append(name);\r
489         }\r
490             buf.append(xsig.substring(n));\r
491             break;\r
492         }\r
493 \r
494         pw.print(buf.toString());\r
495     }\r
496 \r
497     public void println(PrintWriter pw, boolean detail, boolean html) {\r
498         print(pw, detail, html);\r
499         pw.println();\r
500     }\r
501 \r
502     private static final String[] typeNames = {\r
503         "status", "visibility", "static", "final", "synchronized",\r
504         "abstract", "category", "package", "class", "name", "signature"\r
505     };\r
506 \r
507     public static final String getTypeValName(int typ, int val) {\r
508         try {\r
509             return names[typ][val];\r
510         }\r
511         catch (Exception e) {\r
512             return "";\r
513         }\r
514     }\r
515 \r
516     private static final String[][] names = {\r
517         { "(draft)     ", "(stable)    ", "(deprecated)", "(obsolete)  ", "*internal*  " },\r
518         { "package", "public", "protected", "private" },\r
519         { "", "static" },\r
520         { "", "final" },\r
521         { "", "synchronized" },\r
522         { "", "abstract" },\r
523         { "class", "field", "constructor", "method"  },\r
524         null,\r
525         null,\r
526         null,\r
527         null,\r
528         null\r
529     };\r
530 \r
531     private static final String[][] shortNames = {\r
532         { "DR", "ST", "DP", "OB", "IN" },\r
533         { "PK", "PB", "PT", "PR" },\r
534         { "NS", "ST" },\r
535         { "NF", "FN" },\r
536         { "NS", "SY" },\r
537         { "NA", "AB" },\r
538         { "L", "F", "C", "M" },\r
539         null,\r
540         null,\r
541         null,\r
542         null,\r
543         null\r
544     };\r
545 \r
546     private static void validateType(int typ) {\r
547         if (typ < 0 || typ > NUM_TYPES) {\r
548             throw new IllegalArgumentException("bad type index: " + typ);\r
549         }\r
550     }\r
551 \r
552     public String toString() {\r
553         return get(NAM, true);\r
554     }\r
555 }\r