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