duke@1: /* bpatel@1568: * Copyright (c) 1997, 2013, 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: package com.sun.tools.doclets.formats.html; duke@1: jjg@1357: import java.io.*; jjg@1357: import java.util.*; jjg@1357: jjg@1357: import com.sun.javadoc.*; bpatel@1568: import com.sun.tools.javac.sym.Profiles; bpatel@1568: import com.sun.tools.javac.jvm.Profile; duke@1: import com.sun.tools.doclets.internal.toolkit.*; duke@1: import com.sun.tools.doclets.internal.toolkit.builders.*; duke@1: import com.sun.tools.doclets.internal.toolkit.util.*; duke@1: duke@1: /** duke@1: * The class with "start" method, calls individual Writers. 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. jjg@1359: * duke@1: * @author Atul M Dambalkar duke@1: * @author Robert Field duke@1: * @author Jamie Ho duke@1: * duke@1: */ duke@1: public class HtmlDoclet extends AbstractDoclet { jjg@1410: // An instance will be created by validOptions, and used by start. jjg@1410: private static HtmlDoclet docletToStart = null; jjg@1410: jjg@140: public HtmlDoclet() { jjg@1410: configuration = new ConfigurationImpl(); jjg@140: } duke@1: duke@1: /** duke@1: * The global configuration information for this run. duke@1: */ jjg@1410: public final ConfigurationImpl configuration; duke@1: duke@1: /** duke@1: * The "start" method as required by Javadoc. duke@1: * duke@1: * @param root the root of the documentation tree. duke@1: * @see com.sun.javadoc.RootDoc duke@1: * @return true if the doclet ran without encountering any errors. duke@1: */ duke@1: public static boolean start(RootDoc root) { jjg@1410: // In typical use, options will have been set up by calling validOptions, jjg@1410: // which will create an HtmlDoclet for use here. jjg@1410: HtmlDoclet doclet; jjg@1410: if (docletToStart != null) { jjg@1410: doclet = docletToStart; jjg@1410: docletToStart = null; jjg@1410: } else { jjg@1410: doclet = new HtmlDoclet(); jjg@140: } jjg@1410: return doclet.start(doclet, root); duke@1: } duke@1: duke@1: /** duke@1: * Create the configuration instance. duke@1: * Override this method to use a different duke@1: * configuration. duke@1: */ duke@1: public Configuration configuration() { jjg@1410: return configuration; duke@1: } duke@1: duke@1: /** duke@1: * Start the generation of files. Call generate methods in the individual duke@1: * writers, which will in turn genrate the documentation files. Call the duke@1: * TreeWriter generation first to ensure the Class Hierarchy is built duke@1: * first and then can be used in the later generation. duke@1: * duke@1: * For new format. duke@1: * duke@1: * @see com.sun.javadoc.RootDoc duke@1: */ duke@1: protected void generateOtherFiles(RootDoc root, ClassTree classtree) duke@1: throws Exception { duke@1: super.generateOtherFiles(root, classtree); duke@1: if (configuration.linksource) { jjg@1372: SourceToHTMLConverter.convertRoot(configuration, jjg@1372: root, DocPaths.SOURCE_OUTPUT); duke@1: } duke@1: jjg@1372: if (configuration.topFile.isEmpty()) { duke@1: configuration.standardmessage. duke@1: error("doclet.No_Non_Deprecated_Classes_To_Document"); duke@1: return; duke@1: } duke@1: boolean nodeprecated = configuration.nodeprecated; jjg@1383: performCopy(configuration.helpfile); jjg@1383: performCopy(configuration.stylesheetfile); duke@1: // do early to reduce memory footprint duke@1: if (configuration.classuse) { duke@1: ClassUseWriter.generate(configuration, classtree); duke@1: } duke@1: IndexBuilder indexbuilder = new IndexBuilder(configuration, nodeprecated); duke@1: duke@1: if (configuration.createtree) { duke@1: TreeWriter.generate(configuration, classtree); duke@1: } duke@1: if (configuration.createindex) { duke@1: if (configuration.splitindex) { duke@1: SplitIndexWriter.generate(configuration, indexbuilder); duke@1: } else { duke@1: SingleIndexWriter.generate(configuration, indexbuilder); duke@1: } duke@1: } duke@1: duke@1: if (!(configuration.nodeprecatedlist || nodeprecated)) { duke@1: DeprecatedListWriter.generate(configuration); duke@1: } duke@1: duke@1: AllClassesFrameWriter.generate(configuration, duke@1: new IndexBuilder(configuration, nodeprecated, true)); duke@1: duke@1: FrameOutputWriter.generate(configuration); duke@1: duke@1: if (configuration.createoverview) { duke@1: PackageIndexWriter.generate(configuration); duke@1: } duke@1: if (configuration.helpfile.length() == 0 && duke@1: !configuration.nohelp) { duke@1: HelpWriter.generate(configuration); duke@1: } bpatel@793: // If a stylesheet file is not specified, copy the default stylesheet bpatel@793: // and replace newline with platform-specific newline. bpatel@1417: DocFile f; duke@1: if (configuration.stylesheetfile.length() == 0) { bpatel@1417: f = DocFile.createFileForOutput(configuration, DocPaths.STYLESHEET); jjg@1383: f.copyResource(DocPaths.RESOURCES.resolve(DocPaths.STYLESHEET), false, true); duke@1: } bpatel@1417: f = DocFile.createFileForOutput(configuration, DocPaths.JAVASCRIPT); bpatel@1417: f.copyResource(DocPaths.RESOURCES.resolve(DocPaths.JAVASCRIPT), true, true); duke@1: } duke@1: duke@1: /** duke@1: * {@inheritDoc} duke@1: */ duke@1: protected void generateClassFiles(ClassDoc[] arr, ClassTree classtree) { duke@1: Arrays.sort(arr); duke@1: for(int i = 0; i < arr.length; i++) { duke@1: if (!(configuration.isGeneratedDoc(arr[i]) && arr[i].isIncluded())) { duke@1: continue; duke@1: } duke@1: ClassDoc prev = (i == 0)? duke@1: null: duke@1: arr[i-1]; duke@1: ClassDoc curr = arr[i]; duke@1: ClassDoc next = (i+1 == arr.length)? duke@1: null: duke@1: arr[i+1]; duke@1: try { duke@1: if (curr.isAnnotationType()) { duke@1: AbstractBuilder annotationTypeBuilder = duke@1: configuration.getBuilderFactory() duke@1: .getAnnotationTypeBuilder((AnnotationTypeDoc) curr, duke@1: prev, next); duke@1: annotationTypeBuilder.build(); duke@1: } else { duke@1: AbstractBuilder classBuilder = duke@1: configuration.getBuilderFactory() duke@1: .getClassBuilder(curr, prev, next, classtree); duke@1: classBuilder.build(); duke@1: } kizune@2071: } catch (IOException e) { kizune@2071: throw new DocletAbortException(e); kizune@2071: } catch (DocletAbortException de) { kizune@2071: throw de; duke@1: } catch (Exception e) { duke@1: e.printStackTrace(); jjg@1985: throw new DocletAbortException(e); duke@1: } duke@1: } duke@1: } duke@1: duke@1: /** duke@1: * {@inheritDoc} duke@1: */ bpatel@1568: protected void generateProfileFiles() throws Exception { bpatel@2023: if (configuration.showProfiles && configuration.profilePackages.size() > 0) { bpatel@1568: ProfileIndexFrameWriter.generate(configuration); bpatel@1568: Profile prevProfile = null, nextProfile; bpatel@2023: String profileName; bpatel@1568: for (int i = 1; i < configuration.profiles.getProfileCount(); i++) { bpatel@2023: profileName = Profile.lookup(i).name; bpatel@2023: // Generate profile package pages only if there are any packages bpatel@2023: // in a profile to be documented. The profilePackages map will not bpatel@2023: // contain an entry for the profile if there are no packages to be documented. bpatel@2023: if (!configuration.shouldDocumentProfile(profileName)) bpatel@2023: continue; bpatel@2023: ProfilePackageIndexFrameWriter.generate(configuration, profileName); bpatel@1568: PackageDoc[] packages = configuration.profilePackages.get( bpatel@2023: profileName); bpatel@1568: PackageDoc prev = null, next; bpatel@1568: for (int j = 0; j < packages.length; j++) { bpatel@1568: // if -nodeprecated option is set and the package is marked as bpatel@1568: // deprecated, do not generate the profilename-package-summary.html bpatel@1568: // and profilename-package-frame.html pages for that package. bpatel@1568: if (!(configuration.nodeprecated && Util.isDeprecated(packages[j]))) { bpatel@1568: ProfilePackageFrameWriter.generate(configuration, packages[j], i); bpatel@1568: next = (j + 1 < packages.length bpatel@1568: && packages[j + 1].name().length() > 0) ? packages[j + 1] : null; bpatel@1568: AbstractBuilder profilePackageSummaryBuilder = bpatel@1568: configuration.getBuilderFactory().getProfilePackageSummaryBuilder( bpatel@1568: packages[j], prev, next, Profile.lookup(i)); bpatel@1568: profilePackageSummaryBuilder.build(); bpatel@1568: prev = packages[j]; bpatel@1568: } bpatel@1568: } bpatel@1568: nextProfile = (i + 1 < configuration.profiles.getProfileCount()) ? bpatel@1568: Profile.lookup(i + 1) : null; bpatel@1568: AbstractBuilder profileSummaryBuilder = bpatel@1568: configuration.getBuilderFactory().getProfileSummaryBuilder( bpatel@1568: Profile.lookup(i), prevProfile, nextProfile); bpatel@1568: profileSummaryBuilder.build(); bpatel@1568: prevProfile = Profile.lookup(i); bpatel@1568: } bpatel@1568: } bpatel@1568: } bpatel@1568: bpatel@1568: /** bpatel@1568: * {@inheritDoc} bpatel@1568: */ duke@1: protected void generatePackageFiles(ClassTree classtree) throws Exception { duke@1: PackageDoc[] packages = configuration.packages; duke@1: if (packages.length > 1) { duke@1: PackageIndexFrameWriter.generate(configuration); duke@1: } duke@1: PackageDoc prev = null, next; bpatel@995: for (int i = 0; i < packages.length; i++) { bpatel@995: // if -nodeprecated option is set and the package is marked as bpatel@995: // deprecated, do not generate the package-summary.html, package-frame.html bpatel@995: // and package-tree.html pages for that package. bpatel@995: if (!(configuration.nodeprecated && Util.isDeprecated(packages[i]))) { bpatel@995: PackageFrameWriter.generate(configuration, packages[i]); bpatel@995: next = (i + 1 < packages.length && bpatel@995: packages[i + 1].name().length() > 0) ? packages[i + 1] : null; bpatel@995: //If the next package is unnamed package, skip 2 ahead if possible bpatel@995: next = (i + 2 < packages.length && next == null) ? packages[i + 2] : next; bpatel@995: AbstractBuilder packageSummaryBuilder = bpatel@995: configuration.getBuilderFactory().getPackageSummaryBuilder( bpatel@995: packages[i], prev, next); bpatel@995: packageSummaryBuilder.build(); bpatel@995: if (configuration.createtree) { bpatel@995: PackageTreeWriter.generate(configuration, bpatel@995: packages[i], prev, next, bpatel@995: configuration.nodeprecated); bpatel@995: } bpatel@995: prev = packages[i]; duke@1: } duke@1: } duke@1: } duke@1: jjg@1410: public static final ConfigurationImpl sharedInstanceForOptions = jjg@1410: new ConfigurationImpl(); jjg@1410: duke@1: /** duke@1: * Check for doclet added options here. duke@1: * duke@1: * @return number of arguments to option. Zero return means duke@1: * option not known. Negative value means error occurred. duke@1: */ duke@1: public static int optionLength(String option) { duke@1: // Construct temporary configuration for check jjg@1410: return sharedInstanceForOptions.optionLength(option); duke@1: } duke@1: duke@1: /** duke@1: * Check that options have the correct arguments here. duke@1: *

duke@1: * This method is not required and will default gracefully duke@1: * (to true) if absent. duke@1: *

duke@1: * Printing option related error messages (using the provided duke@1: * DocErrorReporter) is the responsibility of this method. duke@1: * duke@1: * @return true if the options are valid. duke@1: */ duke@1: public static boolean validOptions(String options[][], duke@1: DocErrorReporter reporter) { jjg@1410: docletToStart = new HtmlDoclet(); jjg@1410: return docletToStart.configuration.validOptions(options, reporter); duke@1: } duke@1: jjg@1383: private void performCopy(String filename) { jjg@1383: if (filename.isEmpty()) jjg@1383: return; jjg@1383: duke@1: try { jjg@1383: DocFile fromfile = DocFile.createFileForInput(configuration, filename); jjg@1383: DocPath path = DocPath.create(fromfile.getName()); jjg@1383: DocFile toFile = DocFile.createFileForOutput(configuration, path); jjg@1383: if (toFile.isSameFile(fromfile)) jjg@1383: return; jjg@1383: jjg@1383: configuration.message.notice((SourcePosition) null, jjg@1383: "doclet.Copying_File_0_To_File_1", jjg@1383: fromfile.toString(), path.getPath()); jjg@1383: toFile.copyFile(fromfile); duke@1: } catch (IOException exc) { jjg@1383: configuration.message.error((SourcePosition) null, duke@1: "doclet.perform_copy_exception_encountered", duke@1: exc.toString()); jjg@1985: throw new DocletAbortException(exc); duke@1: } duke@1: } duke@1: }