ConstantsSummaryBuilder.java revision 3233:b5d08bc0d224
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        String parsedPackageName = utils.parsePackageName(currentPackage);
204        PackageElement p = utils.elementUtils.getPackageElement(parsedPackageName);
205        if (!printedPackageHeaders.contains(p)) {
206            writer.addPackageName(currentPackage, summariesTree, first);
207            printedPackageHeaders.add(p);
208        }
209    }
210
211    /**
212     * Build the summary for the current class.
213     *
214     * @param node the XML element that specifies which components to document
215     * @param summariesTree the tree to which the class constant summary will be added
216     */
217    public void buildClassConstantSummary(XMLNode node, Content summariesTree) {
218        SortedSet<TypeElement> classes = !currentPackage.isUnnamed()
219                ? utils.getAllClasses(currentPackage)
220                : configuration.typeElementCatalog.allUnnamedClasses();
221        Content classConstantTree = writer.getClassConstantHeader();
222        for (TypeElement te : classes) {
223            if (!typeElementsWithConstFields.contains(te) ||
224                !utils.isIncluded(te)) {
225                continue;
226            }
227            currentClass = te;
228            //Build the documentation for the current class.
229            buildChildren(node, classConstantTree);
230        }
231        writer.addClassConstant(summariesTree, classConstantTree);
232    }
233
234    /**
235     * Build the summary of constant members in the class.
236     *
237     * @param node the XML element that specifies which components to document
238     * @param classConstantTree the tree to which the constant members table
239     *                          will be added
240     */
241    public void buildConstantMembers(XMLNode node, Content classConstantTree) {
242        new ConstantFieldBuilder(currentClass).buildMembersSummary(node, classConstantTree);
243    }
244
245    /**
246     * Return true if the given package has constant fields to document.
247     *
248     * @param pkg   the package being checked.
249     * @return true if the given package has constant fields to document.
250     */
251    private boolean hasConstantField(PackageElement pkg) {
252        SortedSet<TypeElement> classes = !pkg.isUnnamed()
253                  ? utils.getAllClasses(pkg)
254                  : configuration.typeElementCatalog.allUnnamedClasses();
255        boolean found = false;
256        for (TypeElement te : classes) {
257            if (utils.isIncluded(te) && hasConstantField(te)) {
258                found = true;
259            }
260        }
261        return found;
262    }
263
264    /**
265     * Return true if the given class has constant fields to document.
266     *
267     * @param typeElement the class being checked.
268     * @return true if the given package has constant fields to document.
269     */
270    private boolean hasConstantField (TypeElement typeElement) {
271        VisibleMemberMap visibleMemberMapFields = new VisibleMemberMap(typeElement,
272            VisibleMemberMap.Kind.FIELDS, configuration);
273        SortedSet<Element> fields = visibleMemberMapFields.getLeafClassMembers();
274        for (Element f : fields) {
275            VariableElement field = (VariableElement)f;
276            if (field.getConstantValue() != null) {
277                typeElementsWithConstFields.add(typeElement);
278                return true;
279            }
280        }
281        return false;
282    }
283
284    /**
285     * Return true if the given package name has been printed.  Also
286     * return true if the root of this package has been printed.
287     *
288     * @param pkgname the name of the package to check.
289     */
290    private boolean hasPrintedPackageIndex(PackageElement pkg) {
291        for (PackageElement printedPkg : printedPackageHeaders) {
292            if (utils.getPackageName(pkg).startsWith(utils.parsePackageName(printedPkg))) {
293                return true;
294            }
295        }
296        return false;
297    }
298
299    /**
300     * Print the table of constants.
301     *
302     * @author Jamie Ho
303     */
304    private class ConstantFieldBuilder {
305
306        /**
307         * The map used to get the visible variables.
308         */
309        protected VisibleMemberMap visibleMemberMapFields = null;
310
311        /**
312         * The map used to get the visible variables.
313         */
314        protected VisibleMemberMap visibleMemberMapEnumConst = null;
315
316        /**
317         * The typeElement that we are examining constants for.
318         */
319        protected TypeElement typeElement;
320
321        /**
322         * Construct a ConstantFieldSubWriter.
323         * @param typeElement the typeElement that we are examining constants for.
324         */
325        public ConstantFieldBuilder(TypeElement typeElement) {
326            this.typeElement = typeElement;
327            visibleMemberMapFields = new VisibleMemberMap(typeElement,
328                VisibleMemberMap.Kind.FIELDS, configuration);
329            visibleMemberMapEnumConst = new VisibleMemberMap(typeElement,
330                VisibleMemberMap.Kind.ENUM_CONSTANTS, configuration);
331        }
332
333        /**
334         * Builds the table of constants for a given class.
335         *
336         * @param node the XML element that specifies which components to document
337         * @param classConstantTree the tree to which the class constants table
338         *                          will be added
339         */
340        protected void buildMembersSummary(XMLNode node, Content classConstantTree) {
341            SortedSet<VariableElement> members = members();
342            if (!members.isEmpty()) {
343                writer.addConstantMembers(typeElement, members, classConstantTree);
344            }
345        }
346
347        /**
348         * Return the list of visible constant fields for the given TypeElement.
349         * @return the list of visible constant fields for the given TypeElement.
350         */
351        protected SortedSet<VariableElement> members() {
352            SortedSet<Element> list = visibleMemberMapFields.getLeafClassMembers();
353            list.addAll(visibleMemberMapEnumConst.getLeafClassMembers());
354            SortedSet<VariableElement> inclList =
355                    new TreeSet<>(utils.makeGeneralPurposeComparator());
356            for (Element element : list) {
357                VariableElement member = (VariableElement)element;
358                if (member.getConstantValue() != null) {
359                    inclList.add(member);
360                }
361            }
362            return inclList;
363        }
364    }
365}
366