~ubuntu-branches/ubuntu/vivid/icu4j-4.4/vivid

« back to all changes in this revision

Viewing changes to tools/build/src/com/ibm/icu/dev/tool/docs/APIInfo.java

  • Committer: Bazaar Package Importer
  • Author(s): Niels Thykier
  • Date: 2011-08-02 15:50:33 UTC
  • Revision ID: james.westby@ubuntu.com-20110802155033-itjzsl21y2lqdonn
Tags: upstream-4.4.2
ImportĀ upstreamĀ versionĀ 4.4.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/**
 
2
 *******************************************************************************
 
3
 * Copyright (C) 2005-2010, 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
        for (int i = 0; i < vals.length; ++i) {
 
210
            if (val.equalsIgnoreCase(vals[i])) {
 
211
                info &= ~(masks[typ] << shifts[typ]);
 
212
                info |= i << shifts[typ];
 
213
                return;
 
214
            }
 
215
        }
 
216
 
 
217
        throw new IllegalArgumentException(
 
218
            "unrecognized value '" + val + "' for type '" + typeNames[typ] + "'");
 
219
    }
 
220
 
 
221
    /**
 
222
     * Enable status version included in input/output
 
223
     */
 
224
    public void includeStatusVersion(boolean include) {
 
225
        includeStatusVer = include;
 
226
    }
 
227
 
 
228
    /**
 
229
     * Write the information out as a single line in brief format.
 
230
     * If there are IO errors, throws a RuntimeException.
 
231
     */
 
232
    public void writeln(BufferedWriter w) {
 
233
        try {
 
234
            for (int i = 0; i < NUM_TYPES; ++i) {
 
235
                String s = get(i, true);
 
236
                if (s != null) {
 
237
                    w.write(s);
 
238
                }
 
239
                if (includeStatusVer && i == STA) {
 
240
                    String ver = getStatusVersion();
 
241
                    if (ver.length() > 0) {
 
242
                        w.write("@");
 
243
                        w.write(getStatusVersion());
 
244
                    }
 
245
                }
 
246
                w.write(SEP);
 
247
            }
 
248
            w.newLine();
 
249
        }
 
250
        catch (IOException e) {
 
251
            RuntimeException re = new RuntimeException("IO Error");
 
252
            re.initCause(e);
 
253
            throw re;
 
254
        }
 
255
    }
 
256
 
 
257
    /**
 
258
     * Read a record from the input and initialize this APIInfo.
 
259
     * Return true if successful, false if EOF, otherwise throw
 
260
     * a RuntimeException.
 
261
     */
 
262
    public boolean read(BufferedReader r) {
 
263
        int i = 0;
 
264
        try {
 
265
            for (; i < NUM_TYPES; ++i) {
 
266
                setType(i, readToken(r));
 
267
            }
 
268
            r.readLine(); // swallow line end sequence
 
269
        }
 
270
        catch (IOException e) {
 
271
            if (i == 0) { // assume if first read returns error, we have reached end of input
 
272
                return false;
 
273
            }
 
274
            RuntimeException re = new RuntimeException("IO Error");
 
275
            re.initCause(e);
 
276
            throw re;
 
277
        }
 
278
 
 
279
        return true;
 
280
    }
 
281
 
 
282
    /**
 
283
     * Read one token from input, which should have been written by
 
284
     * APIInfo.  Throws IOException if EOF is encountered before the
 
285
     * token is complete (i.e. before the separator character is
 
286
     * encountered) or if the token exceeds the maximum length of
 
287
     * 255 chars.
 
288
     */
 
289
    public static String readToken(BufferedReader r) throws IOException {
 
290
        char[] buf = new char[256];
 
291
        int i = 0;
 
292
        for (; i < buf.length; ++i) {
 
293
            int c = r.read();
 
294
            if (c == -1) {
 
295
                throw new IOException("unexpected EOF");
 
296
            } else if (c == SEP) {
 
297
                break;
 
298
            }
 
299
            buf[i] = (char)c;
 
300
        }
 
301
        if (i == buf.length) {
 
302
            throw new IOException("unterminated token" + new String(buf));
 
303
        }
 
304
 
 
305
        return new String(buf, 0, i);
 
306
    }
 
307
 
 
308
    /**
 
309
     * The default comparator for APIInfo.  This compares packages, class/name
 
310
     * (as the info represents a class or other object), category, name,
 
311
     * and signature.
 
312
     */
 
