src/share/classes/com/sun/tools/javadoc/Start.java

Wed, 27 Apr 2016 01:34:52 +0800

author
aoqi
date
Wed, 27 Apr 2016 01:34:52 +0800
changeset 0
959103a6100f
child 2525
2eb010b6cb22
permissions
-rw-r--r--

Initial load
http://hg.openjdk.java.net/jdk8u/jdk8u/langtools/
changeset: 2573:53ca196be1ae
tag: jdk8u25-b17

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.javadoc;
aoqi@0 27
aoqi@0 28 import java.io.File;
aoqi@0 29 import java.io.FileNotFoundException;
aoqi@0 30 import java.io.IOException;
aoqi@0 31 import java.io.PrintWriter;
aoqi@0 32 import java.util.ArrayList;
aoqi@0 33 import java.util.Collection;
aoqi@0 34 import java.util.Collections;
aoqi@0 35
aoqi@0 36 import javax.tools.JavaFileManager;
aoqi@0 37 import javax.tools.JavaFileObject;
aoqi@0 38
aoqi@0 39 import com.sun.javadoc.*;
aoqi@0 40 import com.sun.tools.javac.main.CommandLine;
aoqi@0 41 import com.sun.tools.javac.util.ClientCodeException;
aoqi@0 42 import com.sun.tools.javac.util.Context;
aoqi@0 43 import com.sun.tools.javac.util.List;
aoqi@0 44 import com.sun.tools.javac.util.ListBuffer;
aoqi@0 45 import com.sun.tools.javac.util.Log;
aoqi@0 46 import com.sun.tools.javac.util.Options;
aoqi@0 47 import static com.sun.tools.javac.code.Flags.*;
aoqi@0 48
aoqi@0 49 /**
aoqi@0 50 * Main program of Javadoc.
aoqi@0 51 * Previously named "Main".
aoqi@0 52 *
aoqi@0 53 * <p><b>This is NOT part of any supported API.
aoqi@0 54 * If you write code that depends on this, you do so at your own risk.
aoqi@0 55 * This code and its internal interfaces are subject to change or
aoqi@0 56 * deletion without notice.</b>
aoqi@0 57 *
aoqi@0 58 * @since 1.2
aoqi@0 59 * @author Robert Field
aoqi@0 60 * @author Neal Gafter (rewrite)
aoqi@0 61 */
aoqi@0 62 public class Start extends ToolOption.Helper {
aoqi@0 63 /** Context for this invocation. */
aoqi@0 64 private final Context context;
aoqi@0 65
aoqi@0 66 private final String defaultDocletClassName;
aoqi@0 67 private final ClassLoader docletParentClassLoader;
aoqi@0 68
aoqi@0 69 private static final String javadocName = "javadoc";
aoqi@0 70
aoqi@0 71 private static final String standardDocletClassName =
aoqi@0 72 "com.sun.tools.doclets.standard.Standard";
aoqi@0 73
aoqi@0 74 private long defaultFilter = PUBLIC | PROTECTED;
aoqi@0 75
aoqi@0 76 private final Messager messager;
aoqi@0 77
aoqi@0 78 private DocletInvoker docletInvoker;
aoqi@0 79
aoqi@0 80 /**
aoqi@0 81 * In API mode, exceptions thrown while calling the doclet are
aoqi@0 82 * propagated using ClientCodeException.
aoqi@0 83 */
aoqi@0 84 private boolean apiMode;
aoqi@0 85
aoqi@0 86 Start(String programName,
aoqi@0 87 PrintWriter errWriter,
aoqi@0 88 PrintWriter warnWriter,
aoqi@0 89 PrintWriter noticeWriter,
aoqi@0 90 String defaultDocletClassName) {
aoqi@0 91 this(programName, errWriter, warnWriter, noticeWriter, defaultDocletClassName, null);
aoqi@0 92 }
aoqi@0 93
aoqi@0 94 Start(String programName,
aoqi@0 95 PrintWriter errWriter,
aoqi@0 96 PrintWriter warnWriter,
aoqi@0 97 PrintWriter noticeWriter,
aoqi@0 98 String defaultDocletClassName,
aoqi@0 99 ClassLoader docletParentClassLoader) {
aoqi@0 100 context = new Context();
aoqi@0 101 messager = new Messager(context, programName, errWriter, warnWriter, noticeWriter);
aoqi@0 102 this.defaultDocletClassName = defaultDocletClassName;
aoqi@0 103 this.docletParentClassLoader = docletParentClassLoader;
aoqi@0 104 }
aoqi@0 105
aoqi@0 106 Start(String programName, String defaultDocletClassName) {
aoqi@0 107 this(programName, defaultDocletClassName, null);
aoqi@0 108 }
aoqi@0 109
aoqi@0 110 Start(String programName, String defaultDocletClassName,
aoqi@0 111 ClassLoader docletParentClassLoader) {
aoqi@0 112 context = new Context();
aoqi@0 113 messager = new Messager(context, programName);
aoqi@0 114 this.defaultDocletClassName = defaultDocletClassName;
aoqi@0 115 this.docletParentClassLoader = docletParentClassLoader;
aoqi@0 116 }
aoqi@0 117
aoqi@0 118 Start(String programName, ClassLoader docletParentClassLoader) {
aoqi@0 119 this(programName, standardDocletClassName, docletParentClassLoader);
aoqi@0 120 }
aoqi@0 121
aoqi@0 122 Start(String programName) {
aoqi@0 123 this(programName, standardDocletClassName);
aoqi@0 124 }
aoqi@0 125
aoqi@0 126 Start(ClassLoader docletParentClassLoader) {
aoqi@0 127 this(javadocName, docletParentClassLoader);
aoqi@0 128 }
aoqi@0 129
aoqi@0 130 Start() {
aoqi@0 131 this(javadocName);
aoqi@0 132 }
aoqi@0 133
aoqi@0 134 public Start(Context context) {
aoqi@0 135 context.getClass(); // null check
aoqi@0 136 this.context = context;
aoqi@0 137 apiMode = true;
aoqi@0 138 defaultDocletClassName = standardDocletClassName;
aoqi@0 139 docletParentClassLoader = null;
aoqi@0 140
aoqi@0 141 Log log = context.get(Log.logKey);
aoqi@0 142 if (log instanceof Messager)
aoqi@0 143 messager = (Messager) log;
aoqi@0 144 else {
aoqi@0 145 PrintWriter out = context.get(Log.outKey);
aoqi@0 146 messager = (out == null) ? new Messager(context, javadocName)
aoqi@0 147 : new Messager(context, javadocName, out, out, out);
aoqi@0 148 }
aoqi@0 149 }
aoqi@0 150
aoqi@0 151 /**
aoqi@0 152 * Usage
aoqi@0 153 */
aoqi@0 154 @Override
aoqi@0 155 void usage() {
aoqi@0 156 usage(true);
aoqi@0 157 }
aoqi@0 158
aoqi@0 159 void usage(boolean exit) {
aoqi@0 160 usage("main.usage", "-help", null, exit);
aoqi@0 161 }
aoqi@0 162
aoqi@0 163 @Override
aoqi@0 164 void Xusage() {
aoqi@0 165 Xusage(true);
aoqi@0 166 }
aoqi@0 167
aoqi@0 168 void Xusage(boolean exit) {
aoqi@0 169 usage("main.Xusage", "-X", "main.Xusage.foot", exit);
aoqi@0 170 }
aoqi@0 171
aoqi@0 172 private void usage(String main, String doclet, String foot, boolean exit) {
aoqi@0 173 // RFE: it would be better to replace the following with code to
aoqi@0 174 // write a header, then help for each option, then a footer.
aoqi@0 175 messager.notice(main);
aoqi@0 176
aoqi@0 177 // let doclet print usage information (does nothing on error)
aoqi@0 178 if (docletInvoker != null) {
aoqi@0 179 // RFE: this is a pretty bad way to get the doclet to show
aoqi@0 180 // help info. Moreover, the output appears on stdout,
aoqi@0 181 // and <i>not</i> on any of the standard streams passed
aoqi@0 182 // to javadoc, and in particular, not to the noticeWriter
aoqi@0 183 // But, to fix this, we need to fix the Doclet API.
aoqi@0 184 docletInvoker.optionLength(doclet);
aoqi@0 185 }
aoqi@0 186
aoqi@0 187 if (foot != null)
aoqi@0 188 messager.notice(foot);
aoqi@0 189
aoqi@0 190 if (exit) exit();
aoqi@0 191 }
aoqi@0 192
aoqi@0 193 /**
aoqi@0 194 * Exit
aoqi@0 195 */
aoqi@0 196 private void exit() {
aoqi@0 197 messager.exit();
aoqi@0 198 }
aoqi@0 199
aoqi@0 200
aoqi@0 201 /**
aoqi@0 202 * Main program - external wrapper
aoqi@0 203 */
aoqi@0 204 int begin(String... argv) {
aoqi@0 205 boolean ok = begin(null, argv, Collections.<JavaFileObject> emptySet());
aoqi@0 206 return ok ? 0 : 1;
aoqi@0 207 }
aoqi@0 208
aoqi@0 209 public boolean begin(Class<?> docletClass, Iterable<String> options, Iterable<? extends JavaFileObject> fileObjects) {
aoqi@0 210 Collection<String> opts = new ArrayList<String>();
aoqi@0 211 for (String opt: options) opts.add(opt);
aoqi@0 212 return begin(docletClass, opts.toArray(new String[opts.size()]), fileObjects);
aoqi@0 213 }
aoqi@0 214
aoqi@0 215 private boolean begin(Class<?> docletClass, String[] options, Iterable<? extends JavaFileObject> fileObjects) {
aoqi@0 216 boolean failed = false;
aoqi@0 217
aoqi@0 218 try {
aoqi@0 219 failed = !parseAndExecute(docletClass, options, fileObjects);
aoqi@0 220 } catch (Messager.ExitJavadoc exc) {
aoqi@0 221 // ignore, we just exit this way
aoqi@0 222 } catch (OutOfMemoryError ee) {
aoqi@0 223 messager.error(Messager.NOPOS, "main.out.of.memory");
aoqi@0 224 failed = true;
aoqi@0 225 } catch (ClientCodeException e) {
aoqi@0 226 // simply rethrow these exceptions, to be caught and handled by JavadocTaskImpl
aoqi@0 227 throw e;
aoqi@0 228 } catch (Error ee) {
aoqi@0 229 ee.printStackTrace(System.err);
aoqi@0 230 messager.error(Messager.NOPOS, "main.fatal.error");
aoqi@0 231 failed = true;
aoqi@0 232 } catch (Exception ee) {
aoqi@0 233 ee.printStackTrace(System.err);
aoqi@0 234 messager.error(Messager.NOPOS, "main.fatal.exception");
aoqi@0 235 failed = true;
aoqi@0 236 } finally {
aoqi@0 237 messager.exitNotice();
aoqi@0 238 messager.flush();
aoqi@0 239 }
aoqi@0 240 failed |= messager.nerrors() > 0;
aoqi@0 241 failed |= rejectWarnings && messager.nwarnings() > 0;
aoqi@0 242 return !failed;
aoqi@0 243 }
aoqi@0 244
aoqi@0 245 /**
aoqi@0 246 * Main program - internal
aoqi@0 247 */
aoqi@0 248 private boolean parseAndExecute(
aoqi@0 249 Class<?> docletClass,
aoqi@0 250 String[] argv,
aoqi@0 251 Iterable<? extends JavaFileObject> fileObjects) throws IOException {
aoqi@0 252 long tm = System.currentTimeMillis();
aoqi@0 253
aoqi@0 254 ListBuffer<String> javaNames = new ListBuffer<String>();
aoqi@0 255
aoqi@0 256 // Preprocess @file arguments
aoqi@0 257 try {
aoqi@0 258 argv = CommandLine.parse(argv);
aoqi@0 259 } catch (FileNotFoundException e) {
aoqi@0 260 messager.error(Messager.NOPOS, "main.cant.read", e.getMessage());
aoqi@0 261 exit();
aoqi@0 262 } catch (IOException e) {
aoqi@0 263 e.printStackTrace(System.err);
aoqi@0 264 exit();
aoqi@0 265 }
aoqi@0 266
aoqi@0 267
aoqi@0 268 JavaFileManager fileManager = context.get(JavaFileManager.class);
aoqi@0 269 setDocletInvoker(docletClass, fileManager, argv);
aoqi@0 270
aoqi@0 271 compOpts = Options.instance(context);
aoqi@0 272 // Make sure no obsolete source/target messages are reported
aoqi@0 273 compOpts.put("-Xlint:-options", "-Xlint:-options");
aoqi@0 274
aoqi@0 275 // Parse arguments
aoqi@0 276 for (int i = 0 ; i < argv.length ; i++) {
aoqi@0 277 String arg = argv[i];
aoqi@0 278
aoqi@0 279 ToolOption o = ToolOption.get(arg);
aoqi@0 280 if (o != null) {
aoqi@0 281 // hack: this restriction should be removed
aoqi@0 282 if (o == ToolOption.LOCALE && i > 0)
aoqi@0 283 usageError("main.locale_first");
aoqi@0 284
aoqi@0 285 if (o.hasArg) {
aoqi@0 286 oneArg(argv, i++);
aoqi@0 287 o.process(this, argv[i]);
aoqi@0 288 } else {
aoqi@0 289 setOption(arg);
aoqi@0 290 o.process(this);
aoqi@0 291 }
aoqi@0 292
aoqi@0 293 } else if (arg.startsWith("-XD")) {
aoqi@0 294 // hidden javac options
aoqi@0 295 String s = arg.substring("-XD".length());
aoqi@0 296 int eq = s.indexOf('=');
aoqi@0 297 String key = (eq < 0) ? s : s.substring(0, eq);
aoqi@0 298 String value = (eq < 0) ? s : s.substring(eq+1);
aoqi@0 299 compOpts.put(key, value);
aoqi@0 300 }
aoqi@0 301 // call doclet for its options
aoqi@0 302 // other arg starts with - is invalid
aoqi@0 303 else if (arg.startsWith("-")) {
aoqi@0 304 int optionLength;
aoqi@0 305 optionLength = docletInvoker.optionLength(arg);
aoqi@0 306 if (optionLength < 0) {
aoqi@0 307 // error already displayed
aoqi@0 308 exit();
aoqi@0 309 } else if (optionLength == 0) {
aoqi@0 310 // option not found
aoqi@0 311 usageError("main.invalid_flag", arg);
aoqi@0 312 } else {
aoqi@0 313 // doclet added option
aoqi@0 314 if ((i + optionLength) > argv.length) {
aoqi@0 315 usageError("main.requires_argument", arg);
aoqi@0 316 }
aoqi@0 317 ListBuffer<String> args = new ListBuffer<String>();
aoqi@0 318 for (int j = 0; j < optionLength-1; ++j) {
aoqi@0 319 args.append(argv[++i]);
aoqi@0 320 }
aoqi@0 321 setOption(arg, args.toList());
aoqi@0 322 }
aoqi@0 323 } else {
aoqi@0 324 javaNames.append(arg);
aoqi@0 325 }
aoqi@0 326 }
aoqi@0 327 compOpts.notifyListeners();
aoqi@0 328
aoqi@0 329 if (javaNames.isEmpty() && subPackages.isEmpty() && isEmpty(fileObjects)) {
aoqi@0 330 usageError("main.No_packages_or_classes_specified");
aoqi@0 331 }
aoqi@0 332
aoqi@0 333 if (!docletInvoker.validOptions(options.toList())) {
aoqi@0 334 // error message already displayed
aoqi@0 335 exit();
aoqi@0 336 }
aoqi@0 337
aoqi@0 338 JavadocTool comp = JavadocTool.make0(context);
aoqi@0 339 if (comp == null) return false;
aoqi@0 340
aoqi@0 341 if (showAccess == null) {
aoqi@0 342 setFilter(defaultFilter);
aoqi@0 343 }
aoqi@0 344
aoqi@0 345 LanguageVersion languageVersion = docletInvoker.languageVersion();
aoqi@0 346 RootDocImpl root = comp.getRootDocImpl(
aoqi@0 347 docLocale,
aoqi@0 348 encoding,
aoqi@0 349 showAccess,
aoqi@0 350 javaNames.toList(),
aoqi@0 351 options.toList(),
aoqi@0 352 fileObjects,
aoqi@0 353 breakiterator,
aoqi@0 354 subPackages.toList(),
aoqi@0 355 excludedPackages.toList(),
aoqi@0 356 docClasses,
aoqi@0 357 // legacy?
aoqi@0 358 languageVersion == null || languageVersion == LanguageVersion.JAVA_1_1,
aoqi@0 359 quiet);
aoqi@0 360
aoqi@0 361 // release resources
aoqi@0 362 comp = null;
aoqi@0 363
aoqi@0 364 // pass off control to the doclet
aoqi@0 365 boolean ok = root != null;
aoqi@0 366 if (ok) ok = docletInvoker.start(root);
aoqi@0 367
aoqi@0 368 // We're done.
aoqi@0 369 if (compOpts.get("-verbose") != null) {
aoqi@0 370 tm = System.currentTimeMillis() - tm;
aoqi@0 371 messager.notice("main.done_in", Long.toString(tm));
aoqi@0 372 }
aoqi@0 373
aoqi@0 374 return ok;
aoqi@0 375 }
aoqi@0 376
aoqi@0 377 private <T> boolean isEmpty(Iterable<T> iter) {
aoqi@0 378 return !iter.iterator().hasNext();
aoqi@0 379 }
aoqi@0 380
aoqi@0 381 /**
aoqi@0 382 * Init the doclet invoker.
aoqi@0 383 * The doclet class may be given explicitly, or via the -doclet option in
aoqi@0 384 * argv.
aoqi@0 385 * If the doclet class is not given explicitly, it will be loaded from
aoqi@0 386 * the file manager's DOCLET_PATH location, if available, or via the
aoqi@0 387 * -doclet path option in argv.
aoqi@0 388 * @param docletClass The doclet class. May be null.
aoqi@0 389 * @param fileManager The file manager used to get the class loader to load
aoqi@0 390 * the doclet class if required. May be null.
aoqi@0 391 * @param argv Args containing -doclet and -docletpath, in case they are required.
aoqi@0 392 */
aoqi@0 393 private void setDocletInvoker(Class<?> docletClass, JavaFileManager fileManager, String[] argv) {
aoqi@0 394 if (docletClass != null) {
aoqi@0 395 docletInvoker = new DocletInvoker(messager, docletClass, apiMode);
aoqi@0 396 // TODO, check no -doclet, -docletpath
aoqi@0 397 return;
aoqi@0 398 }
aoqi@0 399
aoqi@0 400 String docletClassName = null;
aoqi@0 401 String docletPath = null;
aoqi@0 402
aoqi@0 403 // Parse doclet specifying arguments
aoqi@0 404 for (int i = 0 ; i < argv.length ; i++) {
aoqi@0 405 String arg = argv[i];
aoqi@0 406 if (arg.equals(ToolOption.DOCLET.opt)) {
aoqi@0 407 oneArg(argv, i++);
aoqi@0 408 if (docletClassName != null) {
aoqi@0 409 usageError("main.more_than_one_doclet_specified_0_and_1",
aoqi@0 410 docletClassName, argv[i]);
aoqi@0 411 }
aoqi@0 412 docletClassName = argv[i];
aoqi@0 413 } else if (arg.equals(ToolOption.DOCLETPATH.opt)) {
aoqi@0 414 oneArg(argv, i++);
aoqi@0 415 if (docletPath == null) {
aoqi@0 416 docletPath = argv[i];
aoqi@0 417 } else {
aoqi@0 418 docletPath += File.pathSeparator + argv[i];
aoqi@0 419 }
aoqi@0 420 }
aoqi@0 421 }
aoqi@0 422
aoqi@0 423 if (docletClassName == null) {
aoqi@0 424 docletClassName = defaultDocletClassName;
aoqi@0 425 }
aoqi@0 426
aoqi@0 427 // attempt to find doclet
aoqi@0 428 docletInvoker = new DocletInvoker(messager, fileManager,
aoqi@0 429 docletClassName, docletPath,
aoqi@0 430 docletParentClassLoader,
aoqi@0 431 apiMode);
aoqi@0 432 }
aoqi@0 433
aoqi@0 434 /**
aoqi@0 435 * Set one arg option.
aoqi@0 436 * Error and exit if one argument is not provided.
aoqi@0 437 */
aoqi@0 438 private void oneArg(String[] args, int index) {
aoqi@0 439 if ((index + 1) < args.length) {
aoqi@0 440 setOption(args[index], args[index+1]);
aoqi@0 441 } else {
aoqi@0 442 usageError("main.requires_argument", args[index]);
aoqi@0 443 }
aoqi@0 444 }
aoqi@0 445
aoqi@0 446 @Override
aoqi@0 447 void usageError(String key, Object... args) {
aoqi@0 448 messager.error(Messager.NOPOS, key, args);
aoqi@0 449 usage(true);
aoqi@0 450 }
aoqi@0 451
aoqi@0 452 /**
aoqi@0 453 * indicate an option with no arguments was given.
aoqi@0 454 */
aoqi@0 455 private void setOption(String opt) {
aoqi@0 456 String[] option = { opt };
aoqi@0 457 options.append(option);
aoqi@0 458 }
aoqi@0 459
aoqi@0 460 /**
aoqi@0 461 * indicate an option with one argument was given.
aoqi@0 462 */
aoqi@0 463 private void setOption(String opt, String argument) {
aoqi@0 464 String[] option = { opt, argument };
aoqi@0 465 options.append(option);
aoqi@0 466 }
aoqi@0 467
aoqi@0 468 /**
aoqi@0 469 * indicate an option with the specified list of arguments was given.
aoqi@0 470 */
aoqi@0 471 private void setOption(String opt, List<String> arguments) {
aoqi@0 472 String[] args = new String[arguments.length() + 1];
aoqi@0 473 int k = 0;
aoqi@0 474 args[k++] = opt;
aoqi@0 475 for (List<String> i = arguments; i.nonEmpty(); i=i.tail) {
aoqi@0 476 args[k++] = i.head;
aoqi@0 477 }
aoqi@0 478 options.append(args);
aoqi@0 479 }
aoqi@0 480 }

mercurial