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: *
jjg@1359: *
This is NOT part of any supported API.
jjg@1359: * If you write code that depends on this, you do so at your own risk.
jjg@1359: * This code and its internal interfaces are subject to change or
jjg@1359: * deletion without notice.
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: */
jjg@1410: protected final ConstantsSummaryWriter writer;
duke@1:
duke@1: /**
duke@1: * The set of ClassDocs that have constant fields.
duke@1: */
jjg@1410: protected final 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: *
jjg@1410: * @param context the build context.
jjg@1410: * @param writer the writer for the summary.
duke@1: */
jjg@1410: private ConstantsSummaryBuilder(Context context,
jjg@1410: ConstantsSummaryWriter writer) {
jjg@1410: super(context);
jjg@1410: this.writer = writer;
jjg@1410: this.classDocsWithConstFields = new HashSet();
duke@1: }
duke@1:
duke@1: /**
duke@1: * Construct a ConstantsSummaryBuilder.
duke@1: *
jjg@1410: * @param context the build context.
duke@1: * @param writer the writer for the summary.
duke@1: */
jjg@1410: public static ConstantsSummaryBuilder getInstance(Context context,
jjg@1410: ConstantsSummaryWriter writer) {
jjg@1410: return new ConstantsSummaryBuilder(context, writer);
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: }
jjg@1410: build(layoutParser.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: * @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: }