313
    public static Comparator defaultComparator() {
 
314
        final Comparator c = new Comparator() {
 
315
                public int compare(Object lhs, Object rhs) {
 
316
                    APIInfo lhi = (APIInfo)lhs;
 
317
                    APIInfo rhi = (APIInfo)rhs;
 
318
                    int result = lhi.pack.compareTo(rhi.pack);
 
319
                    if (result == 0) {
 
320
                        result = (lhi.getVal(CAT) == CAT_CLASS ? lhi.name : lhi.cls)
 
321
                            .compareTo(rhi.getVal(CAT) == CAT_CLASS ? rhi.name : rhi.cls);
 
322
                        if (result == 0) {
 
323
                            result = lhi.getVal(CAT)- rhi.getVal(CAT);
 
324
                            if (result == 0) {
 
325
                                result = lhi.name.compareTo(rhi.name);
 
326
                                if (result == 0) {
 
327
                                    result = lhi.sig.compareTo(rhi.sig);
 
328
                                }
 
329
                            }
 
330
                        }
 
331
                    }
 
332
                    return result;
 
333
                }
 
334
            };
 
335
        return c;
 
336
    }
 
337
 
 
338
    /**
 
339
     * This compares two APIInfos by package, class/name, category, name, and then if
 
340
     * the APIInfo does not represent a class, by signature.  The difference between
 
341
     * this and the default comparator is that APIInfos representing classes are considered
 
342
     * equal regardless of their signatures (which represent inheritance for classes).
 
343
     */
 
344
    public static Comparator changedComparator() {
 
345
        final Comparator c = new Comparator() {
 
346
                public int compare(Object lhs, Object rhs) {
 
347
                    APIInfo lhi = (APIInfo)lhs;
 
348
                    APIInfo rhi = (APIInfo)rhs;
 
349
                    int result = lhi.pack.compareTo(rhi.pack);
 
350
                    if (result == 0) {
 
351
                        result = (lhi.getVal(CAT) == CAT_CLASS ? lhi.name : lhi.cls)
 
352
                            .compareTo(rhi.getVal(CAT) == CAT_CLASS ? rhi.name : rhi.cls);
 
353
                        if (result == 0) {
 
354
                            result = lhi.getVal(CAT)- rhi.getVal(CAT);
 
355
                            if (result == 0) {
 
356
                                result = lhi.name.compareTo(rhi.name);
 
357
                                if (result == 0 && lhi.getVal(CAT) != CAT_CLASS) {
 
358
                                    // signature change on fields ignored
 
359
                                    if (lhi.getVal(CAT) != CAT_FIELD) {
 
360
                                        result = lhi.sig.compareTo(rhi.sig);
 
361
                                    }
 
362
                                }
 
363
                            }
 
364
                        }
 
365
                    }
 
366
                    return result;
 
367
                }
 
368
            };
 
369
        return c;
 
370
    }
 
371
 
 
372
    /**
 
373
     * This compares two APIInfos by package, then sorts classes before non-classes, then
 
374
     * by class/name, category, name, and signature.
 
375
     */
 
376
    public static Comparator classFirstComparator() {
 
377
        final Comparator c = new Comparator() {
 
378
                public int compare(Object lhs, Object rhs) {
 
379
                    APIInfo lhi = (APIInfo)lhs;
 
380
                    APIInfo rhi = (APIInfo)rhs;
 
381
                    int result = lhi.pack.compareTo(rhi.pack);
 
382
                    if (result == 0) {
 
383
                        boolean lcls = lhi.getVal(CAT) == CAT_CLASS;
 
384
                        boolean rcls = rhi.getVal(CAT) == CAT_CLASS;
 
385
                        result = lcls == rcls ? 0 : (lcls ? -1 : 1);
 
386
                        if (result == 0) {
 
387
                            result = (lcls ? lhi.name : lhi.cls).compareTo(
 
388
                                rcls ? rhi.name : rhi.cls);
 
389
                            if (result == 0) {
 
390
                                result = lhi.getVal(CAT)- rhi.getVal(CAT);
 
391
                                if (result == 0) {
 
392
                                    result = lhi.name.compareTo(rhi.name);
 
393
                                    if (result == 0 && !lcls) {
 
394
                                        result = lhi.sig.compareTo(rhi.sig);
 
395
                                    }
 
396
                                }
 
397
                            }
 
398
                        }
 
399
                    }
 
400
                    return result;
 
401
                }
 
402
            };
 
403
        return c;
 
404
    }
 
405
 
 
406
    /**
 
407
     * Write the data in report format.
 
408
     */
 
