12d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert// © 2016 and later: Unicode, Inc. and others.
22d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert// License & terms of use: http://www.unicode.org/copyright.html#License
3bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert/**
4bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert*******************************************************************************
5bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert* Copyright (C) 2004-2015, International Business Machines Corporation and    *
6bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert* others. All Rights Reserved.                                                *
7bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert*******************************************************************************
8bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert*/
9bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
10bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert/**
11bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert * Represent a file of APIInfo records.
12bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert */
13bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
14bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubertpackage com.ibm.icu.dev.tool.docs;
15bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
16bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubertimport java.io.BufferedReader;
17bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubertimport java.io.File;
18bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubertimport java.io.FileInputStream;
19bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubertimport java.io.IOException;
20bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubertimport java.io.InputStream;
21bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubertimport java.io.InputStreamReader;
22bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubertimport java.io.PrintWriter;
23bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubertimport java.util.Collections;
24bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubertimport java.util.Enumeration;
25bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubertimport java.util.Iterator;
26bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubertimport java.util.Set;
27bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubertimport java.util.TreeSet;
28bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubertimport java.util.zip.GZIPInputStream;
29bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubertimport java.util.zip.ZipEntry;
30bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubertimport java.util.zip.ZipFile;
31bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
32bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubertpublic final class APIData {
33bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert    int version;
34bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert    String name;
35bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert    String base;
36bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert    TreeSet<APIInfo> set;
37bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
38bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert    static APIData read(BufferedReader br, boolean internal) {
39bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        try {
40bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            APIData data = new APIData();
41bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
42bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            data.version = Integer.parseInt(APIInfo.readToken(br)); // version
43bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            if (data.version > APIInfo.VERSION) {
44bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                throw new IllegalArgumentException(
45bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                    "data version " + data.version
46bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                    + " is newer than current version (" + APIInfo.VERSION + ")");
47bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            }
48bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            data.name = APIInfo.readToken(br);
49bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            data.base = APIInfo.readToken(br); // base
50bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            br.readLine();
51bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
52bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            data.set = new TreeSet(APIInfo.defaultComparator());
53bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            for (APIInfo info = new APIInfo(); info.read(br); info = new APIInfo()) {
54bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                if (internal || !info.isInternal()) {
55bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                    data.set.add(info);
56bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                }
57bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            }
58bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            // System.out.println("read " + data.set.size() + " record(s)");
59bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            return data;
60bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        }
61bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        catch (IOException e) {
62bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            RuntimeException re = new RuntimeException("error reading api data");
63bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            re.initCause(e);
64bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            throw re;
65bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        }
66bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert    }
67bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
68bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert    public static APIData read(File file, boolean internal) {
69bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        String fileName = file.getName();
70bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        ZipFile zf = null;
71bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        try {
72bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            InputStream is;
73bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            if (fileName.endsWith(".zip")) {
74bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                zf = new ZipFile(file);
75bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                Enumeration entryEnum = zf.entries();
76bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                if (entryEnum.hasMoreElements()) {
77bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                    ZipEntry entry = (ZipEntry)entryEnum.nextElement();
78bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                    is = zf.getInputStream(entry);
79bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                    // we only handle one!!!
80bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                } else {
81bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                    throw new IOException("zip file is empty");
82bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                }
83bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            } else {
84bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                is = new FileInputStream(file);
85bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                if (fileName.endsWith(".gz")) {
86bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                    is = new GZIPInputStream(is);
87bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                }
88bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            }
89bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            InputStreamReader isr = new InputStreamReader(is);
90bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            return read(new BufferedReader(isr), internal);
91bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        } catch (IOException e) {
92bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            RuntimeException re = new RuntimeException("error getting info stream: " + fileName);
93bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            re.initCause(e);
94bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            throw re;
95bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        } finally {
96bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            if (zf != null) {
97bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                try {
98bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                    zf.close();
99bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                } catch (IOException e) {
100bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                    RuntimeException re = new RuntimeException("failed to close the zip file: " + fileName);
101bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                    re.initCause(e);
102bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                    throw re;
103bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                }
104bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            }
105bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        }
106bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert    }
107bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
108bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert    static APIData read(String fileName, boolean internal) {
109bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        return read(new File(fileName), internal);
110bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert    }
111bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
112bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert    private static final String[] stanames = {
113bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        "draft", "stable", "deprecated", "obsolete", "internal"
114bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert    };
115bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert    private static final String[] catnames = {
116bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        "classes", "fields", "constructors", "methods"
117bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert    };
118bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
119bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert    public void printStats(PrintWriter pw) {
120bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        // classes, methods, fields
121bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        // draft, stable, other
122bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
123bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        int[] stats = new int[catnames.length * stanames.length];
124bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
125bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        Iterator iter = set.iterator();
126bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        while (iter.hasNext()) {
127bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            APIInfo info = (APIInfo)iter.next();
128bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
129bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            if (info.isPublic() || info.isProtected()) {
130bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                int sta = info.getVal(APIInfo.STA);
131bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                int cat = info.getVal(APIInfo.CAT);
132bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                stats[cat * stanames.length + sta] += 1;
133bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            }
134bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        }
135bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
136bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        int tt = 0;
137bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        for (int cat = 0; cat < catnames.length; ++cat) {
138bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            pw.println(catnames[cat]);
139bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            int t = 0;
140bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            for (int sta = 0; sta < stanames.length; ++sta) {
141bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                int v = stats[cat * stanames.length + sta];
142bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                t += v;
143bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                pw.println("   " + stanames[sta] + ": " + v);
144bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            }
145bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            tt += t;
146bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            pw.println("total: " + t);
147bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            pw.println();
148bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        }
149bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        pw.println("total apis: " + tt);
150bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert    }
151bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
152bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert    public Set<APIInfo> getAPIInfoSet() {
153bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        return Collections.unmodifiableSet(set);
154bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert    }
155bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
156bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert    public static void main(String[] args) {
157bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        PrintWriter pw = new PrintWriter(System.out);
158bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
159bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        boolean internal = false;
160bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        String path = "src/com/ibm/icu/dev/tool/docs/";
161bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
162bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        String fn = "icu4j52.api3.gz";
163bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        if (args.length == 0) {
164bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            args = new String[] { "-file", fn };
165bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        }
166bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
167bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        for (int i = 0; i < args.length; ++i) {
168bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            String arg = args[i];
169bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            if (arg.equals("-path:")) {
170bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                path = args[++i];
171bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            } else if (arg.equals("-internal:")) {
172bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                internal = args[++i].toLowerCase().charAt(0) == 't';
173bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            } else if (arg.equals("-file")) {
174bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                fn = args[++i];
175bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
176bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                File f = new File(path, fn);
177bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                read(f,internal).printStats(pw);
178bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                pw.flush();
179bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            }
180bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        }
181bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert    }
182bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert}
183