duke@1: /* jjg@1357: * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. duke@1: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. duke@1: * duke@1: * This code is free software; you can redistribute it and/or modify it duke@1: * under the terms of the GNU General Public License version 2 only, as ohair@554: * published by the Free Software Foundation. Oracle designates this duke@1: * particular file as subject to the "Classpath" exception as provided ohair@554: * by Oracle in the LICENSE file that accompanied this code. duke@1: * duke@1: * This code is distributed in the hope that it will be useful, but WITHOUT duke@1: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or duke@1: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License duke@1: * version 2 for more details (a copy is included in the LICENSE file that duke@1: * accompanied this code). duke@1: * duke@1: * You should have received a copy of the GNU General Public License version duke@1: * 2 along with this work; if not, write to the Free Software Foundation, duke@1: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. duke@1: * ohair@554: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ohair@554: * or visit www.oracle.com if you need additional information or have any ohair@554: * questions. duke@1: */ duke@1: duke@1: package com.sun.tools.doclets.internal.toolkit.builders; duke@1: bpatel@766: import java.io.*; bpatel@766: import java.util.*; jjg@1357: bpatel@766: import com.sun.javadoc.*; jjg@1357: import com.sun.tools.doclets.internal.toolkit.*; duke@1: import com.sun.tools.doclets.internal.toolkit.util.*; duke@1: duke@1: /** duke@1: * Builds the Constants Summary Page. duke@1: * duke@1: * This code is not part of an API. duke@1: * It is implementation that is subject to change. duke@1: * Do not use it as an API duke@1: * duke@1: * @author Jamie Ho bpatel@766: * @author Bhavesh Patel (Modified) duke@1: * @since 1.5 duke@1: */ duke@1: public class ConstantsSummaryBuilder extends AbstractBuilder { duke@1: duke@1: /** duke@1: * The root element of the constant summary XML is {@value}. duke@1: */ duke@1: public static final String ROOT = "ConstantSummary"; duke@1: duke@1: /** duke@1: * The maximum number of package directories shown in the constant duke@1: * value index. duke@1: */ duke@1: public static final int MAX_CONSTANT_VALUE_INDEX_LENGTH = 2; duke@1: duke@1: /** duke@1: * The writer used to write the results. duke@1: */ duke@1: protected ConstantsSummaryWriter writer; duke@1: duke@1: /** duke@1: * The set of ClassDocs that have constant fields. duke@1: */ jjg@74: protected Set classDocsWithConstFields; duke@1: duke@1: /** duke@1: * The set of printed package headers. duke@1: */ jjg@74: protected Set printedPackageHeaders; duke@1: duke@1: /** duke@1: * The current package being documented. duke@1: */ duke@1: private PackageDoc currentPackage; duke@1: duke@1: /** duke@1: * The current class being documented. duke@1: */ duke@1: private ClassDoc currentClass; duke@1: duke@1: /** bpatel@766: * The content tree for the constant summary documentation. bpatel@766: */ bpatel@766: private Content contentTree; bpatel@766: bpatel@766: /** duke@1: * Construct a new ConstantsSummaryBuilder. duke@1: * duke@1: * @param configuration the current configuration of the duke@1: * doclet. duke@1: */ duke@1: private ConstantsSummaryBuilder(Configuration configuration) { duke@1: super(configuration); duke@1: } duke@1: duke@1: /** duke@1: * Construct a ConstantsSummaryBuilder. duke@1: * duke@1: * @param configuration the configuration used in this run duke@1: * of the doclet. duke@1: * @param writer the writer for the summary. duke@1: */ duke@1: public static ConstantsSummaryBuilder getInstance( duke@1: Configuration configuration, ConstantsSummaryWriter writer) { duke@1: ConstantsSummaryBuilder builder = new ConstantsSummaryBuilder( duke@1: configuration); duke@1: builder.writer = writer; jjg@74: builder.classDocsWithConstFields = new HashSet(); duke@1: return builder; duke@1: } duke@1: duke@1: /** duke@1: * {@inheritDoc} duke@1: */ duke@1: public void build() throws IOException { duke@1: if (writer == null) { duke@1: //Doclet does not support this output. duke@1: return; duke@1: } bpatel@766: build(LayoutParser.getInstance(configuration).parseXML(ROOT), contentTree); duke@1: } duke@1: duke@1: /** duke@1: * {@inheritDoc} duke@1: */ duke@1: public String getName() { duke@1: return ROOT; duke@1: } duke@1: duke@1: /** duke@1: * Build the constant summary. duke@1: * bpatel@766: * @param node the XML element that specifies which components to document bpatel@766: * @param contentTree the content tree to which the documentation will be added duke@1: */ bpatel@766: public void buildConstantSummary(XMLNode node, Content contentTree) throws Exception { bpatel@766: contentTree = writer.getHeader(); bpatel@766: buildChildren(node, contentTree); bpatel@766: writer.addFooter(contentTree); bpatel@766: writer.printDocument(contentTree); duke@1: writer.close(); duke@1: } duke@1: duke@1: /** bpatel@766: * Build the list of packages. bpatel@766: * bpatel@766: * @param node the XML element that specifies which components to document bpatel@766: * @param contentTree the content tree to which the content list will be added duke@1: */ bpatel@766: public void buildContents(XMLNode node, Content contentTree) { bpatel@766: Content contentListTree = writer.getContentsHeader(); duke@1: PackageDoc[] packages = configuration.packages; jjg@74: printedPackageHeaders = new HashSet(); duke@1: for (int i = 0; i < packages.length; i++) { duke@1: if (hasConstantField(packages[i]) && ! hasPrintedPackageIndex(packages[i].name())) { bpatel@766: writer.addLinkToPackageContent(packages[i], duke@1: parsePackageName(packages[i].name()), bpatel@766: printedPackageHeaders, contentListTree); duke@1: } duke@1: } bpatel@766: contentTree.addContent(writer.getContentsList(contentListTree)); duke@1: } duke@1: duke@1: /** duke@1: * Build the summary for each documented package. duke@1: * bpatel@766: * @param node the XML element that specifies which components to document bpatel@766: * @param contentTree the tree to which the summaries will be added duke@1: */ bpatel@766: public void buildConstantSummaries(XMLNode node, Content contentTree) { duke@1: PackageDoc[] packages = configuration.packages; jjg@74: printedPackageHeaders = new HashSet(); bpatel@766: Content summariesTree = writer.getConstantSummaries(); duke@1: for (int i = 0; i < packages.length; i++) { duke@1: if (hasConstantField(packages[i])) { duke@1: currentPackage = packages[i]; duke@1: //Build the documentation for the current package. bpatel@766: buildChildren(node, summariesTree); duke@1: } duke@1: } bpatel@766: contentTree.addContent(summariesTree); duke@1: } duke@1: duke@1: /** bpatel@766: * Build the header for the given package. duke@1: * bpatel@766: * @param node the XML element that specifies which components to document bpatel@766: * @param summariesTree the tree to which the package header will be added duke@1: */ bpatel@766: public void buildPackageHeader(XMLNode node, Content summariesTree) { bpatel@766: String parsedPackageName = parsePackageName(currentPackage.name()); bpatel@766: if (! printedPackageHeaders.contains(parsedPackageName)) { bpatel@766: writer.addPackageName(currentPackage, bpatel@766: parsePackageName(currentPackage.name()), summariesTree); bpatel@766: printedPackageHeaders.add(parsedPackageName); bpatel@766: } duke@1: } duke@1: duke@1: /** duke@1: * Build the summary for the current class. duke@1: * bpatel@766: * @param node the XML element that specifies which components to document bpatel@766: * @param summariesTree the tree to which the class constant summary will be added duke@1: */ bpatel@766: public void buildClassConstantSummary(XMLNode node, Content summariesTree) { duke@1: ClassDoc[] classes = currentPackage.name().length() > 0 ? duke@1: currentPackage.allClasses() : duke@1: configuration.classDocCatalog.allClasses( duke@1: DocletConstants.DEFAULT_PACKAGE_NAME); duke@1: Arrays.sort(classes); bpatel@766: Content classConstantTree = writer.getClassConstantHeader(); duke@1: for (int i = 0; i < classes.length; i++) { duke@1: if (! classDocsWithConstFields.contains(classes[i]) || duke@1: ! classes[i].isIncluded()) { duke@1: continue; duke@1: } duke@1: currentClass = classes[i]; duke@1: //Build the documentation for the current class. bpatel@766: buildChildren(node, classConstantTree); duke@1: } bpatel@766: summariesTree.addContent(classConstantTree); duke@1: } duke@1: duke@1: /** bpatel@766: * Build the summary of constant members in the class. bpatel@766: * bpatel@766: * @param node the XML element that specifies which components to document bpatel@766: * @param classConstantTree the tree to which the constant members table bpatel@766: * will be added duke@1: */ bpatel@766: public void buildConstantMembers(XMLNode node, Content classConstantTree) { bpatel@766: new ConstantFieldBuilder(currentClass).buildMembersSummary(node, classConstantTree); duke@1: } duke@1: duke@1: /** duke@1: * Return true if the given package has constant fields to document. duke@1: * duke@1: * @param pkg the package being checked. duke@1: * @return true if the given package has constant fields to document. duke@1: */ duke@1: private boolean hasConstantField(PackageDoc pkg) { duke@1: ClassDoc[] classes; duke@1: if (pkg.name().length() > 0) { duke@1: classes = pkg.allClasses(); duke@1: } else { duke@1: classes = configuration.classDocCatalog.allClasses( duke@1: DocletConstants.DEFAULT_PACKAGE_NAME); duke@1: } duke@1: boolean found = false; duke@1: for (int j = 0; j < classes.length; j++){ duke@1: if (classes[j].isIncluded() && hasConstantField(classes[j])) { duke@1: found = true; duke@1: } duke@1: } duke@1: return found; duke@1: } duke@1: duke@1: /** duke@1: * Return true if the given class has constant fields to document. duke@1: * duke@1: * @param classDoc the class being checked. duke@1: * @return true if the given package has constant fields to document. duke@1: */ duke@1: private boolean hasConstantField (ClassDoc classDoc) { duke@1: VisibleMemberMap visibleMemberMapFields = new VisibleMemberMap(classDoc, duke@1: VisibleMemberMap.FIELDS, configuration.nodeprecated); mcimadamore@184: List fields = visibleMemberMapFields.getLeafClassMembers(configuration); mcimadamore@184: for (Iterator iter = fields.iterator(); iter.hasNext(); ) { duke@1: FieldDoc field = (FieldDoc) iter.next(); duke@1: if (field.constantValueExpression() != null) { duke@1: classDocsWithConstFields.add(classDoc); duke@1: return true; duke@1: } duke@1: } duke@1: return false; duke@1: } duke@1: duke@1: /** duke@1: * Return true if the given package name has been printed. Also duke@1: * return true if the root of this package has been printed. duke@1: * duke@1: * @param pkgname the name of the package to check. duke@1: */ duke@1: private boolean hasPrintedPackageIndex(String pkgname) { jjg@74: String[] list = printedPackageHeaders.toArray(new String[] {}); duke@1: for (int i = 0; i < list.length; i++) { duke@1: if (pkgname.startsWith(list[i])) { duke@1: return true; duke@1: } duke@1: } duke@1: return false; duke@1: } duke@1: duke@1: /** duke@1: * Print the table of constants. duke@1: * duke@1: * @author Jamie Ho duke@1: * @since 1.4 duke@1: */ duke@1: private class ConstantFieldBuilder { duke@1: duke@1: /** duke@1: * The map used to get the visible variables. duke@1: */ duke@1: protected VisibleMemberMap visibleMemberMapFields = null; duke@1: duke@1: /** duke@1: * The map used to get the visible variables. duke@1: */ duke@1: protected VisibleMemberMap visibleMemberMapEnumConst = null; duke@1: duke@1: /** duke@1: * The classdoc that we are examining constants for. duke@1: */ duke@1: protected ClassDoc classdoc; duke@1: duke@1: /** duke@1: * Construct a ConstantFieldSubWriter. duke@1: * @param classdoc the classdoc that we are examining constants for. duke@1: */ duke@1: public ConstantFieldBuilder(ClassDoc classdoc) { duke@1: this.classdoc = classdoc; duke@1: visibleMemberMapFields = new VisibleMemberMap(classdoc, duke@1: VisibleMemberMap.FIELDS, configuration.nodeprecated); duke@1: visibleMemberMapEnumConst = new VisibleMemberMap(classdoc, duke@1: VisibleMemberMap.ENUM_CONSTANTS, configuration.nodeprecated); duke@1: } duke@1: duke@1: /** duke@1: * Builds the table of constants for a given class. bpatel@766: * bpatel@766: * @param node the XML element that specifies which components to document bpatel@766: * @param classConstantTree the tree to which the class constants table bpatel@766: * will be added duke@1: */ bpatel@766: protected void buildMembersSummary(XMLNode node, Content classConstantTree) { jjg@74: List members = new ArrayList(members()); duke@1: if (members.size() > 0) { duke@1: Collections.sort(members); bpatel@766: writer.addConstantMembers(classdoc, members, classConstantTree); duke@1: } duke@1: } duke@1: duke@1: /** duke@1: * Return the list of visible constant fields for the given classdoc. duke@1: * @param cd the classdoc to examine. duke@1: * @return the list of visible constant fields for the given classdoc. duke@1: */ jjg@74: protected List members() { jjg@74: List l = visibleMemberMapFields.getLeafClassMembers(configuration); duke@1: l.addAll(visibleMemberMapEnumConst.getLeafClassMembers(configuration)); jjg@74: Iterator iter; duke@1: duke@1: if(l != null){ duke@1: iter = l.iterator(); duke@1: } else { duke@1: return null; duke@1: } jjg@74: List inclList = new LinkedList(); duke@1: FieldDoc member; duke@1: while(iter.hasNext()){ duke@1: member = (FieldDoc)iter.next(); duke@1: if(member.constantValue() != null){ duke@1: inclList.add(member); duke@1: } duke@1: } duke@1: return inclList; duke@1: } duke@1: } duke@1: duke@1: /** duke@1: * Parse the package name. We only want to display package name up to duke@1: * 2 levels. duke@1: */ duke@1: private String parsePackageName(String pkgname) { duke@1: int index = -1; duke@1: for (int j = 0; j < MAX_CONSTANT_VALUE_INDEX_LENGTH; j++) { duke@1: index = pkgname.indexOf(".", index + 1); duke@1: } duke@1: if (index != -1) { duke@1: pkgname = pkgname.substring(0, index); duke@1: } duke@1: return pkgname; duke@1: } duke@1: }