409
    public void print(PrintWriter pw, boolean detail, boolean html) {
 
410
        StringBuffer buf = new StringBuffer();
 
411
 
 
412
        // remove all occurrences of icu packages from the param string
 
413
        // fortunately, all the packages have 4 chars (lang, math, text, util).
 
414
        String xsig = sig;
 
415
        if (!detail) {
 
416
            final String ICUPACK = "com.ibm.icu.";
 
417
            StringBuffer tbuf = new StringBuffer();
 
418
            for (int i = 0; i < sig.length();) {
 
419
                int n = sig.indexOf(ICUPACK, i);
 
420
                if (n == -1) {
 
421
                    tbuf.append(sig.substring(i));
 
422
                    break;
 
423
                }
 
424
                tbuf.append(sig.substring(i, n));
 
425
                i = n + ICUPACK.length() + 5; // trailing 'xxxx.'
 
426
            }
 
427
            xsig = tbuf.toString();
 
428
        }
 
429
 
 
430
        // construct signature
 
431
        for (int i = STA; i < CAT; ++i) { // include status
 
432
            String s = get(i, false);
 
433
            if (s != null && s.length() > 0) {
 
434
                if (html && s.indexOf("internal") != -1) {
 
435
                    buf.append("<span style='color:red'>");
 
436
                    buf.append(s);
 
437
                    buf.append("</span>");
 
438
                } else {
 
439
                    buf.append(s);
 
440
                    buf.append(' ');
 
441
                }
 
442
            }
 
443
        }
 
444
 
 
445
        int val = getVal(CAT);
 
446
        switch (val) {
 
447
        case CAT_CLASS:
 
448
            if (sig.indexOf("extends") == -1) {
 
449
                buf.append("interface ");
 
450
            } else {
 
451
                buf.append("class ");
 
452
            }
 
453
        if (html) {
 
454
        buf.append("<i>");
 
455
        }
 
456
            if (cls.length() > 0) {
 
457
                buf.append(cls);
 
458
                buf.append('.');
 
459
            }
 
460
            buf.append(name);
 
461
        if (html) {
 
462
        buf.append("</i>");
 
463
        }
 
464
            if (detail) {
 
465
                buf.append(' ');
 
466
                buf.append(sig);
 
467
            }
 
468
            break;
 
469
 
 
470
        case CAT_FIELD:
 
471
            buf.append(xsig);
 
472
            buf.append(' ');
 
473
            buf.append(name);
 
474
            break;
 
475
 
 
476
        case CAT_METHOD:
 
477
        case CAT_CONSTRUCTOR:
 
478
            int n = xsig.indexOf('(');
 
479
            if (n > 0) {
 
480
                buf.append(xsig.substring(0, n));
 
481
                buf.append(' ');
 
482
            } else {
 
483
                n = 0;
 
484
            }
 
485
        if (html) {
 
486
        buf.append("<i>" + name + "</i>");
 
487
        } else {
 
488
        buf.append(name);
 
489
        }
 
490
            buf.append(xsig.substring(n));
 
491
            break;
 
492
        }
 
493
 
 
494
        pw.print(buf.toString());
 
495
    }
 
496
 
 
497
    public void println(PrintWriter pw, boolean detail, boolean html) {
 
498
        print(pw, detail, html);
 
499
        pw.println();
 
500
    }
 
501
 
 
502
    private static final String[] typeNames = {
 
503
        "status", "visibility", "static", "final", "synchronized",
 
504
        "abstract", "category", "package", "class", "name", "signature"
 
505
    };
 
506
 
 
507
    public static final String getTypeValName(int typ, int val) {
 
508
        try {
 
509
            return names[typ][val];
 
510
        }
 
511
        catch (Exception e) {
 
512
            return "";
 
513
        }
 
514
    }
 
515
 
 
516
    private static final String[][] names = {
 
517
        { "(draft)     ", "(stable)    ", "(deprecated)", "(obsolete)  ", "*internal*  " },
 
518
        { "package", "public", "protected", "private" },
 
519
        { "", "static" },
 
520
        { "", "final" },
 
521
        { "", "synchronized" },
 
522
        { "", "abstract" },
 
523
        { "class", "field", "constructor", "method"  },
 
524
        null,
 
525
        null,
 
526
        null,
 
527
        null,
 
528
        null
 
529
    };
 
530
 
 
531
    private static final String[][] shortNames = {
 
532
        { "DR", "ST", "DP", "OB", "IN" },
 
533
        { "PK", "PB", "PT", "PR" },
 
534
        { "NS", "ST" },
 
535
        { "NF", "FN" },
 
536
        { "NS", "SY" },
 
537
        { "NA", "AB" },
 
538
        { "L", "F", "C", "M" },
 
539
        null,
 
540
        null,
 
541
        null,
 
542
        null,
 
543
        null
 
544
    };
 
545
 
 
546
    private static void validateType(int typ) {
 
547
        if (typ < 0 || typ > NUM_TYPES) {
 
548
            throw new IllegalArgumentException("bad type index: " + typ);
 
549
        }
 
550
    }
 
551
 
 
552
    public String toString() {
 
553
        return get(NAM, true);
 
554
    }
 
555
}