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