Path: blob/aarch64-shenandoah-jdk8u272-b10/langtools/src/share/classes/com/sun/tools/javadoc/Start.java
38899 views
/*1* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package com.sun.tools.javadoc;2627import java.io.File;28import java.io.FileNotFoundException;29import java.io.IOException;30import java.io.PrintWriter;31import java.util.ArrayList;32import java.util.Collection;33import java.util.Collections;3435import javax.tools.JavaFileManager;36import javax.tools.JavaFileObject;3738import com.sun.javadoc.*;39import com.sun.tools.javac.main.CommandLine;40import com.sun.tools.javac.util.ClientCodeException;41import com.sun.tools.javac.util.Context;42import com.sun.tools.javac.util.List;43import com.sun.tools.javac.util.ListBuffer;44import com.sun.tools.javac.util.Log;45import com.sun.tools.javac.util.Options;46import static com.sun.tools.javac.code.Flags.*;4748/**49* Main program of Javadoc.50* Previously named "Main".51*52* <p><b>This is NOT part of any supported API.53* If you write code that depends on this, you do so at your own risk.54* This code and its internal interfaces are subject to change or55* deletion without notice.</b>56*57* @since 1.258* @author Robert Field59* @author Neal Gafter (rewrite)60*/61public class Start extends ToolOption.Helper {62/** Context for this invocation. */63private final Context context;6465private final String defaultDocletClassName;66private final ClassLoader docletParentClassLoader;6768private static final String javadocName = "javadoc";6970private static final String standardDocletClassName =71"com.sun.tools.doclets.standard.Standard";7273private long defaultFilter = PUBLIC | PROTECTED;7475private final Messager messager;7677private DocletInvoker docletInvoker;7879/**80* In API mode, exceptions thrown while calling the doclet are81* propagated using ClientCodeException.82*/83private boolean apiMode;8485Start(String programName,86PrintWriter errWriter,87PrintWriter warnWriter,88PrintWriter noticeWriter,89String defaultDocletClassName) {90this(programName, errWriter, warnWriter, noticeWriter, defaultDocletClassName, null);91}9293Start(String programName,94PrintWriter errWriter,95PrintWriter warnWriter,96PrintWriter noticeWriter,97String defaultDocletClassName,98ClassLoader docletParentClassLoader) {99context = new Context();100messager = new Messager(context, programName, errWriter, warnWriter, noticeWriter);101this.defaultDocletClassName = defaultDocletClassName;102this.docletParentClassLoader = docletParentClassLoader;103}104105Start(String programName, String defaultDocletClassName) {106this(programName, defaultDocletClassName, null);107}108109Start(String programName, String defaultDocletClassName,110ClassLoader docletParentClassLoader) {111context = new Context();112messager = new Messager(context, programName);113this.defaultDocletClassName = defaultDocletClassName;114this.docletParentClassLoader = docletParentClassLoader;115}116117Start(String programName, ClassLoader docletParentClassLoader) {118this(programName, standardDocletClassName, docletParentClassLoader);119}120121Start(String programName) {122this(programName, standardDocletClassName);123}124125Start(ClassLoader docletParentClassLoader) {126this(javadocName, docletParentClassLoader);127}128129Start() {130this(javadocName);131}132133public Start(Context context) {134context.getClass(); // null check135this.context = context;136apiMode = true;137defaultDocletClassName = standardDocletClassName;138docletParentClassLoader = null;139140Log log = context.get(Log.logKey);141if (log instanceof Messager)142messager = (Messager) log;143else {144PrintWriter out = context.get(Log.outKey);145messager = (out == null) ? new Messager(context, javadocName)146: new Messager(context, javadocName, out, out, out);147}148}149150/**151* Usage152*/153@Override154void usage() {155usage(true);156}157158void usage(boolean exit) {159usage("main.usage", "-help", null, exit);160}161162@Override163void Xusage() {164Xusage(true);165}166167void Xusage(boolean exit) {168usage("main.Xusage", "-X", "main.Xusage.foot", exit);169}170171private void usage(String main, String doclet, String foot, boolean exit) {172// RFE: it would be better to replace the following with code to173// write a header, then help for each option, then a footer.174messager.notice(main);175176// let doclet print usage information (does nothing on error)177if (docletInvoker != null) {178// RFE: this is a pretty bad way to get the doclet to show179// help info. Moreover, the output appears on stdout,180// and <i>not</i> on any of the standard streams passed181// to javadoc, and in particular, not to the noticeWriter182// But, to fix this, we need to fix the Doclet API.183docletInvoker.optionLength(doclet);184}185186if (foot != null)187messager.notice(foot);188189if (exit) exit();190}191192/**193* Exit194*/195private void exit() {196messager.exit();197}198199200/**201* Main program - external wrapper202*/203int begin(String... argv) {204boolean ok = begin(null, argv, Collections.<JavaFileObject> emptySet());205return ok ? 0 : 1;206}207208public boolean begin(Class<?> docletClass, Iterable<String> options, Iterable<? extends JavaFileObject> fileObjects) {209Collection<String> opts = new ArrayList<String>();210for (String opt: options) opts.add(opt);211return begin(docletClass, opts.toArray(new String[opts.size()]), fileObjects);212}213214private boolean begin(Class<?> docletClass, String[] options, Iterable<? extends JavaFileObject> fileObjects) {215boolean failed = false;216217try {218failed = !parseAndExecute(docletClass, options, fileObjects);219} catch (Messager.ExitJavadoc exc) {220// ignore, we just exit this way221} catch (OutOfMemoryError ee) {222messager.error(Messager.NOPOS, "main.out.of.memory");223failed = true;224} catch (ClientCodeException e) {225// simply rethrow these exceptions, to be caught and handled by JavadocTaskImpl226throw e;227} catch (Error ee) {228ee.printStackTrace(System.err);229messager.error(Messager.NOPOS, "main.fatal.error");230failed = true;231} catch (Exception ee) {232ee.printStackTrace(System.err);233messager.error(Messager.NOPOS, "main.fatal.exception");234failed = true;235} finally {236messager.exitNotice();237messager.flush();238}239failed |= messager.nerrors() > 0;240failed |= rejectWarnings && messager.nwarnings() > 0;241return !failed;242}243244/**245* Main program - internal246*/247private boolean parseAndExecute(248Class<?> docletClass,249String[] argv,250Iterable<? extends JavaFileObject> fileObjects) throws IOException {251long tm = System.currentTimeMillis();252253ListBuffer<String> javaNames = new ListBuffer<String>();254255// Preprocess @file arguments256try {257argv = CommandLine.parse(argv);258} catch (FileNotFoundException e) {259messager.error(Messager.NOPOS, "main.cant.read", e.getMessage());260exit();261} catch (IOException e) {262e.printStackTrace(System.err);263exit();264}265266267JavaFileManager fileManager = context.get(JavaFileManager.class);268setDocletInvoker(docletClass, fileManager, argv);269270compOpts = Options.instance(context);271// Make sure no obsolete source/target messages are reported272compOpts.put("-Xlint:-options", "-Xlint:-options");273274// Parse arguments275for (int i = 0 ; i < argv.length ; i++) {276String arg = argv[i];277278ToolOption o = ToolOption.get(arg);279if (o != null) {280// hack: this restriction should be removed281if (o == ToolOption.LOCALE && i > 0)282usageError("main.locale_first");283284if (o.hasArg) {285oneArg(argv, i++);286o.process(this, argv[i]);287} else {288setOption(arg);289o.process(this);290}291292} else if (arg.startsWith("-XD")) {293// hidden javac options294String s = arg.substring("-XD".length());295int eq = s.indexOf('=');296String key = (eq < 0) ? s : s.substring(0, eq);297String value = (eq < 0) ? s : s.substring(eq+1);298compOpts.put(key, value);299}300// call doclet for its options301// other arg starts with - is invalid302else if (arg.startsWith("-")) {303int optionLength;304optionLength = docletInvoker.optionLength(arg);305if (optionLength < 0) {306// error already displayed307exit();308} else if (optionLength == 0) {309// option not found310usageError("main.invalid_flag", arg);311} else {312// doclet added option313if ((i + optionLength) > argv.length) {314usageError("main.requires_argument", arg);315}316ListBuffer<String> args = new ListBuffer<String>();317for (int j = 0; j < optionLength-1; ++j) {318args.append(argv[++i]);319}320setOption(arg, args.toList());321}322} else {323javaNames.append(arg);324}325}326compOpts.notifyListeners();327328if (javaNames.isEmpty() && subPackages.isEmpty() && isEmpty(fileObjects)) {329usageError("main.No_packages_or_classes_specified");330}331332if (!docletInvoker.validOptions(options.toList())) {333// error message already displayed334exit();335}336337JavadocTool comp = JavadocTool.make0(context);338if (comp == null) return false;339340if (showAccess == null) {341setFilter(defaultFilter);342}343344LanguageVersion languageVersion = docletInvoker.languageVersion();345RootDocImpl root = comp.getRootDocImpl(346docLocale,347encoding,348showAccess,349javaNames.toList(),350options.toList(),351fileObjects,352breakiterator,353subPackages.toList(),354excludedPackages.toList(),355docClasses,356// legacy?357languageVersion == null || languageVersion == LanguageVersion.JAVA_1_1,358quiet);359360// release resources361comp = null;362363// pass off control to the doclet364boolean ok = root != null;365if (ok) ok = docletInvoker.start(root);366367// We're done.368if (compOpts.get("-verbose") != null) {369tm = System.currentTimeMillis() - tm;370messager.notice("main.done_in", Long.toString(tm));371}372373return ok;374}375376private <T> boolean isEmpty(Iterable<T> iter) {377return !iter.iterator().hasNext();378}379380/**381* Init the doclet invoker.382* The doclet class may be given explicitly, or via the -doclet option in383* argv.384* If the doclet class is not given explicitly, it will be loaded from385* the file manager's DOCLET_PATH location, if available, or via the386* -doclet path option in argv.387* @param docletClass The doclet class. May be null.388* @param fileManager The file manager used to get the class loader to load389* the doclet class if required. May be null.390* @param argv Args containing -doclet and -docletpath, in case they are required.391*/392private void setDocletInvoker(Class<?> docletClass, JavaFileManager fileManager, String[] argv) {393if (docletClass != null) {394docletInvoker = new DocletInvoker(messager, docletClass, apiMode);395// TODO, check no -doclet, -docletpath396return;397}398399String docletClassName = null;400String docletPath = null;401402// Parse doclet specifying arguments403for (int i = 0 ; i < argv.length ; i++) {404String arg = argv[i];405if (arg.equals(ToolOption.DOCLET.opt)) {406oneArg(argv, i++);407if (docletClassName != null) {408usageError("main.more_than_one_doclet_specified_0_and_1",409docletClassName, argv[i]);410}411docletClassName = argv[i];412} else if (arg.equals(ToolOption.DOCLETPATH.opt)) {413oneArg(argv, i++);414if (docletPath == null) {415docletPath = argv[i];416} else {417docletPath += File.pathSeparator + argv[i];418}419}420}421422if (docletClassName == null) {423docletClassName = defaultDocletClassName;424}425426// attempt to find doclet427docletInvoker = new DocletInvoker(messager, fileManager,428docletClassName, docletPath,429docletParentClassLoader,430apiMode);431}432433/**434* Set one arg option.435* Error and exit if one argument is not provided.436*/437private void oneArg(String[] args, int index) {438if ((index + 1) < args.length) {439setOption(args[index], args[index+1]);440} else {441usageError("main.requires_argument", args[index]);442}443}444445@Override446void usageError(String key, Object... args) {447messager.error(Messager.NOPOS, key, args);448usage(true);449}450451/**452* indicate an option with no arguments was given.453*/454private void setOption(String opt) {455String[] option = { opt };456options.append(option);457}458459/**460* indicate an option with one argument was given.461*/462private void setOption(String opt, String argument) {463String[] option = { opt, argument };464options.append(option);465}466467/**468* indicate an option with the specified list of arguments was given.469*/470private void setOption(String opt, List<String> arguments) {471String[] args = new String[arguments.length() + 1];472int k = 0;473args[k++] = opt;474for (List<String> i = arguments; i.nonEmpty(); i=i.tail) {475args[k++] = i.head;476}477options.append(args);478}479}480481482