Tue, 03 Dec 2013 14:21:45 -0800
8025416: doclet not substituting {@docRoot} in some cases
Reviewed-by: jjg
1 /*
2 * Copyright (c) 1997, 2013, 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;
27 import java.io.*;
28 import java.util.*;
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.*;
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;
54 public HtmlDoclet() {
55 configuration = new ConfigurationImpl();
56 }
58 /**
59 * The global configuration information for this run.
60 */
61 public final ConfigurationImpl configuration;
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 */
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 }
83 /**
84 * Create the configuration instance.
85 * Override this method to use a different
86 * configuration.
87 */
88 public Configuration configuration() {
89 return configuration;
90 }
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 */
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 }
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 copyResourceFile("background.gif");
119 copyResourceFile("tab.gif");
120 copyResourceFile("titlebar.gif");
121 copyResourceFile("titlebar_end.gif");
122 copyResourceFile("activetitlebar.gif");
123 copyResourceFile("activetitlebar_end.gif");
124 // do early to reduce memory footprint
125 if (configuration.classuse) {
126 ClassUseWriter.generate(configuration, classtree);
127 }
128 IndexBuilder indexbuilder = new IndexBuilder(configuration, nodeprecated);
130 if (configuration.createtree) {
131 TreeWriter.generate(configuration, classtree);
132 }
133 if (configuration.createindex) {
134 if (configuration.splitindex) {
135 SplitIndexWriter.generate(configuration, indexbuilder);
136 } else {
137 SingleIndexWriter.generate(configuration, indexbuilder);
138 }
139 }
141 if (!(configuration.nodeprecatedlist || nodeprecated)) {
142 DeprecatedListWriter.generate(configuration);
143 }
145 AllClassesFrameWriter.generate(configuration,
146 new IndexBuilder(configuration, nodeprecated, true));
148 FrameOutputWriter.generate(configuration);
150 if (configuration.createoverview) {
151 PackageIndexWriter.generate(configuration);
152 }
153 if (configuration.helpfile.length() == 0 &&
154 !configuration.nohelp) {
155 HelpWriter.generate(configuration);
156 }
157 // If a stylesheet file is not specified, copy the default stylesheet
158 // and replace newline with platform-specific newline.
159 DocFile f;
160 if (configuration.stylesheetfile.length() == 0) {
161 f = DocFile.createFileForOutput(configuration, DocPaths.STYLESHEET);
162 f.copyResource(DocPaths.RESOURCES.resolve(DocPaths.STYLESHEET), false, true);
163 }
164 f = DocFile.createFileForOutput(configuration, DocPaths.JAVASCRIPT);
165 f.copyResource(DocPaths.RESOURCES.resolve(DocPaths.JAVASCRIPT), true, true);
166 }
168 /**
169 * {@inheritDoc}
170 */
171 protected void generateClassFiles(ClassDoc[] arr, ClassTree classtree) {
172 Arrays.sort(arr);
173 for(int i = 0; i < arr.length; i++) {
174 if (!(configuration.isGeneratedDoc(arr[i]) && arr[i].isIncluded())) {
175 continue;
176 }
177 ClassDoc prev = (i == 0)?
178 null:
179 arr[i-1];
180 ClassDoc curr = arr[i];
181 ClassDoc next = (i+1 == arr.length)?
182 null:
183 arr[i+1];
184 try {
185 if (curr.isAnnotationType()) {
186 AbstractBuilder annotationTypeBuilder =
187 configuration.getBuilderFactory()
188 .getAnnotationTypeBuilder((AnnotationTypeDoc) curr,
189 prev, next);
190 annotationTypeBuilder.build();
191 } else {
192 AbstractBuilder classBuilder =
193 configuration.getBuilderFactory()
194 .getClassBuilder(curr, prev, next, classtree);
195 classBuilder.build();
196 }
197 } catch (IOException e) {
198 throw new DocletAbortException(e);
199 } catch (DocletAbortException de) {
200 throw de;
201 } catch (Exception e) {
202 e.printStackTrace();
203 throw new DocletAbortException(e);
204 }
205 }
206 }
208 /**
209 * {@inheritDoc}
210 */
211 protected void generateProfileFiles() throws Exception {
212 if (configuration.showProfiles && configuration.profilePackages.size() > 0) {
213 ProfileIndexFrameWriter.generate(configuration);
214 Profile prevProfile = null, nextProfile;
215 String profileName;
216 for (int i = 1; i < configuration.profiles.getProfileCount(); i++) {
217 profileName = Profile.lookup(i).name;
218 // Generate profile package pages only if there are any packages
219 // in a profile to be documented. The profilePackages map will not
220 // contain an entry for the profile if there are no packages to be documented.
221 if (!configuration.shouldDocumentProfile(profileName))
222 continue;
223 ProfilePackageIndexFrameWriter.generate(configuration, profileName);
224 PackageDoc[] packages = configuration.profilePackages.get(
225 profileName);
226 PackageDoc prev = null, next;
227 for (int j = 0; j < packages.length; j++) {
228 // if -nodeprecated option is set and the package is marked as
229 // deprecated, do not generate the profilename-package-summary.html
230 // and profilename-package-frame.html pages for that package.
231 if (!(configuration.nodeprecated && Util.isDeprecated(packages[j]))) {
232 ProfilePackageFrameWriter.generate(configuration, packages[j], i);
233 next = (j + 1 < packages.length
234 && packages[j + 1].name().length() > 0) ? packages[j + 1] : null;
235 AbstractBuilder profilePackageSummaryBuilder =
236 configuration.getBuilderFactory().getProfilePackageSummaryBuilder(
237 packages[j], prev, next, Profile.lookup(i));
238 profilePackageSummaryBuilder.build();
239 prev = packages[j];
240 }
241 }
242 nextProfile = (i + 1 < configuration.profiles.getProfileCount()) ?
243 Profile.lookup(i + 1) : null;
244 AbstractBuilder profileSummaryBuilder =
245 configuration.getBuilderFactory().getProfileSummaryBuilder(
246 Profile.lookup(i), prevProfile, nextProfile);
247 profileSummaryBuilder.build();
248 prevProfile = Profile.lookup(i);
249 }
250 }
251 }
253 /**
254 * {@inheritDoc}
255 */
256 protected void generatePackageFiles(ClassTree classtree) throws Exception {
257 PackageDoc[] packages = configuration.packages;
258 if (packages.length > 1) {
259 PackageIndexFrameWriter.generate(configuration);
260 }
261 PackageDoc prev = null, next;
262 for (int i = 0; i < packages.length; i++) {
263 // if -nodeprecated option is set and the package is marked as
264 // deprecated, do not generate the package-summary.html, package-frame.html
265 // and package-tree.html pages for that package.
266 if (!(configuration.nodeprecated && Util.isDeprecated(packages[i]))) {
267 PackageFrameWriter.generate(configuration, packages[i]);
268 next = (i + 1 < packages.length &&
269 packages[i + 1].name().length() > 0) ? packages[i + 1] : null;
270 //If the next package is unnamed package, skip 2 ahead if possible
271 next = (i + 2 < packages.length && next == null) ? packages[i + 2] : next;
272 AbstractBuilder packageSummaryBuilder =
273 configuration.getBuilderFactory().getPackageSummaryBuilder(
274 packages[i], prev, next);
275 packageSummaryBuilder.build();
276 if (configuration.createtree) {
277 PackageTreeWriter.generate(configuration,
278 packages[i], prev, next,
279 configuration.nodeprecated);
280 }
281 prev = packages[i];
282 }
283 }
284 }
286 public static final ConfigurationImpl sharedInstanceForOptions =
287 new ConfigurationImpl();
289 /**
290 * Check for doclet added options here.
291 *
292 * @return number of arguments to option. Zero return means
293 * option not known. Negative value means error occurred.
294 */
295 public static int optionLength(String option) {
296 // Construct temporary configuration for check
297 return sharedInstanceForOptions.optionLength(option);
298 }
300 /**
301 * Check that options have the correct arguments here.
302 * <P>
303 * This method is not required and will default gracefully
304 * (to true) if absent.
305 * <P>
306 * Printing option related error messages (using the provided
307 * DocErrorReporter) is the responsibility of this method.
308 *
309 * @return true if the options are valid.
310 */
311 public static boolean validOptions(String options[][],
312 DocErrorReporter reporter) {
313 docletToStart = new HtmlDoclet();
314 return docletToStart.configuration.validOptions(options, reporter);
315 }
317 /**
318 * Copy a file in the resources directory to the destination directory.
319 * @param resource The name of the resource file to copy
320 */
321 private void copyResourceFile(String resource) {
322 DocPath p = DocPaths.RESOURCES.resolve(resource);
323 DocFile f = DocFile.createFileForOutput(configuration, p);
324 f.copyResource(p, false, false);
325 }
327 private void performCopy(String filename) {
328 if (filename.isEmpty())
329 return;
331 try {
332 DocFile fromfile = DocFile.createFileForInput(configuration, filename);
333 DocPath path = DocPath.create(fromfile.getName());
334 DocFile toFile = DocFile.createFileForOutput(configuration, path);
335 if (toFile.isSameFile(fromfile))
336 return;
338 configuration.message.notice((SourcePosition) null,
339 "doclet.Copying_File_0_To_File_1",
340 fromfile.toString(), path.getPath());
341 toFile.copyFile(fromfile);
342 } catch (IOException exc) {
343 configuration.message.error((SourcePosition) null,
344 "doclet.perform_copy_exception_encountered",
345 exc.toString());
346 throw new DocletAbortException(exc);
347 }
348 }
349 }