ConstantsSummaryBuilder.java revision 3294:9adfb22ff08f
1/*
2 * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package jdk.javadoc.internal.doclets.toolkit.builders;
27
28import java.io.*;
29import java.util.*;
30
31import javax.lang.model.element.Element;
32import javax.lang.model.element.PackageElement;
33import javax.lang.model.element.TypeElement;
34import javax.lang.model.element.VariableElement;
35
36import jdk.javadoc.internal.doclets.toolkit.ConstantsSummaryWriter;
37import jdk.javadoc.internal.doclets.toolkit.Content;
38import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberMap;
39
40
41/**
42 * Builds the Constants Summary Page.
43 *
44 *  <p><b>This is NOT part of any supported API.
45 *  If you write code that depends on this, you do so at your own risk.
46 *  This code and its internal interfaces are subject to change or
47 *  deletion without notice.</b>
48 *
49 * @author Jamie Ho
50 * @author Bhavesh Patel (Modified)
51 */
52public class ConstantsSummaryBuilder extends AbstractBuilder {
53
54    /**
55     * The root element of the constant summary XML is {@value}.
56     */
57    public static final String ROOT = "ConstantSummary";
58
59    /**
60     * The maximum number of package directories shown in the constant
61     * value index.
62     */
63    public static final int MAX_CONSTANT_VALUE_INDEX_LENGTH = 2;
64
65    /**
66     * The writer used to write the results.
67     */
68    protected final ConstantsSummaryWriter writer;
69
70    /**
71     * The set of TypeElements that have constant fields.
72     */
73    protected final Set<TypeElement> typeElementsWithConstFields;
74
75    /**
76     * The set of printed package headers.
77     */
78    protected final Set<PackageElement> printedPackageHeaders;
79
80    /**
81     * The current package being documented.
82     */
83    private PackageElement currentPackage;
84
85    /**
86     * The current class being documented.
87     */
88    private TypeElement currentClass;
89
90    /**
91     * The content tree for the constant summary documentation.
92     */
93    private Content contentTree;
94
95    /**
96     * True if first package is listed.
97     */
98    private boolean first = true;
99
100    /**
101     * Construct a new ConstantsSummaryBuilder.
102     *
103     * @param context       the build context.
104     * @param writer        the writer for the summary.
105     */
106    private ConstantsSummaryBuilder(Context context,
107            ConstantsSummaryWriter writer) {
108        super(context);
109        this.writer = writer;
110        this.typeElementsWithConstFields = new HashSet<>();
111        this.printedPackageHeaders = new TreeSet<>(utils.makePackageComparator());
112    }
113
114    /**
115     * Construct a ConstantsSummaryBuilder.
116     *
117     * @param context       the build context.
118     * @param writer        the writer for the summary.
119     */
120    public static ConstantsSummaryBuilder getInstance(Context context,
121            ConstantsSummaryWriter writer) {
122        return new ConstantsSummaryBuilder(context, writer);
123    }
124
125    /**
126     * {@inheritDoc}
127     */
128    @Override
129    public void build() throws IOException {
130        if (writer == null) {
131            //Doclet does not support this output.
132            return;
133        }
134        build(layoutParser.parseXML(ROOT), contentTree);
135    }
136
137    /**
138     * {@inheritDoc}
139     */
140    @Override
141    public String getName() {
142        return ROOT;
143    }
144
145    /**
146     * Build the constant summary.
147     *
148     * @param node the XML element that specifies which components to document
149     * @param contentTree the content tree to which the documentation will be added
150     */
151    public void buildConstantSummary(XMLNode node, Content contentTree) throws Exception {
152        contentTree = writer.getHeader();
153        buildChildren(node, contentTree);
154        writer.addFooter(contentTree);
155        writer.printDocument(contentTree);
156        writer.close();
157    }
158
159    /**
160     * Build the list of packages.
161     *
162     * @param node the XML element that specifies which components to document
163     * @param contentTree the content tree to which the content list will be added
164     */
165    public void buildContents(XMLNode node, Content contentTree) {
166        Content contentListTree = writer.getContentsHeader();
167        printedPackageHeaders.clear();
168        for (PackageElement pkg : configuration.packages) {
169            if (hasConstantField(pkg) && !hasPrintedPackageIndex(pkg)) {
170                writer.addLinkToPackageContent(pkg, printedPackageHeaders, contentListTree);
171            }
172        }
173        writer.addContentsList(contentTree, contentListTree);
174    }
175
176    /**
177     * Build the summary for each documented package.
178     *
179     * @param node the XML element that specifies which components to document
180     * @param contentTree the tree to which the summaries will be added
181     */
182    public void buildConstantSummaries(XMLNode node, Content contentTree) {
183        printedPackageHeaders.clear();
184        Content summariesTree = writer.getConstantSummaries();
185        for (PackageElement aPackage : configuration.packages) {
186            if (hasConstantField(aPackage)) {
187                currentPackage = aPackage;
188                //Build the documentation for the current package.
189                buildChildren(node, summariesTree);
190                first = false;
191            }
192        }
193        writer.addConstantSummaries(contentTree, summariesTree);
194    }
195
196    /**
197     * Build the header for the given package.
198     *
199     * @param node the XML element that specifies which components to document
200     * @param summariesTree the tree to which the package header will be added
201     */
202    public void buildPackageHeader(XMLNode node, Content summariesTree) {
203        PackageElement abbrevPkg = configuration.workArounds.getAbbreviatedPackageElement(currentPackage);
204        if (!printedPackageHeaders.contains(abbrevPkg)) {
205            writer.addPackageName(currentPackage, summariesTree, first);
206            printedPackageHeaders.add(abbrevPkg);
207        }
208    }
209
210    /**
211     * Build the summary for the current class.
212     *
213     * @param node the XML element that specifies which components to document
214     * @param summariesTree the tree to which the class constant summary will be added
215     */
216    public void buildClassConstantSummary(XMLNode node, Content summariesTree) {
217        SortedSet<TypeElement> classes = !currentPackage.isUnnamed()
218                ? utils.getAllClasses(currentPackage)
219                : configuration.typeElementCatalog.allUnnamedClasses();
220        Content classConstantTree = writer.getClassConstantHeader();
221        for (TypeElement te : classes) {
222            if (!typeElementsWithConstFields.contains(te) ||
223                !utils.isIncluded(te)) {
224                continue;
225            }
226            currentClass = te;
227            //Build the documentation for the current class.
228            buildChildren(node, classConstantTree);
229        }
230        writer.addClassConstant(summariesTree, classConstantTree);
231    }
232
233    /**
234     * Build the summary of constant members in the class.
235     *
236     * @param node the XML element that specifies which components to document
237     * @param classConstantTree the tree to which the constant members table
238     *                          will be added
239     */
240    public void buildConstantMembers(XMLNode node, Content classConstantTree) {
241        new ConstantFieldBuilder(currentClass).buildMembersSummary(node, classConstantTree);
242    }
243
244    /**
245     * Return true if the given package has constant fields to document.
246     *
247     * @param pkg   the package being checked.
248     * @return true if the given package has constant fields to document.
249     */
250    private boolean hasConstantField(PackageElement pkg) {
251        SortedSet<TypeElement> classes = !pkg.isUnnamed()
252                  ? utils.getAllClasses(pkg)
253                  : configuration.typeElementCatalog.allUnnamedClasses();
254        boolean found = false;
255        for (TypeElement te : classes) {
256            if (utils.isIncluded(te) && hasConstantField(te)) {
257                found = true;
258            }
259        }
260        return found;
261    }
262
263    /**
264     * Return true if the given class has constant fields to document.
265     *
266     * @param typeElement the class being checked.
267     * @return true if the given package has constant fields to document.
268     */
269    private boolean hasConstantField (TypeElement typeElement) {
270        VisibleMemberMap visibleMemberMapFields = new VisibleMemberMap(typeElement,
271            VisibleMemberMap.Kind.FIELDS, configuration);
272        SortedSet<Element> fields = visibleMemberMapFields.getLeafClassMembers();
273        for (Element f : fields) {
274            VariableElement field = (VariableElement)f;
275            if (field.getConstantValue() != null) {
276                typeElementsWithConstFields.add(typeElement);
277                return true;
278            }
279        }
280        return false;
281    }
282
283    /**
284     * Return true if the given package name has been printed.  Also
285     * return true if the root of this package has been printed.
286     *
287     * @param pkgname the name of the package to check.
288     */
289    private boolean hasPrintedPackageIndex(PackageElement pkg) {
290        for (PackageElement printedPkg : printedPackageHeaders) {
291            if (utils.getPackageName(pkg).startsWith(utils.parsePackageName(printedPkg))) {
292                return true;
293            }
294        }
295        return false;
296    }
297
298    /**
299     * Print the table of constants.
300     *
301     * @author Jamie Ho
302     */
303    private class ConstantFieldBuilder {
304
305        /**
306         * The map used to get the visible variables.
307         */
308        protected VisibleMemberMap visibleMemberMapFields = null;
309
310        /**
311         * The map used to get the visible variables.
312         */
313        protected VisibleMemberMap visibleMemberMapEnumConst = null;
314
315        /**
316         * The typeElement that we are examining constants for.
317         */
318        protected TypeElement typeElement;
319
320        /**
321         * Construct a ConstantFieldSubWriter.
322         * @param typeElement the typeElement that we are examining constants for.
323         */
324        public ConstantFieldBuilder(TypeElement typeElement) {
325            this.typeElement = typeElement;
326            visibleMemberMapFields = new VisibleMemberMap(typeElement,
327                VisibleMemberMap.Kind.FIELDS, configuration);
328            visibleMemberMapEnumConst = new VisibleMemberMap(typeElement,
329                VisibleMemberMap.Kind.ENUM_CONSTANTS, configuration);
330        }
331
332        /**
333         * Builds the table of constants for a given class.
334         *
335         * @param node the XML element that specifies which components to document
336         * @param classConstantTree the tree to which the class constants table
337         *                          will be added
338         */
339        protected void buildMembersSummary(XMLNode node, Content classConstantTree) {
340            SortedSet<VariableElement> members = members();
341            if (!members.isEmpty()) {
342                writer.addConstantMembers(typeElement, members, classConstantTree);
343            }
344        }
345
346        /**
347         * Return the list of visible constant fields for the given TypeElement.
348         * @return the list of visible constant fields for the given TypeElement.
349         */
350        protected SortedSet<VariableElement> members() {
351            SortedSet<Element> list = visibleMemberMapFields.getLeafClassMembers();
352            list.addAll(visibleMemberMapEnumConst.getLeafClassMembers());
353            SortedSet<VariableElement> inclList =
354                    new TreeSet<>(utils.makeGeneralPurposeComparator());
355            for (Element element : list) {
356                VariableElement member = (VariableElement)element;
357                if (member.getConstantValue() != null) {
358                    inclList.add(member);
359                }
360            }
361            return inclList;
362        }
363    }
364}
365