src/share/classes/com/sun/tools/doclets/internal/toolkit/Configuration.java

Sat, 07 Nov 2020 10:30:02 +0800

author
aoqi
date
Sat, 07 Nov 2020 10:30:02 +0800
changeset 3938
93012e2a5d1d
parent 2525
2eb010b6cb22
permissions
-rw-r--r--

Added tag mips-jdk8u275-b01 for changeset eb6ee6a5f2fe

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

mercurial