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 26package com.sun.tools.doclets.internal.toolkit; 27 28import java.io.*; 29import java.util.*; 30import java.util.regex.Matcher; 31import java.util.regex.Pattern; 32 33import javax.tools.JavaFileManager; 34import javax.tools.JavaFileManager.Location; 35 36import com.sun.javadoc.*; 37import com.sun.tools.doclets.internal.toolkit.builders.BuilderFactory; 38import com.sun.tools.doclets.internal.toolkit.taglets.*; 39import com.sun.tools.doclets.internal.toolkit.util.*; 40import com.sun.tools.javac.util.StringUtils; 41 42/** 43 * Configure the output based on the options. Doclets should sub-class 44 * Configuration, to configure and add their own options. This class contains 45 * all user options which are supported by the 1.1 doclet and the standard 46 * doclet. 47 * 48 * <p><b>This is NOT part of any supported API. 49 * If you write code that depends on this, you do so at your own risk. 50 * This code and its internal interfaces are subject to change or 51 * deletion without notice.</b> 52 * 53 * @author Robert Field. 54 * @author Atul Dambalkar. 55 * @author Jamie Ho 56 */ 57@Deprecated 58public abstract class Configuration { 59 60 /** 61 * Exception used to report a problem during setOptions. 62 */ 63 public static class Fault extends Exception { 64 private static final long serialVersionUID = 0; 65 66 Fault(String msg) { 67 super(msg); 68 } 69 70 Fault(String msg, Exception cause) { 71 super(msg, cause); 72 } 73 } 74 75 /** 76 * The factory for builders. 77 */ 78 protected BuilderFactory builderFactory; 79 80 /** 81 * The taglet manager. 82 */ 83 public TagletManager tagletManager; 84 85 /** 86 * The path to the builder XML input file. 87 */ 88 public String builderXMLPath; 89 90 /** 91 * The default path to the builder XML. 92 */ 93 private static final String DEFAULT_BUILDER_XML = "resources/doclet.xml"; 94 95 /** 96 * The path to Taglets 97 */ 98 public String tagletpath = ""; 99 100 /** 101 * This is true if option "-serialwarn" is used. Defualt value is false to 102 * suppress excessive warnings about serial tag. 103 */ 104 public boolean serialwarn = false; 105 106 /** 107 * The specified amount of space between tab stops. 108 */ 109 public int sourcetab; 110 111 public String tabSpaces; 112 113 /** 114 * True if we should generate browsable sources. 115 */ 116 public boolean linksource = false; 117 118 /** 119 * True if command line option "-nosince" is used. Default value is 120 * false. 121 */ 122 public boolean nosince = false; 123 124 /** 125 * True if we should recursively copy the doc-file subdirectories 126 */ 127 public boolean copydocfilesubdirs = false; 128 129 /** 130 * The META charset tag used for cross-platform viewing. 131 */ 132 public String charset = ""; 133 134 /** 135 * True if user wants to add member names as meta keywords. 136 * Set to false because meta keywords are ignored in general 137 * by most Internet search engines. 138 */ 139 public boolean keywords = false; 140 141 /** 142 * The meta tag keywords instance. 143 */ 144 public final MetaKeywords metakeywords; 145 146 /** 147 * The list of doc-file subdirectories to exclude 148 */ 149 protected Set<String> excludedDocFileDirs; 150 151 /** 152 * The list of qualifiers to exclude 153 */ 154 protected Set<String> excludedQualifiers; 155 156 /** 157 * The Root of the generated Program Structure from the Doclet API. 158 */ 159 public RootDoc root; 160 161 /** 162 * An utility class for commonly used helpers 163 */ 164 public Utils utils; 165 /** 166 * Destination directory name, in which doclet will generate the entire 167 * documentation. Default is current directory. 168 */ 169 public String destDirName = ""; 170 171 /** 172 * Destination directory name, in which doclet will copy the doc-files to. 173 */ 174 public String docFileDestDirName = ""; 175 176 /** 177 * Encoding for this document. Default is default encoding for this 178 * platform. 179 */ 180 public String docencoding = null; 181 182 /** 183 * True if user wants to suppress descriptions and tags. 184 */ 185 public boolean nocomment = false; 186 187 /** 188 * Encoding for this document. Default is default encoding for this 189 * platform. 190 */ 191 public String encoding = null; 192 193 /** 194 * Generate author specific information for all the classes if @author 195 * tag is used in the doc comment and if -author option is used. 196 * <code>showauthor</code> is set to true if -author option is used. 197 * Default is don't show author information. 198 */ 199 public boolean showauthor = false; 200 201 /** 202 * Generate documentation for JavaFX getters and setters automatically 203 * by copying it from the appropriate property definition. 204 */ 205 public boolean javafx = false; 206 207 /** 208 * Generate version specific information for the all the classes 209 * if @version tag is used in the doc comment and if -version option is 210 * used. <code>showversion</code> is set to true if -version option is 211 * used.Default is don't show version information. 212 */ 213 public boolean showversion = false; 214 215 /** 216 * Don't generate deprecated API information at all, if -nodeprecated 217 * option is used. <code>nodepracted</code> is set to true if 218 * -nodeprecated option is used. Default is generate deprected API 219 * information. 220 */ 221 public boolean nodeprecated = false; 222 223 /** 224 * The catalog of classes specified on the command-line 225 */ 226 public ClassDocCatalog classDocCatalog; 227 228 /** 229 * Message Retriever for the doclet, to retrieve message from the resource 230 * file for this Configuration, which is common for 1.1 and standard 231 * doclets. 232 * 233 * TODO: Make this private!!! 234 */ 235 public MessageRetriever message = null; 236 237 /** 238 * True if user wants to suppress time stamp in output. 239 * Default is false. 240 */ 241 public boolean notimestamp= false; 242 243 /** 244 * The package grouping instance. 245 */ 246 public final Group group = new Group(this); 247 248 /** 249 * The tracker of external package links. 250 */ 251 public final Extern extern = new Extern(this); 252 253 /** 254 * Return the build date for the doclet. 255 */ 256 public abstract String getDocletSpecificBuildDate(); 257 258 /** 259 * This method should be defined in all those doclets(configurations), 260 * which want to derive themselves from this Configuration. This method 261 * can be used to set its own command line options. 262 * 263 * @param options The array of option names and values. 264 * @throws DocletAbortException 265 */ 266 public abstract void setSpecificDocletOptions(String[][] options) throws Fault; 267 268 /** 269 * Return the doclet specific {@link MessageRetriever} 270 * @return the doclet specific MessageRetriever. 271 */ 272 public abstract MessageRetriever getDocletSpecificMsg(); 273 274 /** 275 * A sorted set of packages specified on the command-line merged with a 276 * collection of packages that contain the classes specified on the 277 * command-line. 278 */ 279 public SortedSet<PackageDoc> packages; 280 281 public boolean exportInternalAPI; 282 283 /** 284 * Constructor. Constructs the message retriever with resource file. 285 */ 286 public Configuration() { 287 message = 288 new MessageRetriever(this, 289 "com.sun.tools.doclets.internal.toolkit.resources.doclets"); 290 excludedDocFileDirs = new HashSet<>(); 291 excludedQualifiers = new HashSet<>(); 292 setTabWidth(DocletConstants.DEFAULT_TAB_STOP_LENGTH); 293 utils = new Utils(); 294 metakeywords = new MetaKeywords(this); 295 } 296 297 /** 298 * Return the builder factory for this doclet. 299 * 300 * @return the builder factory for this doclet. 301 */ 302 public BuilderFactory getBuilderFactory() { 303 if (builderFactory == null) { 304 builderFactory = new BuilderFactory(this); 305 } 306 return builderFactory; 307 } 308 309 /** 310 * This method should be defined in all those doclets 311 * which want to inherit from this Configuration. This method 312 * should return the number of arguments to the command line 313 * option (including the option name). For example, 314 * -notimestamp is a single-argument option, so this method would 315 * return 1. 316 * 317 * @param option Command line option under consideration. 318 * @return number of arguments to option (including the 319 * option name). Zero return means option not known. 320 * Negative value means error occurred. 321 */ 322 public int optionLength(String option) { 323 option = StringUtils.toLowerCase(option); 324 switch (option) { 325 case "-author": 326 case "-docfilessubdirs": 327 case "-javafx": 328 case "-keywords": 329 case "-linksource": 330 case "-nocomment": 331 case "-nodeprecated": 332 case "-nosince": 333 case "-notimestamp": 334 case "-quiet": 335 case "-xnodate": 336 case "-version": 337 case "-xdaccessinternalapi": 338 return 1; 339 case "-d": 340 case "-docencoding": 341 case "-encoding": 342 case "-excludedocfilessubdir": 343 case "-link": 344 case "-sourcetab": 345 case "-noqualifier": 346 case "-output": 347 case "-sourcepath": 348 case "-tag": 349 case "-taglet": 350 case "-tagletpath": 351 return 2; 352 case "-group": 353 case "-linkoffline": 354 return 3; 355 default: 356 return -1; // indicate we don't know about it 357 } 358 } 359 360 /** 361 * Perform error checking on the given options. 362 * 363 * @param options the given options to check. 364 * @param reporter the reporter used to report errors. 365 */ 366 public abstract boolean validOptions(String options[][], 367 DocErrorReporter reporter); 368 369 private void initPackages() { 370 packages = new TreeSet<>(Arrays.asList(root.specifiedPackages())); 371 for (ClassDoc aClass : root.specifiedClasses()) { 372 packages.add(aClass.containingPackage()); 373 } 374 } 375 376 /** 377 * Set the command line options supported by this configuration. 378 * 379 * @param options the two dimensional array of options. 380 */ 381 public void setOptions(String[][] options) throws Fault { 382 LinkedHashSet<String[]> customTagStrs = new LinkedHashSet<>(); 383 384 // Some options, specifically -link and -linkoffline, require that 385 // the output directory has already been created: so do that first. 386 for (String[] os : options) { 387 String opt = StringUtils.toLowerCase(os[0]); 388 if (opt.equals("-d")) { 389 destDirName = addTrailingFileSep(os[1]); 390 docFileDestDirName = destDirName; 391 ensureOutputDirExists(); 392 break; 393 } 394 } 395 396 for (String[] os : options) { 397 String opt = StringUtils.toLowerCase(os[0]); 398 if (opt.equals("-docfilessubdirs")) { 399 copydocfilesubdirs = true; 400 } else if (opt.equals("-docencoding")) { 401 docencoding = os[1]; 402 } else if (opt.equals("-encoding")) { 403 encoding = os[1]; 404 } else if (opt.equals("-author")) { 405 showauthor = true; 406 } else if (opt.equals("-javafx")) { 407 javafx = true; 408 } else if (opt.equals("-nosince")) { 409 nosince = true; 410 } else if (opt.equals("-version")) { 411 showversion = true; 412 } else if (opt.equals("-nodeprecated")) { 413 nodeprecated = true; 414 } else if (opt.equals("-excludedocfilessubdir")) { 415 addToSet(excludedDocFileDirs, os[1]); 416 } else if (opt.equals("-noqualifier")) { 417 addToSet(excludedQualifiers, os[1]); 418 } else if (opt.equals("-linksource")) { 419 linksource = true; 420 } else if (opt.equals("-sourcetab")) { 421 linksource = true; 422 try { 423 setTabWidth(Integer.parseInt(os[1])); 424 } catch (NumberFormatException e) { 425 //Set to -1 so that warning will be printed 426 //to indicate what is valid argument. 427 sourcetab = -1; 428 } 429 if (sourcetab <= 0) { 430 message.warning("doclet.sourcetab_warning"); 431 setTabWidth(DocletConstants.DEFAULT_TAB_STOP_LENGTH); 432 } 433 } else if (opt.equals("-notimestamp")) { 434 notimestamp = true; 435 } else if (opt.equals("-nocomment")) { 436 nocomment = true; 437 } else if (opt.equals("-tag") || opt.equals("-taglet")) { 438 customTagStrs.add(os); 439 } else if (opt.equals("-tagletpath")) { 440 tagletpath = os[1]; 441 } else if (opt.equals("-keywords")) { 442 keywords = true; 443 } else if (opt.equals("-serialwarn")) { 444 serialwarn = true; 445 } else if (opt.equals("-group")) { 446 group.checkPackageGroups(os[1], os[2]); 447 } else if (opt.equals("-link")) { 448 String url = os[1]; 449 extern.link(url, url, root, false); 450 } else if (opt.equals("-linkoffline")) { 451 String url = os[1]; 452 String pkglisturl = os[2]; 453 extern.link(url, pkglisturl, root, true); 454 } else if (opt.equals("-xdaccessinternalapi")) { 455 exportInternalAPI = true; 456 } 457 } 458 if (docencoding == null) { 459 docencoding = encoding; 460 } 461 462 classDocCatalog = new ClassDocCatalog(root.specifiedClasses(), this); 463 initTagletManager(customTagStrs); 464 } 465 466 /** 467 * Set the command line options supported by this configuration. 468 * 469 * @throws DocletAbortException 470 */ 471 public void setOptions() throws Fault { 472 initPackages(); 473 setOptions(root.options()); 474 setSpecificDocletOptions(root.options()); 475 } 476 477 private void ensureOutputDirExists() throws Fault { 478 DocFile destDir = DocFile.createFileForDirectory(this, destDirName); 479 if (!destDir.exists()) { 480 //Create the output directory (in case it doesn't exist yet) 481 root.printNotice(getText("doclet.dest_dir_create", destDirName)); 482 destDir.mkdirs(); 483 } else if (!destDir.isDirectory()) { 484 throw new Fault(getText( 485 "doclet.destination_directory_not_directory_0", 486 destDir.getPath())); 487 } else if (!destDir.canWrite()) { 488 throw new Fault(getText( 489 "doclet.destination_directory_not_writable_0", 490 destDir.getPath())); 491 } 492 } 493 494 495 /** 496 * Initialize the taglet manager. The strings to initialize the simple custom tags should 497 * be in the following format: "[tag name]:[location str]:[heading]". 498 * @param customTagStrs the set two dimensional arrays of strings. These arrays contain 499 * either -tag or -taglet arguments. 500 */ 501 private void initTagletManager(Set<String[]> customTagStrs) { 502 tagletManager = (tagletManager == null) 503 ? new TagletManager(nosince, showversion, showauthor, javafx, exportInternalAPI, message) 504 : tagletManager; 505 for (String[] args : customTagStrs) { 506 if (args[0].equals("-taglet")) { 507 tagletManager.addCustomTag(args[1], getFileManager(), tagletpath); 508 continue; 509 } 510 String[] tokens = tokenize(args[1], 511 TagletManager.SIMPLE_TAGLET_OPT_SEPARATOR, 3); 512 if (tokens.length == 1) { 513 String tagName = args[1]; 514 if (tagletManager.isKnownCustomTag(tagName)) { 515 //reorder a standard tag 516 tagletManager.addNewSimpleCustomTag(tagName, null, ""); 517 } else { 518 //Create a simple tag with the heading that has the same name as the tag. 519 StringBuilder heading = new StringBuilder(tagName + ":"); 520 heading.setCharAt(0, Character.toUpperCase(tagName.charAt(0))); 521 tagletManager.addNewSimpleCustomTag(tagName, heading.toString(), "a"); 522 } 523 } else if (tokens.length == 2) { 524 //Add simple taglet without heading, probably to excluding it in the output. 525 tagletManager.addNewSimpleCustomTag(tokens[0], tokens[1], ""); 526 } else if (tokens.length >= 3) { 527 tagletManager.addNewSimpleCustomTag(tokens[0], tokens[2], tokens[1]); 528 } else { 529 message.error("doclet.Error_invalid_custom_tag_argument", args[1]); 530 } 531 } 532 } 533 534 /** 535 * Given a string, return an array of tokens. The separator can be escaped 536 * with the '\' character. The '\' character may also be escaped by the 537 * '\' character. 538 * 539 * @param s the string to tokenize. 540 * @param separator the separator char. 541 * @param maxTokens the maximum number of tokens returned. If the 542 * max is reached, the remaining part of s is appended 543 * to the end of the last token. 544 * 545 * @return an array of tokens. 546 */ 547 private String[] tokenize(String s, char separator, int maxTokens) { 548 List<String> tokens = new ArrayList<>(); 549 StringBuilder token = new StringBuilder (); 550 boolean prevIsEscapeChar = false; 551 for (int i = 0; i < s.length(); i += Character.charCount(i)) { 552 int currentChar = s.codePointAt(i); 553 if (prevIsEscapeChar) { 554 // Case 1: escaped character 555 token.appendCodePoint(currentChar); 556 prevIsEscapeChar = false; 557 } else if (currentChar == separator && tokens.size() < maxTokens-1) { 558 // Case 2: separator 559 tokens.add(token.toString()); 560 token = new StringBuilder(); 561 } else if (currentChar == '\\') { 562 // Case 3: escape character 563 prevIsEscapeChar = true; 564 } else { 565 // Case 4: regular character 566 token.appendCodePoint(currentChar); 567 } 568 } 569 if (token.length() > 0) { 570 tokens.add(token.toString()); 571 } 572 return tokens.toArray(new String[] {}); 573 } 574 575 private void addToSet(Set<String> s, String str){ 576 StringTokenizer st = new StringTokenizer(str, ":"); 577 String current; 578 while(st.hasMoreTokens()){ 579 current = st.nextToken(); 580 s.add(current); 581 } 582 } 583 584 /** 585 * Add a trailing file separator, if not found. Remove superfluous 586 * file separators if any. Preserve the front double file separator for 587 * UNC paths. 588 * 589 * @param path Path under consideration. 590 * @return String Properly constructed path string. 591 */ 592 public static String addTrailingFileSep(String path) { 593 String fs = System.getProperty("file.separator"); 594 String dblfs = fs + fs; 595 int indexDblfs; 596 while ((indexDblfs = path.indexOf(dblfs, 1)) >= 0) { 597 path = path.substring(0, indexDblfs) + 598 path.substring(indexDblfs + fs.length()); 599 } 600 if (!path.endsWith(fs)) 601 path += fs; 602 return path; 603 } 604 605 /** 606 * This checks for the validity of the options used by the user. 607 * This works exactly like 608 * {@link com.sun.javadoc.Doclet#validOptions(String[][], 609 * DocErrorReporter)}. This will validate the options which are shared 610 * by our doclets. For example, this method will flag an error using 611 * the DocErrorReporter if user has used "-nohelp" and "-helpfile" option 612 * together. 613 * 614 * @param options options used on the command line. 615 * @param reporter used to report errors. 616 * @return true if all the options are valid. 617 */ 618 public boolean generalValidOptions(String options[][], 619 DocErrorReporter reporter) { 620 boolean docencodingfound = false; 621 String encoding = ""; 622 for (int oi = 0; oi < options.length; oi++) { 623 String[] os = options[oi]; 624 String opt = StringUtils.toLowerCase(os[0]); 625 if (opt.equals("-docencoding")) { 626 docencodingfound = true; 627 if (!checkOutputFileEncoding(os[1], reporter)) { 628 return false; 629 } 630 } else if (opt.equals("-encoding")) { 631 encoding = os[1]; 632 } 633 } 634 if (!docencodingfound && encoding.length() > 0) { 635 if (!checkOutputFileEncoding(encoding, reporter)) { 636 return false; 637 } 638 } 639 return true; 640 } 641 642 /** 643 * Check the validity of the given Source or Output File encoding on this 644 * platform. 645 * 646 * @param docencoding output file encoding. 647 * @param reporter used to report errors. 648 */ 649 private boolean checkOutputFileEncoding(String docencoding, 650 DocErrorReporter reporter) { 651 OutputStream ost= new ByteArrayOutputStream(); 652 OutputStreamWriter osw = null; 653 try { 654 osw = new OutputStreamWriter(ost, docencoding); 655 } catch (UnsupportedEncodingException exc) { 656 reporter.printError(getText("doclet.Encoding_not_supported", 657 docencoding)); 658 return false; 659 } finally { 660 try { 661 if (osw != null) { 662 osw.close(); 663 } 664 } catch (IOException exc) { 665 } 666 } 667 return true; 668 } 669 670 /** 671 * Return true if the given doc-file subdirectory should be excluded and 672 * false otherwise. 673 * @param docfilesubdir the doc-files subdirectory to check. 674 */ 675 public boolean shouldExcludeDocFileDir(String docfilesubdir){ 676 if (excludedDocFileDirs.contains(docfilesubdir)) { 677 return true; 678 } else { 679 return false; 680 } 681 } 682 683 /** 684 * Return true if the given qualifier should be excluded and false otherwise. 685 * @param qualifier the qualifier to check. 686 */ 687 public boolean shouldExcludeQualifier(String qualifier){ 688 if (excludedQualifiers.contains("all") || 689 excludedQualifiers.contains(qualifier) || 690 excludedQualifiers.contains(qualifier + ".*")) { 691 return true; 692 } else { 693 int index = -1; 694 while ((index = qualifier.indexOf(".", index + 1)) != -1) { 695 if (excludedQualifiers.contains(qualifier.substring(0, index + 1) + "*")) { 696 return true; 697 } 698 } 699 return false; 700 } 701 } 702 703 /** 704 * Return the qualified name of the <code>ClassDoc</code> if it's qualifier is not excluded. Otherwise, 705 * return the unqualified <code>ClassDoc</code> name. 706 * @param cd the <code>ClassDoc</code> to check. 707 */ 708 public String getClassName(ClassDoc cd) { 709 PackageDoc pd = cd.containingPackage(); 710 if (pd != null && shouldExcludeQualifier(cd.containingPackage().name())) { 711 return cd.name(); 712 } else { 713 return cd.qualifiedName(); 714 } 715 } 716 717 public String getText(String key) { 718 // Check the doclet specific properties file. 719 MessageRetriever docletMessage = getDocletSpecificMsg(); 720 if (docletMessage.containsKey(key)) { 721 return docletMessage.getText(key); 722 } 723 // Check the shared properties file. 724 return message.getText(key); 725 } 726 727 public String getText(String key, String a1) { 728 // Check the doclet specific properties file. 729 MessageRetriever docletMessage = getDocletSpecificMsg(); 730 if (docletMessage.containsKey(key)) { 731 return docletMessage.getText(key, a1); 732 } 733 // Check the shared properties file. 734 return message.getText(key, a1); 735 } 736 737 public String getText(String key, String a1, String a2) { 738 // Check the doclet specific properties file. 739 MessageRetriever docletMessage = getDocletSpecificMsg(); 740 if (docletMessage.containsKey(key)) { 741 return docletMessage.getText(key, a1, a2); 742 } 743 // Check the shared properties file. 744 return message.getText(key, a1, a2); 745 } 746 747 public String getText(String key, String a1, String a2, String a3) { 748 // Check the doclet specific properties file. 749 MessageRetriever docletMessage = getDocletSpecificMsg(); 750 if (docletMessage.containsKey(key)) { 751 return docletMessage.getText(key, a1, a2, a3); 752 } 753 // Check the shared properties file. 754 return message.getText(key, a1, a2, a3); 755 } 756 757 public abstract Content newContent(); 758 759 /** 760 * Get the configuration string as a content. 761 * 762 * @param key the key to look for in the configuration file 763 * @return a content tree for the text 764 */ 765 public Content getResource(String key) { 766 Content c = newContent(); 767 c.addContent(getText(key)); 768 return c; 769 } 770 771 /** 772 * Get the configuration string as a content. 773 * 774 * @param key the key to look for in the configuration file 775 * @param o string or content argument added to configuration text 776 * @return a content tree for the text 777 */ 778 public Content getResource(String key, Object o) { 779 return getResource(key, o, null, null); 780 } 781 782 /** 783 * Get the configuration string as a content. 784 * 785 * @param key the key to look for in the configuration file 786 * @param o string or content argument added to configuration text 787 * @return a content tree for the text 788 */ 789 public Content getResource(String key, Object o1, Object o2) { 790 return getResource(key, o1, o2, null); 791 } 792 793 /** 794 * Get the configuration string as a content. 795 * 796 * @param key the key to look for in the configuration file 797 * @param o1 string or content argument added to configuration text 798 * @param o2 string or content argument added to configuration text 799 * @return a content tree for the text 800 */ 801 public Content getResource(String key, Object o0, Object o1, Object o2) { 802 Content c = newContent(); 803 Pattern p = Pattern.compile("\\{([012])\\}"); 804 String text = getText(key); 805 Matcher m = p.matcher(text); 806 int start = 0; 807 while (m.find(start)) { 808 c.addContent(text.substring(start, m.start())); 809 810 Object o = null; 811 switch (m.group(1).charAt(0)) { 812 case '0': o = o0; break; 813 case '1': o = o1; break; 814 case '2': o = o2; break; 815 } 816 817 if (o == null) { 818 c.addContent("{" + m.group(1) + "}"); 819 } else if (o instanceof String) { 820 c.addContent((String) o); 821 } else if (o instanceof Content) { 822 c.addContent((Content) o); 823 } 824 825 start = m.end(); 826 } 827 828 c.addContent(text.substring(start)); 829 return c; 830 } 831 832 833 /** 834 * Return true if the ClassDoc element is getting documented, depending upon 835 * -nodeprecated option and the deprecation information. Return true if 836 * -nodeprecated is not used. Return false if -nodeprecated is used and if 837 * either ClassDoc element is deprecated or the containing package is deprecated. 838 * 839 * @param cd the ClassDoc for which the page generation is checked 840 */ 841 public boolean isGeneratedDoc(ClassDoc cd) { 842 if (!nodeprecated) { 843 return true; 844 } 845 return !(utils.isDeprecated(cd) || utils.isDeprecated(cd.containingPackage())); 846 } 847 848 /** 849 * Return the doclet specific instance of a writer factory. 850 * @return the {@link WriterFactory} for the doclet. 851 */ 852 public abstract WriterFactory getWriterFactory(); 853 854 /** 855 * Return the input stream to the builder XML. 856 * 857 * @return the input steam to the builder XML. 858 * @throws FileNotFoundException when the given XML file cannot be found. 859 */ 860 public InputStream getBuilderXML() throws IOException { 861 return builderXMLPath == null ? 862 Configuration.class.getResourceAsStream(DEFAULT_BUILDER_XML) : 863 DocFile.createFileForInput(this, builderXMLPath).openInputStream(); 864 } 865 866 /** 867 * Return the Locale for this document. 868 */ 869 public abstract Locale getLocale(); 870 871 /** 872 * Return the current file manager. 873 */ 874 public abstract JavaFileManager getFileManager(); 875 876 /** 877 * Return the comparator that will be used to sort member documentation. 878 * To no do any sorting, return null. 879 * 880 * @return the {@link java.util.Comparator} used to sort members. 881 */ 882 public abstract Comparator<ProgramElementDoc> getMemberComparator(); 883 884 private void setTabWidth(int n) { 885 sourcetab = n; 886 tabSpaces = String.format("%" + n + "s", ""); 887 } 888 889 public abstract boolean showMessage(SourcePosition pos, String key); 890 891 public abstract Location getLocationForPackage(PackageDoc pd); 892} 893