1 /*
2  * Copyright (c) 1997, 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 package com.sun.tools.doclets.formats.html;
26 
27 import java.io.*;
28 import java.util.*;
29 
30 import com.sun.javadoc.*;
31 import com.sun.tools.javac.sym.Profiles;
32 import com.sun.tools.javac.jvm.Profile;
33 import com.sun.tools.doclets.internal.toolkit.*;
34 import com.sun.tools.doclets.internal.toolkit.builders.*;
35 import com.sun.tools.doclets.internal.toolkit.util.*;
36 
37 /**
38  * The class with "start" method, calls individual Writers.
39  *
40  *  <p><b>This is NOT part of any supported API.
41  *  If you write code that depends on this, you do so at your own risk.
42  *  This code and its internal interfaces are subject to change or
43  *  deletion without notice.</b>
44  *
45  * @author Atul M Dambalkar
46  * @author Robert Field
47  * @author Jamie Ho
48  *
49  */
50 public class HtmlDoclet extends AbstractDoclet {
51     // An instance will be created by validOptions, and used by start.
52     private static HtmlDoclet docletToStart = null;
53 
HtmlDoclet()54     public HtmlDoclet() {
55         configuration = new ConfigurationImpl();
56     }
57 
58     /**
59      * The global configuration information for this run.
60      */
61     public final ConfigurationImpl configuration;
62 
63     /**
64      * The "start" method as required by Javadoc.
65      *
66      * @param root the root of the documentation tree.
67      * @see com.sun.javadoc.RootDoc
68      * @return true if the doclet ran without encountering any errors.
69      */
start(RootDoc root)70     public static boolean start(RootDoc root) {
71         // In typical use, options will have been set up by calling validOptions,
72         // which will create an HtmlDoclet for use here.
73         HtmlDoclet doclet;
74         if (docletToStart != null) {
75             doclet = docletToStart;
76             docletToStart = null;
77         } else {
78             doclet = new HtmlDoclet();
79         }
80         return doclet.start(doclet, root);
81     }
82 
83     /**
84      * Create the configuration instance.
85      * Override this method to use a different
86      * configuration.
87      */
configuration()88     public Configuration configuration() {
89         return configuration;
90     }
91 
92     /**
93      * Start the generation of files. Call generate methods in the individual
94      * writers, which will in turn genrate the documentation files. Call the
95      * TreeWriter generation first to ensure the Class Hierarchy is built
96      * first and then can be used in the later generation.
97      *
98      * For new format.
99      *
100      * @see com.sun.javadoc.RootDoc
101      */
generateOtherFiles(RootDoc root, ClassTree classtree)102     protected void generateOtherFiles(RootDoc root, ClassTree classtree)
103             throws Exception {
104         super.generateOtherFiles(root, classtree);
105         if (configuration.linksource) {
106             SourceToHTMLConverter.convertRoot(configuration,
107                 root, DocPaths.SOURCE_OUTPUT);
108         }
109 
110         if (configuration.topFile.isEmpty()) {
111             configuration.standardmessage.
112                 error("doclet.No_Non_Deprecated_Classes_To_Document");
113             return;
114         }
115         boolean nodeprecated = configuration.nodeprecated;
116         performCopy(configuration.helpfile);
117         performCopy(configuration.stylesheetfile);
118         // do early to reduce memory footprint
119         if (configuration.classuse) {
120             ClassUseWriter.generate(configuration, classtree);
121         }
122         IndexBuilder indexbuilder = new IndexBuilder(configuration, nodeprecated);
123 
124         if (configuration.createtree) {
125             TreeWriter.generate(configuration, classtree);
126         }
127         if (configuration.createindex) {
128             if (configuration.splitindex) {
129                 SplitIndexWriter.generate(configuration, indexbuilder);
130             } else {
131                 SingleIndexWriter.generate(configuration, indexbuilder);
132             }
133         }
134 
135         if (!(configuration.nodeprecatedlist || nodeprecated)) {
136             DeprecatedListWriter.generate(configuration);
137         }
138 
139         AllClassesFrameWriter.generate(configuration,
140             new IndexBuilder(configuration, nodeprecated, true));
141 
142         FrameOutputWriter.generate(configuration);
143 
144         if (configuration.createoverview) {
145             PackageIndexWriter.generate(configuration);
146         }
147         if (configuration.helpfile.length() == 0 &&
148             !configuration.nohelp) {
149             HelpWriter.generate(configuration);
150         }
151         // If a stylesheet file is not specified, copy the default stylesheet
152         // and replace newline with platform-specific newline.
153         DocFile f;
154         if (configuration.stylesheetfile.length() == 0) {
155             f = DocFile.createFileForOutput(configuration, DocPaths.STYLESHEET);
156             f.copyResource(DocPaths.RESOURCES.resolve(DocPaths.STYLESHEET), false, true);
157         }
158         f = DocFile.createFileForOutput(configuration, DocPaths.JAVASCRIPT);
159         f.copyResource(DocPaths.RESOURCES.resolve(DocPaths.JAVASCRIPT), true, true);
160     }
161 
162     /**
163      * {@inheritDoc}
164      */
generateClassFiles(ClassDoc[] arr, ClassTree classtree)165     protected void generateClassFiles(ClassDoc[] arr, ClassTree classtree) {
166         Arrays.sort(arr);
167         for(int i = 0; i < arr.length; i++) {
168             if (!(configuration.isGeneratedDoc(arr[i]) && arr[i].isIncluded())) {
169                 continue;
170             }
171             ClassDoc prev = (i == 0)?
172                 null:
173                 arr[i-1];
174             ClassDoc curr = arr[i];
175             ClassDoc next = (i+1 == arr.length)?
176                 null:
177                 arr[i+1];
178             try {
179                 if (curr.isAnnotationType()) {
180                     AbstractBuilder annotationTypeBuilder =
181                         configuration.getBuilderFactory()
182                             .getAnnotationTypeBuilder((AnnotationTypeDoc) curr,
183                                 prev, next);
184                     annotationTypeBuilder.build();
185                 } else {
186                     AbstractBuilder classBuilder =
187                         configuration.getBuilderFactory()
188                             .getClassBuilder(curr, prev, next, classtree);
189                     classBuilder.build();
190                 }
191             } catch (IOException e) {
192                 throw new DocletAbortException(e);
193             } catch (FatalError fe) {
194                 throw fe;
195             } catch (DocletAbortException de) {
196                 throw de;
197             } catch (Exception e) {
198                 e.printStackTrace();
199                 throw new DocletAbortException(e);
200             }
201         }
202     }
203 
204     /**
205      * {@inheritDoc}
206      */
generateProfileFiles()207     protected void generateProfileFiles() throws Exception {
208         if (configuration.showProfiles && configuration.profilePackages.size() > 0) {
209             ProfileIndexFrameWriter.generate(configuration);
210             Profile prevProfile = null, nextProfile;
211             String profileName;
212             for (int i = 1; i < configuration.profiles.getProfileCount(); i++) {
213                 profileName = Profile.lookup(i).name;
214                 // Generate profile package pages only if there are any packages
215                 // in a profile to be documented. The profilePackages map will not
216                 // contain an entry for the profile if there are no packages to be documented.
217                 if (!configuration.shouldDocumentProfile(profileName))
218                     continue;
219                 ProfilePackageIndexFrameWriter.generate(configuration, profileName);
220                 PackageDoc[] packages = configuration.profilePackages.get(
221                         profileName);
222                 PackageDoc prev = null, next;
223                 for (int j = 0; j < packages.length; j++) {
224                     // if -nodeprecated option is set and the package is marked as
225                     // deprecated, do not generate the profilename-package-summary.html
226                     // and profilename-package-frame.html pages for that package.
227                     if (!(configuration.nodeprecated && Util.isDeprecated(packages[j]))) {
228                         ProfilePackageFrameWriter.generate(configuration, packages[j], i);
229                         next = (j + 1 < packages.length
230                                 && packages[j + 1].name().length() > 0) ? packages[j + 1] : null;
231                         AbstractBuilder profilePackageSummaryBuilder =
232                                 configuration.getBuilderFactory().getProfilePackageSummaryBuilder(
233                                 packages[j], prev, next, Profile.lookup(i));
234                         profilePackageSummaryBuilder.build();
235                         prev = packages[j];
236                     }
237                 }
238                 nextProfile = (i + 1 < configuration.profiles.getProfileCount()) ?
239                         Profile.lookup(i + 1) : null;
240                 AbstractBuilder profileSummaryBuilder =
241                         configuration.getBuilderFactory().getProfileSummaryBuilder(
242                         Profile.lookup(i), prevProfile, nextProfile);
243                 profileSummaryBuilder.build();
244                 prevProfile = Profile.lookup(i);
245             }
246         }
247     }
248 
249     /**
250      * {@inheritDoc}
251      */
generatePackageFiles(ClassTree classtree)252     protected void generatePackageFiles(ClassTree classtree) throws Exception {
253         PackageDoc[] packages = configuration.packages;
254         if (packages.length > 1) {
255             PackageIndexFrameWriter.generate(configuration);
256         }
257         PackageDoc prev = null, next;
258         for (int i = 0; i < packages.length; i++) {
259             // if -nodeprecated option is set and the package is marked as
260             // deprecated, do not generate the package-summary.html, package-frame.html
261             // and package-tree.html pages for that package.
262             if (!(configuration.nodeprecated && Util.isDeprecated(packages[i]))) {
263                 PackageFrameWriter.generate(configuration, packages[i]);
264                 next = (i + 1 < packages.length &&
265                         packages[i + 1].name().length() > 0) ? packages[i + 1] : null;
266                 //If the next package is unnamed package, skip 2 ahead if possible
267                 next = (i + 2 < packages.length && next == null) ? packages[i + 2] : next;
268                 AbstractBuilder packageSummaryBuilder =
269                         configuration.getBuilderFactory().getPackageSummaryBuilder(
270                         packages[i], prev, next);
271                 packageSummaryBuilder.build();
272                 if (configuration.createtree) {
273                     PackageTreeWriter.generate(configuration,
274                             packages[i], prev, next,
275                             configuration.nodeprecated);
276                 }
277                 prev = packages[i];
278             }
279         }
280     }
281 
282     public static final ConfigurationImpl sharedInstanceForOptions =
283             new ConfigurationImpl();
284 
285     /**
286      * Check for doclet added options here.
287      *
288      * @return number of arguments to option. Zero return means
289      * option not known.  Negative value means error occurred.
290      */
optionLength(String option)291     public static int optionLength(String option) {
292         // Construct temporary configuration for check
293         return sharedInstanceForOptions.optionLength(option);
294     }
295 
296     /**
297      * Check that options have the correct arguments here.
298      * <P>
299      * This method is not required and will default gracefully
300      * (to true) if absent.
301      * <P>
302      * Printing option related error messages (using the provided
303      * DocErrorReporter) is the responsibility of this method.
304      *
305      * @return true if the options are valid.
306      */
validOptions(String options[][], DocErrorReporter reporter)307     public static boolean validOptions(String options[][],
308             DocErrorReporter reporter) {
309         docletToStart = new HtmlDoclet();
310         return docletToStart.configuration.validOptions(options, reporter);
311     }
312 
performCopy(String filename)313     private void performCopy(String filename) {
314         if (filename.isEmpty())
315             return;
316 
317         try {
318             DocFile fromfile = DocFile.createFileForInput(configuration, filename);
319             DocPath path = DocPath.create(fromfile.getName());
320             DocFile toFile = DocFile.createFileForOutput(configuration, path);
321             if (toFile.isSameFile(fromfile))
322                 return;
323 
324             configuration.message.notice((SourcePosition) null,
325                     "doclet.Copying_File_0_To_File_1",
326                     fromfile.toString(), path.getPath());
327             toFile.copyFile(fromfile);
328         } catch (IOException exc) {
329             configuration.message.error((SourcePosition) null,
330                     "doclet.perform_copy_exception_encountered",
331                     exc.toString());
332             throw new DocletAbortException(exc);
333         }
334     }
335 }
336