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

Tue, 11 Dec 2012 15:05:55 -0800

author
jjg
date
Tue, 11 Dec 2012 15:05:55 -0800
changeset 1443
cfde9737131e
parent 1413
bdcef2ef52d2
child 1797
019063968164
permissions
-rw-r--r--

8004828: refactor init of *DocImpl classes
Reviewed-by: darcy

duke@1 1 /*
jjg@1357 2 * Copyright (c) 1997, 2012, 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@1411 159
jjg@1411 160 /**
jjg@1411 161 * Usage
jjg@1411 162 */
jjg@1411 163 private void usage(boolean exit) {
jjg@1411 164 // RFE: it would be better to replace the following with code to
jjg@1411 165 // write a header, then help for each option, then a footer.
duke@1 166 messager.notice("main.usage");
duke@1 167
duke@1 168 // let doclet print usage information (does nothing on error)
duke@1 169 if (docletInvoker != null) {
duke@1 170 docletInvoker.optionLength("-help");
duke@1 171 }
jjg@1411 172
jjg@1411 173 if (exit) exit();
jjg@1411 174 }
jjg@1411 175
jjg@1411 176 @Override
jjg@1411 177 void Xusage() {
jjg@1411 178 Xusage(true);
duke@1 179 }
duke@1 180
duke@1 181 /**
jjg@584 182 * Usage
jjg@584 183 */
jjg@1411 184 private void Xusage(boolean exit) {
jjg@584 185 messager.notice("main.Xusage");
jjg@1411 186 if (exit) exit();
jjg@584 187 }
jjg@584 188
jjg@584 189 /**
duke@1 190 * Exit
duke@1 191 */
duke@1 192 private void exit() {
duke@1 193 messager.exit();
duke@1 194 }
duke@1 195
duke@1 196
duke@1 197 /**
duke@1 198 * Main program - external wrapper
duke@1 199 */
jjg@127 200 int begin(String... argv) {
jjg@1413 201 boolean ok = begin(null, argv, Collections.<JavaFileObject> emptySet());
jjg@1413 202 return ok ? 0 : 1;
jjg@1413 203 }
jjg@1413 204
jjg@1413 205 public boolean begin(Class<?> docletClass, Iterable<String> options, Iterable<? extends JavaFileObject> fileObjects) {
jjg@1413 206 Collection<String> opts = new ArrayList<String>();
jjg@1413 207 for (String opt: options) opts.add(opt);
jjg@1413 208 return begin(docletClass, opts.toArray(new String[opts.size()]), fileObjects);
jjg@1413 209 }
jjg@1413 210
jjg@1413 211 private boolean begin(Class<?> docletClass, String[] options, Iterable<? extends JavaFileObject> fileObjects) {
duke@1 212 boolean failed = false;
duke@1 213
duke@1 214 try {
jjg@1413 215 failed = !parseAndExecute(docletClass, options, fileObjects);
jjg@1411 216 } catch (Messager.ExitJavadoc exc) {
duke@1 217 // ignore, we just exit this way
duke@1 218 } catch (OutOfMemoryError ee) {
jjg@1411 219 messager.error(Messager.NOPOS, "main.out.of.memory");
duke@1 220 failed = true;
jjg@1413 221 } catch (ClientCodeException e) {
jjg@1413 222 // simply rethrow these exceptions, to be caught and handled by JavadocTaskImpl
jjg@1413 223 throw e;
duke@1 224 } catch (Error ee) {
jjg@1135 225 ee.printStackTrace(System.err);
jjg@1411 226 messager.error(Messager.NOPOS, "main.fatal.error");
duke@1 227 failed = true;
duke@1 228 } catch (Exception ee) {
jjg@1135 229 ee.printStackTrace(System.err);
jjg@1411 230 messager.error(Messager.NOPOS, "main.fatal.exception");
duke@1 231 failed = true;
duke@1 232 } finally {
duke@1 233 messager.exitNotice();
duke@1 234 messager.flush();
duke@1 235 }
duke@1 236 failed |= messager.nerrors() > 0;
duke@1 237 failed |= rejectWarnings && messager.nwarnings() > 0;
jjg@1413 238 return !failed;
duke@1 239 }
duke@1 240
duke@1 241 /**
duke@1 242 * Main program - internal
duke@1 243 */
jjg@1413 244 private boolean parseAndExecute(
jjg@1413 245 Class<?> docletClass,
jjg@1413 246 String[] argv,
jjg@1413 247 Iterable<? extends JavaFileObject> fileObjects) throws IOException {
duke@1 248 long tm = System.currentTimeMillis();
duke@1 249
duke@1 250 ListBuffer<String> javaNames = new ListBuffer<String>();
duke@1 251
duke@1 252 // Preprocess @file arguments
duke@1 253 try {
duke@1 254 argv = CommandLine.parse(argv);
duke@1 255 } catch (FileNotFoundException e) {
jjg@1411 256 messager.error(Messager.NOPOS, "main.cant.read", e.getMessage());
duke@1 257 exit();
duke@1 258 } catch (IOException e) {
jjg@1135 259 e.printStackTrace(System.err);
duke@1 260 exit();
duke@1 261 }
duke@1 262
jjg@1413 263
jjg@1413 264 JavaFileManager fileManager = context.get(JavaFileManager.class);
jjg@1413 265 setDocletInvoker(docletClass, fileManager, argv);
jjg@584 266
jjg@1411 267 compOpts = Options.instance(context);
duke@1 268
duke@1 269 // Parse arguments
duke@1 270 for (int i = 0 ; i < argv.length ; i++) {
duke@1 271 String arg = argv[i];
jjg@1411 272
jjg@1411 273 ToolOption o = ToolOption.get(arg);
jjg@1411 274 if (o != null) {
jjg@1411 275 // hack: this restriction should be removed
jjg@1411 276 if (o == ToolOption.LOCALE && i > 0)
jjg@1411 277 usageError("main.locale_first");
jjg@1411 278
jjg@1411 279 if (o.hasArg) {
jjg@1411 280 oneArg(argv, i++);
jjg@1411 281 o.process(this, argv[i]);
jjg@1411 282 } else {
jjg@1411 283 setOption(arg);
jjg@1411 284 o.process(this);
duke@1 285 }
jjg@1411 286
duke@1 287 } else if (arg.startsWith("-XD")) {
jjg@1411 288 // hidden javac options
duke@1 289 String s = arg.substring("-XD".length());
duke@1 290 int eq = s.indexOf('=');
duke@1 291 String key = (eq < 0) ? s : s.substring(0, eq);
duke@1 292 String value = (eq < 0) ? s : s.substring(eq+1);
duke@1 293 compOpts.put(key, value);
duke@1 294 }
duke@1 295 // call doclet for its options
duke@1 296 // other arg starts with - is invalid
jjg@1411 297 else if (arg.startsWith("-")) {
duke@1 298 int optionLength;
duke@1 299 optionLength = docletInvoker.optionLength(arg);
duke@1 300 if (optionLength < 0) {
duke@1 301 // error already displayed
duke@1 302 exit();
duke@1 303 } else if (optionLength == 0) {
duke@1 304 // option not found
duke@1 305 usageError("main.invalid_flag", arg);
duke@1 306 } else {
duke@1 307 // doclet added option
duke@1 308 if ((i + optionLength) > argv.length) {
duke@1 309 usageError("main.requires_argument", arg);
duke@1 310 }
duke@1 311 ListBuffer<String> args = new ListBuffer<String>();
duke@1 312 for (int j = 0; j < optionLength-1; ++j) {
duke@1 313 args.append(argv[++i]);
duke@1 314 }
duke@1 315 setOption(arg, args.toList());
duke@1 316 }
duke@1 317 } else {
duke@1 318 javaNames.append(arg);
duke@1 319 }
duke@1 320 }
jjg@1392 321 compOpts.notifyListeners();
duke@1 322
jjg@1413 323 if (javaNames.isEmpty() && subPackages.isEmpty() && isEmpty(fileObjects)) {
duke@1 324 usageError("main.No_packages_or_classes_specified");
duke@1 325 }
duke@1 326
duke@1 327 if (!docletInvoker.validOptions(options.toList())) {
duke@1 328 // error message already displayed
duke@1 329 exit();
duke@1 330 }
duke@1 331
duke@1 332 JavadocTool comp = JavadocTool.make0(context);
duke@1 333 if (comp == null) return false;
duke@1 334
duke@1 335 if (showAccess == null) {
duke@1 336 setFilter(defaultFilter);
duke@1 337 }
duke@1 338
duke@1 339 LanguageVersion languageVersion = docletInvoker.languageVersion();
duke@1 340 RootDocImpl root = comp.getRootDocImpl(
jjg@1411 341 docLocale,
jjg@1411 342 encoding,
jjg@1411 343 showAccess,
jjg@1411 344 javaNames.toList(),
jjg@1411 345 options.toList(),
jjg@1413 346 fileObjects,
jjg@1411 347 breakiterator,
jjg@1411 348 subPackages.toList(),
jjg@1411 349 excludedPackages.toList(),
duke@1 350 docClasses,
duke@1 351 // legacy?
jjg@1411 352 languageVersion == null || languageVersion == LanguageVersion.JAVA_1_1,
jjg@1411 353 quiet);
duke@1 354
jjg@1391 355 // release resources
jjg@1391 356 comp = null;
jjg@1391 357
duke@1 358 // pass off control to the doclet
duke@1 359 boolean ok = root != null;
duke@1 360 if (ok) ok = docletInvoker.start(root);
duke@1 361
duke@1 362 // We're done.
duke@1 363 if (compOpts.get("-verbose") != null) {
duke@1 364 tm = System.currentTimeMillis() - tm;
duke@1 365 messager.notice("main.done_in", Long.toString(tm));
duke@1 366 }
duke@1 367
duke@1 368 return ok;
duke@1 369 }
duke@1 370
jjg@1413 371 private <T> boolean isEmpty(Iterable<T> iter) {
jjg@1413 372 return !iter.iterator().hasNext();
jjg@1413 373 }
jjg@1413 374
jjg@1413 375 /**
jjg@1413 376 * Init the doclet invoker.
jjg@1413 377 * The doclet class may be given explicitly, or via the -doclet option in
jjg@1413 378 * argv.
jjg@1413 379 * If the doclet class is not given explicitly, it will be loaded from
jjg@1413 380 * the file manager's DOCLET_PATH location, if available, or via the
jjg@1413 381 * -doclet path option in argv.
jjg@1413 382 * @param docletClass The doclet class. May be null.
jjg@1413 383 * @param fileManager The file manager used to get the class loader to load
jjg@1413 384 * the doclet class if required. May be null.
jjg@1413 385 * @param argv Args containing -doclet and -docletpath, in case they are required.
jjg@1413 386 */
jjg@1413 387 private void setDocletInvoker(Class<?> docletClass, JavaFileManager fileManager, String[] argv) {
jjg@1413 388 if (docletClass != null) {
jjg@1413 389 docletInvoker = new DocletInvoker(messager, docletClass, apiMode);
jjg@1413 390 // TODO, check no -doclet, -docletpath
jjg@1413 391 return;
jjg@1413 392 }
jjg@1413 393
duke@1 394 String docletClassName = null;
duke@1 395 String docletPath = null;
duke@1 396
duke@1 397 // Parse doclet specifying arguments
duke@1 398 for (int i = 0 ; i < argv.length ; i++) {
duke@1 399 String arg = argv[i];
jjg@1413 400 if (arg.equals(ToolOption.DOCLET.opt)) {
duke@1 401 oneArg(argv, i++);
duke@1 402 if (docletClassName != null) {
duke@1 403 usageError("main.more_than_one_doclet_specified_0_and_1",
duke@1 404 docletClassName, argv[i]);
duke@1 405 }
duke@1 406 docletClassName = argv[i];
jjg@1413 407 } else if (arg.equals(ToolOption.DOCLETPATH.opt)) {
duke@1 408 oneArg(argv, i++);
duke@1 409 if (docletPath == null) {
duke@1 410 docletPath = argv[i];
duke@1 411 } else {
duke@1 412 docletPath += File.pathSeparator + argv[i];
duke@1 413 }
duke@1 414 }
duke@1 415 }
duke@1 416
duke@1 417 if (docletClassName == null) {
duke@1 418 docletClassName = defaultDocletClassName;
duke@1 419 }
duke@1 420
duke@1 421 // attempt to find doclet
jjg@1413 422 docletInvoker = new DocletInvoker(messager, fileManager,
jjg@1413 423 docletClassName, docletPath,
jjg@1413 424 docletParentClassLoader,
jjg@1413 425 apiMode);
duke@1 426 }
duke@1 427
duke@1 428 /**
duke@1 429 * Set one arg option.
duke@1 430 * Error and exit if one argument is not provided.
duke@1 431 */
duke@1 432 private void oneArg(String[] args, int index) {
duke@1 433 if ((index + 1) < args.length) {
duke@1 434 setOption(args[index], args[index+1]);
duke@1 435 } else {
duke@1 436 usageError("main.requires_argument", args[index]);
duke@1 437 }
duke@1 438 }
duke@1 439
jjg@1411 440 @Override
jjg@1411 441 void usageError(String key, Object... args) {
jjg@1411 442 messager.error(Messager.NOPOS, key, args);
jjg@1411 443 usage(true);
duke@1 444 }
duke@1 445
duke@1 446 /**
duke@1 447 * indicate an option with no arguments was given.
duke@1 448 */
duke@1 449 private void setOption(String opt) {
duke@1 450 String[] option = { opt };
duke@1 451 options.append(option);
duke@1 452 }
duke@1 453
duke@1 454 /**
duke@1 455 * indicate an option with one argument was given.
duke@1 456 */
duke@1 457 private void setOption(String opt, String argument) {
duke@1 458 String[] option = { opt, argument };
duke@1 459 options.append(option);
duke@1 460 }
duke@1 461
duke@1 462 /**
duke@1 463 * indicate an option with the specified list of arguments was given.
duke@1 464 */
duke@1 465 private void setOption(String opt, List<String> arguments) {
duke@1 466 String[] args = new String[arguments.length() + 1];
duke@1 467 int k = 0;
duke@1 468 args[k++] = opt;
duke@1 469 for (List<String> i = arguments; i.nonEmpty(); i=i.tail) {
duke@1 470 args[k++] = i.head;
duke@1 471 }
jjg@1411 472 options.append(args);
duke@1 473 }
duke@1 474 }

mercurial