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

Thu, 31 Aug 2017 15:17:03 +0800

author
aoqi
date
Thu, 31 Aug 2017 15:17:03 +0800
changeset 2525
2eb010b6cb22
parent 1961
58da1296c6b3
parent 0
959103a6100f
permissions
-rw-r--r--

merge

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

mercurial