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