1 /* 2 * Copyright (c) 1998, 2015, 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 26 package com.sun.tools.doclets.formats.html; 27 28 import java.net.*; 29 import java.util.*; 30 31 import javax.tools.JavaFileManager; 32 33 import com.sun.javadoc.*; 34 import com.sun.tools.doclets.formats.html.markup.*; 35 import com.sun.tools.doclets.internal.toolkit.*; 36 import com.sun.tools.doclets.internal.toolkit.util.*; 37 import com.sun.tools.doclint.DocLint; 38 import com.sun.tools.javac.file.JavacFileManager; 39 import com.sun.tools.javac.util.Context; 40 import com.sun.tools.javac.util.StringUtils; 41 import com.sun.tools.javadoc.RootDocImpl; 42 43 /** 44 * Configure the output based on the command line options. 45 * <p> 46 * Also determine the length of the command line option. For example, 47 * for a option "-header" there will be a string argument associated, then the 48 * the length of option "-header" is two. But for option "-nohelp" no argument 49 * is needed so it's length is 1. 50 * </p> 51 * <p> 52 * Also do the error checking on the options used. For example it is illegal to 53 * use "-helpfile" option when already "-nohelp" option is used. 54 * </p> 55 * 56 * <p><b>This is NOT part of any supported API. 57 * If you write code that depends on this, you do so at your own risk. 58 * This code and its internal interfaces are subject to change or 59 * deletion without notice.</b> 60 * 61 * @author Robert Field. 62 * @author Atul Dambalkar. 63 * @author Jamie Ho 64 * @author Bhavesh Patel (Modified) 65 */ 66 public class ConfigurationImpl extends Configuration { 67 68 /** 69 * The build date. Note: For now, we will use 70 * a version number instead of a date. 71 */ 72 public static final String BUILD_DATE = System.getProperty("java.version"); 73 74 /** 75 * Argument for command line option "-header". 76 */ 77 public String header = ""; 78 79 /** 80 * Argument for command line option "-packagesheader". 81 */ 82 public String packagesheader = ""; 83 84 /** 85 * Argument for command line option "-footer". 86 */ 87 public String footer = ""; 88 89 /** 90 * Argument for command line option "-doctitle". 91 */ 92 public String doctitle = ""; 93 94 /** 95 * Argument for command line option "-windowtitle". 96 */ 97 public String windowtitle = ""; 98 99 /** 100 * Argument for command line option "-top". 101 */ 102 public String top = ""; 103 104 /** 105 * Argument for command line option "-bottom". 106 */ 107 public String bottom = ""; 108 109 /** 110 * Argument for command line option "-helpfile". 111 */ 112 public String helpfile = ""; 113 114 /** 115 * Argument for command line option "-stylesheetfile". 116 */ 117 public String stylesheetfile = ""; 118 119 /** 120 * Argument for command line option "-Xdocrootparent". 121 */ 122 public String docrootparent = ""; 123 124 /** 125 * True if command line option "-nohelp" is used. Default value is false. 126 */ 127 public boolean nohelp = false; 128 129 /** 130 * True if command line option "-splitindex" is used. Default value is 131 * false. 132 */ 133 public boolean splitindex = false; 134 135 /** 136 * False if command line option "-noindex" is used. Default value is true. 137 */ 138 public boolean createindex = true; 139 140 /** 141 * True if command line option "-use" is used. Default value is false. 142 */ 143 public boolean classuse = false; 144 145 /** 146 * False if command line option "-notree" is used. Default value is true. 147 */ 148 public boolean createtree = true; 149 150 /** 151 * True if command line option "-nodeprecated" is used. Default value is 152 * false. 153 */ 154 public boolean nodeprecatedlist = false; 155 156 /** 157 * True if command line option "-nonavbar" is used. Default value is false. 158 */ 159 public boolean nonavbar = false; 160 161 /** 162 * True if command line option "-nooverview" is used. Default value is 163 * false 164 */ 165 private boolean nooverview = false; 166 167 /** 168 * True if command line option "-overview" is used. Default value is false. 169 */ 170 public boolean overview = false; 171 172 /** 173 * This is true if option "-overview" is used or option "-overview" is not 174 * used and number of packages is more than one. 175 */ 176 public boolean createoverview = false; 177 178 /** 179 * This is the HTML version of the generated pages. HTML 4.01 is the default output version. 180 */ 181 public HtmlVersion htmlVersion = HtmlVersion.HTML4; 182 183 /** 184 * Collected set of doclint options 185 */ 186 public Set<String> doclintOpts = new LinkedHashSet<>(); 187 188 /** 189 * Unique Resource Handler for this package. 190 */ 191 public final MessageRetriever standardmessage; 192 193 /** 194 * First file to appear in the right-hand frame in the generated 195 * documentation. 196 */ 197 public DocPath topFile = DocPath.empty; 198 199 /** 200 * The classdoc for the class file getting generated. 201 */ 202 public ClassDoc currentcd = null; // Set this classdoc in the ClassWriter. 203 204 protected List<SearchIndexItem> memberSearchIndex = new ArrayList<>(); 205 206 protected List<SearchIndexItem> packageSearchIndex = new ArrayList<>(); 207 208 protected List<SearchIndexItem> tagSearchIndex = new ArrayList<>(); 209 210 protected List<SearchIndexItem> typeSearchIndex = new ArrayList<>(); 211 212 protected Map<Character,List<SearchIndexItem>> tagSearchIndexMap = new HashMap<>(); 213 214 protected Set<Character> tagSearchIndexKeys; 215 216 /** 217 * Constructor. Initializes resource for the 218 * {@link com.sun.tools.doclets.internal.toolkit.util.MessageRetriever MessageRetriever}. 219 */ 220 public ConfigurationImpl() { 221 standardmessage = new MessageRetriever(this, 222 "com.sun.tools.doclets.formats.html.resources.standard"); 223 } 224 225 private final String versionRBName = "com.sun.tools.javadoc.resources.version"; 226 private ResourceBundle versionRB; 227 228 /** 229 * Return the build date for the doclet. 230 */ 231 @Override 232 public String getDocletSpecificBuildDate() { 233 if (versionRB == null) { 234 try { 235 versionRB = ResourceBundle.getBundle(versionRBName); 236 } catch (MissingResourceException e) { 237 return BUILD_DATE; 238 } 239 } 240 241 try { 242 return versionRB.getString("release"); 243 } catch (MissingResourceException e) { 244 return BUILD_DATE; 245 } 246 } 247 248 /** 249 * Depending upon the command line options provided by the user, set 250 * configure the output generation environment. 251 * 252 * @param options The array of option names and values. 253 */ 254 @Override 255 public void setSpecificDocletOptions(String[][] options) { 256 for (int oi = 0; oi < options.length; ++oi) { 257 String[] os = options[oi]; 258 String opt = StringUtils.toLowerCase(os[0]); 259 if (opt.equals("-footer")) { 260 footer = os[1]; 261 } else if (opt.equals("-header")) { 262 header = os[1]; 263 } else if (opt.equals("-packagesheader")) { 264 packagesheader = os[1]; 265 } else if (opt.equals("-doctitle")) { 266 doctitle = os[1]; 267 } else if (opt.equals("-windowtitle")) { 268 windowtitle = os[1].replaceAll("\\<.*?>", ""); 269 } else if (opt.equals("-top")) { 270 top = os[1]; 271 } else if (opt.equals("-bottom")) { 272 bottom = os[1]; 273 } else if (opt.equals("-helpfile")) { 274 helpfile = os[1]; 275 } else if (opt.equals("-stylesheetfile")) { 276 stylesheetfile = os[1]; 277 } else if (opt.equals("-charset")) { 278 charset = os[1]; 279 } else if (opt.equals("-xdocrootparent")) { 280 docrootparent = os[1]; 281 } else if (opt.equals("-nohelp")) { 282 nohelp = true; 283 } else if (opt.equals("-splitindex")) { 284 splitindex = true; 285 } else if (opt.equals("-noindex")) { 286 createindex = false; 287 } else if (opt.equals("-use")) { 288 classuse = true; 289 } else if (opt.equals("-notree")) { 290 createtree = false; 291 } else if (opt.equals("-nodeprecatedlist")) { 292 nodeprecatedlist = true; 293 } else if (opt.equals("-nonavbar")) { 294 nonavbar = true; 295 } else if (opt.equals("-nooverview")) { 296 nooverview = true; 297 } else if (opt.equals("-overview")) { 298 overview = true; 299 } else if (opt.equals("-html4")) { 300 htmlVersion = HtmlVersion.HTML4; 301 } else if (opt.equals("-html5")) { 302 htmlVersion = HtmlVersion.HTML5; 303 } else if (opt.equals("-xdoclint")) { 304 doclintOpts.add(DocLint.XMSGS_OPTION); 305 } else if (opt.startsWith("-xdoclint:")) { 306 doclintOpts.add(DocLint.XMSGS_CUSTOM_PREFIX + opt.substring(opt.indexOf(":") + 1)); 307 } else if (opt.startsWith("-xdoclint/package:")) { 308 doclintOpts.add(DocLint.XCHECK_PACKAGE + opt.substring(opt.indexOf(":") + 1)); 309 } 310 } 311 if (root.specifiedClasses().length > 0) { 312 Map<String,PackageDoc> map = new HashMap<>(); 313 PackageDoc pd; 314 ClassDoc[] classes = root.classes(); 315 for (ClassDoc aClass : classes) { 316 pd = aClass.containingPackage(); 317 if (!map.containsKey(pd.name())) { 318 map.put(pd.name(), pd); 319 } 320 } 321 } 322 setCreateOverview(); 323 setTopFile(root); 324 325 if (root instanceof RootDocImpl) { 326 ((RootDocImpl) root).initDocLint(doclintOpts, tagletManager.getCustomTagNames(), 327 StringUtils.toLowerCase(htmlVersion.name())); 328 } 329 } 330 331 /** 332 * Returns the "length" of a given option. If an option takes no 333 * arguments, its length is one. If it takes one argument, it's 334 * length is two, and so on. This method is called by JavaDoc to 335 * parse the options it does not recognize. It then calls 336 * {@link #validOptions(String[][], DocErrorReporter)} to 337 * validate them. 338 * <b>Note:</b><br> 339 * The options arrive as case-sensitive strings. For options that 340 * are not case-sensitive, use toLowerCase() on the option string 341 * before comparing it. 342 * 343 * @return number of arguments + 1 for a option. Zero return means 344 * option not known. Negative value means error occurred. 345 */ 346 public int optionLength(String option) { 347 int result = -1; 348 if ((result = super.optionLength(option)) > 0) { 349 return result; 350 } 351 // otherwise look for the options we have added 352 option = StringUtils.toLowerCase(option); 353 if (option.equals("-nodeprecatedlist") || 354 option.equals("-noindex") || 355 option.equals("-notree") || 356 option.equals("-nohelp") || 357 option.equals("-splitindex") || 358 option.equals("-serialwarn") || 359 option.equals("-use") || 360 option.equals("-nonavbar") || 361 option.equals("-nooverview") || 362 option.equals("-html4") || 363 option.equals("-html5") || 364 option.equals("-xdoclint") || 365 option.startsWith("-xdoclint:") || 366 option.startsWith("-xdoclint/package:")) { 367 return 1; 368 } else if (option.equals("-help")) { 369 // Uugh: first, this should not be hidden inside optionLength, 370 // and second, we should not be writing directly to stdout. 371 // But we have no access to a DocErrorReporter, which would 372 // allow use of reporter.printNotice 373 System.out.println(getText("doclet.usage")); 374 return 1; 375 } else if (option.equals("-x")) { 376 // Uugh: first, this should not be hidden inside optionLength, 377 // and second, we should not be writing directly to stdout. 378 // But we have no access to a DocErrorReporter, which would 379 // allow use of reporter.printNotice 380 System.out.println(getText("doclet.X.usage")); 381 return 1; 382 } else if (option.equals("-footer") || 383 option.equals("-header") || 384 option.equals("-packagesheader") || 385 option.equals("-doctitle") || 386 option.equals("-windowtitle") || 387 option.equals("-top") || 388 option.equals("-bottom") || 389 option.equals("-helpfile") || 390 option.equals("-stylesheetfile") || 391 option.equals("-charset") || 392 option.equals("-overview") || 393 option.equals("-xdocrootparent")) { 394 return 2; 395 } else { 396 return 0; 397 } 398 } 399 400 /** 401 * {@inheritDoc} 402 */ 403 @Override 404 public boolean validOptions(String options[][], 405 DocErrorReporter reporter) { 406 boolean helpfile = false; 407 boolean nohelp = false; 408 boolean overview = false; 409 boolean nooverview = false; 410 boolean splitindex = false; 411 boolean noindex = false; 412 // check shared options 413 if (!generalValidOptions(options, reporter)) { 414 return false; 415 } 416 // otherwise look at our options 417 for (int oi = 0; oi < options.length; ++oi) { 418 String[] os = options[oi]; 419 String opt = StringUtils.toLowerCase(os[0]); 420 if (opt.equals("-helpfile")) { 421 if (nohelp == true) { 422 reporter.printError(getText("doclet.Option_conflict", 423 "-helpfile", "-nohelp")); 424 return false; 425 } 426 if (helpfile == true) { 427 reporter.printError(getText("doclet.Option_reuse", 428 "-helpfile")); 429 return false; 430 } 431 DocFile help = DocFile.createFileForInput(this, os[1]); 432 if (!help.exists()) { 433 reporter.printError(getText("doclet.File_not_found", os[1])); 434 return false; 435 } 436 helpfile = true; 437 } else if (opt.equals("-nohelp")) { 438 if (helpfile == true) { 439 reporter.printError(getText("doclet.Option_conflict", 440 "-nohelp", "-helpfile")); 441 return false; 442 } 443 nohelp = true; 444 } else if (opt.equals("-xdocrootparent")) { 445 try { 446 new URL(os[1]); 447 } catch (MalformedURLException e) { 448 reporter.printError(getText("doclet.MalformedURL", os[1])); 449 return false; 450 } 451 } else if (opt.equals("-overview")) { 452 if (nooverview == true) { 453 reporter.printError(getText("doclet.Option_conflict", 454 "-overview", "-nooverview")); 455 return false; 456 } 457 if (overview == true) { 458 reporter.printError(getText("doclet.Option_reuse", 459 "-overview")); 460 return false; 461 } 462 overview = true; 463 } else if (opt.equals("-nooverview")) { 464 if (overview == true) { 465 reporter.printError(getText("doclet.Option_conflict", 466 "-nooverview", "-overview")); 467 return false; 468 } 469 nooverview = true; 470 } else if (opt.equals("-splitindex")) { 471 if (noindex == true) { 472 reporter.printError(getText("doclet.Option_conflict", 473 "-splitindex", "-noindex")); 474 return false; 475 } 476 splitindex = true; 477 } else if (opt.equals("-noindex")) { 478 if (splitindex == true) { 479 reporter.printError(getText("doclet.Option_conflict", 480 "-noindex", "-splitindex")); 481 return false; 482 } 483 noindex = true; 484 } else if (opt.startsWith("-xdoclint:")) { 485 if (opt.contains("/")) { 486 reporter.printError(getText("doclet.Option_doclint_no_qualifiers")); 487 return false; 488 } 489 if (!DocLint.isValidOption( 490 opt.replace("-xdoclint:", DocLint.XMSGS_CUSTOM_PREFIX))) { 491 reporter.printError(getText("doclet.Option_doclint_invalid_arg")); 492 return false; 493 } 494 } else if (opt.startsWith("-xdoclint/package:")) { 495 if (!DocLint.isValidOption( 496 opt.replace("-xdoclint/package:", DocLint.XCHECK_PACKAGE))) { 497 reporter.printError(getText("doclet.Option_doclint_package_invalid_arg")); 498 return false; 499 } 500 } 501 } 502 return true; 503 } 504 505 /** 506 * Return true if the generated output is HTML5. 507 */ 508 public boolean isOutputHtml5() { 509 return htmlVersion == HtmlVersion.HTML5; 510 } 511 512 /** 513 * Return true if the tag is allowed for this specific version of HTML. 514 */ 515 public boolean allowTag(HtmlTag htmlTag) { 516 return htmlTag.allowTag(this.htmlVersion); 517 } 518 519 /** 520 * {@inheritDoc} 521 */ 522 @Override 523 public MessageRetriever getDocletSpecificMsg() { 524 return standardmessage; 525 } 526 527 /** 528 * Decide the page which will appear first in the right-hand frame. It will 529 * be "overview-summary.html" if "-overview" option is used or no 530 * "-overview" but the number of packages is more than one. It will be 531 * "package-summary.html" of the respective package if there is only one 532 * package to document. It will be a class page(first in the sorted order), 533 * if only classes are provided on the command line. 534 * 535 * @param root Root of the program structure. 536 */ 537 protected void setTopFile(RootDoc root) { 538 if (!checkForDeprecation(root)) { 539 return; 540 } 541 if (createoverview) { 542 topFile = DocPaths.OVERVIEW_SUMMARY; 543 } else { 544 if (packages.size() == 1 && packages.first().name().equals("")) { 545 if (root.classes().length > 0) { 546 ClassDoc[] classarr = root.classes(); 547 Arrays.sort(classarr); 548 ClassDoc cd = getValidClass(classarr); 549 topFile = DocPath.forClass(cd); 550 } 551 } else if (!packages.isEmpty()) { 552 topFile = DocPath.forPackage(packages.first()).resolve(DocPaths.PACKAGE_SUMMARY); 553 } 554 } 555 } 556 557 protected ClassDoc getValidClass(ClassDoc[] classarr) { 558 if (!nodeprecated) { 559 return classarr[0]; 560 } 561 for (ClassDoc cd : classarr) { 562 if (cd.tags("deprecated").length == 0) { 563 return cd; 564 } 565 } 566 return null; 567 } 568 569 protected boolean checkForDeprecation(RootDoc root) { 570 for (ClassDoc cd : root.classes()) { 571 if (isGeneratedDoc(cd)) { 572 return true; 573 } 574 } 575 return false; 576 } 577 578 /** 579 * Generate "overview.html" page if option "-overview" is used or number of 580 * packages is more than one. Sets {@link #createoverview} field to true. 581 */ 582 protected void setCreateOverview() { 583 if ((overview || packages.size() > 1) && !nooverview) { 584 createoverview = true; 585 } 586 } 587 588 /** 589 * {@inheritDoc} 590 */ 591 @Override 592 public WriterFactory getWriterFactory() { 593 return new WriterFactoryImpl(this); 594 } 595 596 /** 597 * {@inheritDoc} 598 */ 599 @Override 600 public Comparator<ProgramElementDoc> getMemberComparator() { 601 return null; 602 } 603 604 /** 605 * {@inheritDoc} 606 */ 607 @Override 608 public Locale getLocale() { 609 if (root instanceof RootDocImpl) 610 return ((RootDocImpl)root).getLocale(); 611 else 612 return Locale.getDefault(); 613 } 614 615 /** 616 * {@inheritDoc} 617 */ 618 @Override 619 public JavaFileManager getFileManager() { 620 if (fileManager == null) { 621 if (root instanceof RootDocImpl) 622 fileManager = ((RootDocImpl) root).getFileManager(); 623 else 624 fileManager = new JavacFileManager(new Context(), false, null); 625 } 626 return fileManager; 627 } 628 629 private JavaFileManager fileManager; 630 631 @Override 632 public boolean showMessage(SourcePosition pos, String key) { 633 if (root instanceof RootDocImpl) { 634 return pos == null || ((RootDocImpl) root).showTagMessages(); 635 } 636 return true; 637 } 638 639 @Override 640 public Content newContent() { 641 return new ContentBuilder(); 642 } 643 644 protected void buildSearchTagIndex() { 645 for (SearchIndexItem sii : tagSearchIndex) { 646 String tagLabel = sii.getLabel(); 647 char ch = (tagLabel.length() == 0) 648 ? '*' 649 : Character.toUpperCase(tagLabel.charAt(0)); 650 Character unicode = ch; 651 List<SearchIndexItem> list = tagSearchIndexMap.get(unicode); 652 if (list == null) { 653 list = new ArrayList<>(); 654 tagSearchIndexMap.put(unicode, list); 655 } 656 list.add(sii); 657 } 658 tagSearchIndexKeys = tagSearchIndexMap.keySet(); 659 } 660 }