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

Tue, 24 Dec 2013 09:17:37 -0800

author
ksrini
date
Tue, 24 Dec 2013 09:17:37 -0800
changeset 2227
998b10c43157
parent 1961
58da1296c6b3
child 2525
2eb010b6cb22
permissions
-rw-r--r--

8029230: Update copyright year to match last edit in jdk8 langtools repository for 2013
Reviewed-by: ksrini
Contributed-by: steve.sides@oracle.com

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

mercurial