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

Mon, 06 Oct 2008 16:57:15 -0700

author
jjg
date
Mon, 06 Oct 2008 16:57:15 -0700
changeset 129
944790f83b57
parent 127
d593587c5938
child 174
fdfed22db054
permissions
-rw-r--r--

6748546: javadoc API should be classloader-friendly
Reviewed-by: bpatel

     1 /*
     2  * Copyright 1997-2006 Sun Microsystems, Inc.  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.  Sun designates this
     8  * particular file as subject to the "Classpath" exception as provided
     9  * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
    22  * CA 95054 USA or visit www.sun.com if you need additional information or
    23  * have any questions.
    24  */
    26 package com.sun.tools.javadoc;
    28 import com.sun.javadoc.*;
    30 import com.sun.tools.javac.main.CommandLine;
    31 import com.sun.tools.javac.util.Context;
    32 import com.sun.tools.javac.util.List;
    33 import com.sun.tools.javac.util.ListBuffer;
    34 import com.sun.tools.javac.util.Options;
    36 import java.io.IOException;
    37 import java.io.File;
    38 import java.io.FileNotFoundException;
    39 import java.io.PrintWriter;
    41 import java.util.StringTokenizer;
    43 import static com.sun.tools.javac.code.Flags.*;
    45 /**
    46  * Main program of Javadoc.
    47  * Previously named "Main".
    48  *
    49  * @since 1.2
    50  * @author Robert Field
    51  * @author Neal Gafter (rewrite)
    52  */
    53 class Start {
    54     /** Context for this invocation. */
    55     private final Context context;
    57     private final String defaultDocletClassName;
    58     private final ClassLoader docletParentClassLoader;
    60     private static final String javadocName = "javadoc";
    62     private static final String standardDocletClassName =
    63         "com.sun.tools.doclets.standard.Standard";
    65     private ListBuffer<String[]> options = new ListBuffer<String[]>();
    67     private ModifierFilter showAccess = null;
    69     private long defaultFilter = PUBLIC | PROTECTED;
    71     private Messager messager;
    73     String docLocale = "";
    75     boolean breakiterator = false;
    76     boolean quiet = false;
    77     String encoding = null;
    79     private DocletInvoker docletInvoker;
    81     private static final int F_VERBOSE = 1 << 0;
    82     private static final int F_WARNINGS = 1 << 2;
    84     /* Treat warnings as errors. */
    85     private boolean rejectWarnings = false;
    87     Start(String programName,
    88           PrintWriter errWriter,
    89           PrintWriter warnWriter,
    90           PrintWriter noticeWriter,
    91           String defaultDocletClassName) {
    92         this(programName, errWriter, warnWriter, noticeWriter, defaultDocletClassName, null);
    93     }
    95     Start(String programName,
    96           PrintWriter errWriter,
    97           PrintWriter warnWriter,
    98           PrintWriter noticeWriter,
    99           String defaultDocletClassName,
   100           ClassLoader docletParentClassLoader) {
   101         context = new Context();
   102         messager = new Messager(context, programName, errWriter, warnWriter, noticeWriter);
   103         this.defaultDocletClassName = defaultDocletClassName;
   104         this.docletParentClassLoader = docletParentClassLoader;
   105     }
   107     Start(String programName, String defaultDocletClassName) {
   108         this(programName, defaultDocletClassName, null);
   109     }
   111     Start(String programName, String defaultDocletClassName,
   112           ClassLoader docletParentClassLoader) {
   113         context = new Context();
   114         messager = new Messager(context, programName);
   115         this.defaultDocletClassName = defaultDocletClassName;
   116         this.docletParentClassLoader = docletParentClassLoader;
   117     }
   119     Start(String programName, ClassLoader docletParentClassLoader) {
   120         this(programName, standardDocletClassName, docletParentClassLoader);
   121     }
   123     Start(String programName) {
   124         this(programName, standardDocletClassName);
   125     }
   127     Start(ClassLoader docletParentClassLoader) {
   128         this(javadocName, docletParentClassLoader);
   129     }
   131     Start() {
   132         this(javadocName);
   133     }
   135     /**
   136      * Usage
   137      */
   138     private void usage() {
   139         messager.notice("main.usage");
   141         // let doclet print usage information (does nothing on error)
   142         if (docletInvoker != null) {
   143             docletInvoker.optionLength("-help");
   144         }
   145     }
   147     /**
   148      * Exit
   149      */
   150     private void exit() {
   151         messager.exit();
   152     }
   155     /**
   156      * Main program - external wrapper
   157      */
   158     int begin(String... argv) {
   159         boolean failed = false;
   161         try {
   162             failed = !parseAndExecute(argv);
   163         } catch(Messager.ExitJavadoc exc) {
   164             // ignore, we just exit this way
   165         } catch (OutOfMemoryError ee) {
   166             messager.error(null, "main.out.of.memory");
   167             failed = true;
   168         } catch (Error ee) {
   169             ee.printStackTrace();
   170             messager.error(null, "main.fatal.error");
   171             failed = true;
   172         } catch (Exception ee) {
   173             ee.printStackTrace();
   174             messager.error(null, "main.fatal.exception");
   175             failed = true;
   176         } finally {
   177             messager.exitNotice();
   178             messager.flush();
   179         }
   180         failed |= messager.nerrors() > 0;
   181         failed |= rejectWarnings && messager.nwarnings() > 0;
   182         return failed ? 1 : 0;
   183     }
   185     private void addToList(ListBuffer<String> list, String str){
   186         StringTokenizer st = new StringTokenizer(str, ":");
   187         String current;
   188         while(st.hasMoreTokens()){
   189             current = st.nextToken();
   190             list.append(current);
   191         }
   192     }
   194     /**
   195      * Main program - internal
   196      */
   197     private boolean parseAndExecute(String... argv) throws IOException {
   198         long tm = System.currentTimeMillis();
   200         ListBuffer<String> javaNames = new ListBuffer<String>();
   202         // Preprocess @file arguments
   203         try {
   204             argv = CommandLine.parse(argv);
   205         } catch (FileNotFoundException e) {
   206             messager.error(null, "main.cant.read", e.getMessage());
   207             exit();
   208         } catch (IOException e) {
   209             e.printStackTrace();
   210             exit();
   211         }
   213         setDocletInvoker(argv);
   214         ListBuffer<String> subPackages = new ListBuffer<String>();
   215         ListBuffer<String> excludedPackages = new ListBuffer<String>();
   216         Options compOpts = Options.instance(context);
   217         boolean docClasses = false;
   219         // Parse arguments
   220         for (int i = 0 ; i < argv.length ; i++) {
   221             String arg = argv[i];
   222             if (arg.equals("-subpackages")) {
   223                 oneArg(argv, i++);
   224                 addToList(subPackages, argv[i]);
   225             } else if (arg.equals("-exclude")){
   226                 oneArg(argv, i++);
   227                 addToList(excludedPackages, argv[i]);
   228             } else if (arg.equals("-verbose")) {
   229                 setOption(arg);
   230                 compOpts.put("-verbose", "");
   231             } else if (arg.equals("-encoding")) {
   232                 oneArg(argv, i++);
   233                 encoding = argv[i];
   234                 compOpts.put("-encoding", argv[i]);
   235             } else if (arg.equals("-breakiterator")) {
   236                 breakiterator = true;
   237                 setOption("-breakiterator");
   238             } else if (arg.equals("-quiet")) {
   239                 quiet = true;
   240                 setOption("-quiet");
   241             } else if (arg.equals("-help")) {
   242                 usage();
   243                 exit();
   244             } else if (arg.equals("-Xclasses")) {
   245                 setOption(arg);
   246                 docClasses = true;
   247             } else if (arg.equals("-Xwerror")) {
   248                 setOption(arg);
   249                 rejectWarnings = true;
   250             } else if (arg.equals("-private")) {
   251                 setOption(arg);
   252                 setFilter(ModifierFilter.ALL_ACCESS);
   253             } else if (arg.equals("-package")) {
   254                 setOption(arg);
   255                 setFilter(PUBLIC | PROTECTED |
   256                           ModifierFilter.PACKAGE );
   257             } else if (arg.equals("-protected")) {
   258                 setOption(arg);
   259                 setFilter(PUBLIC | PROTECTED );
   260             } else if (arg.equals("-public")) {
   261                 setOption(arg);
   262                 setFilter(PUBLIC);
   263             } else if (arg.equals("-source")) {
   264                 oneArg(argv, i++);
   265                 if (compOpts.get("-source") != null) {
   266                     usageError("main.option.already.seen", arg);
   267                 }
   268                 compOpts.put("-source", argv[i]);
   269             } else if (arg.equals("-prompt")) {
   270                 compOpts.put("-prompt", "-prompt");
   271                 messager.promptOnError = true;
   272             } else if (arg.equals("-sourcepath")) {
   273                 oneArg(argv, i++);
   274                 if (compOpts.get("-sourcepath") != null) {
   275                     usageError("main.option.already.seen", arg);
   276                 }
   277                 compOpts.put("-sourcepath", argv[i]);
   278             } else if (arg.equals("-classpath")) {
   279                 oneArg(argv, i++);
   280                 if (compOpts.get("-classpath") != null) {
   281                     usageError("main.option.already.seen", arg);
   282                 }
   283                 compOpts.put("-classpath", argv[i]);
   284             } else if (arg.equals("-sysclasspath")) {
   285                 oneArg(argv, i++);
   286                 if (compOpts.get("-bootclasspath") != null) {
   287                     usageError("main.option.already.seen", arg);
   288                 }
   289                 compOpts.put("-bootclasspath", argv[i]);
   290             } else if (arg.equals("-bootclasspath")) {
   291                 oneArg(argv, i++);
   292                 if (compOpts.get("-bootclasspath") != null) {
   293                     usageError("main.option.already.seen", arg);
   294                 }
   295                 compOpts.put("-bootclasspath", argv[i]);
   296             } else if (arg.equals("-extdirs")) {
   297                 oneArg(argv, i++);
   298                 if (compOpts.get("-extdirs") != null) {
   299                     usageError("main.option.already.seen", arg);
   300                 }
   301                 compOpts.put("-extdirs", argv[i]);
   302             } else if (arg.equals("-overview")) {
   303                 oneArg(argv, i++);
   304             } else if (arg.equals("-doclet")) {
   305                 i++;  // handled in setDocletInvoker
   306             } else if (arg.equals("-docletpath")) {
   307                 i++;  // handled in setDocletInvoker
   308             } else if (arg.equals("-locale")) {
   309                 if (i != 0)
   310                     usageError("main.locale_first");
   311                 oneArg(argv, i++);
   312                 docLocale = argv[i];
   313             } else if (arg.startsWith("-XD")) {
   314                 String s = arg.substring("-XD".length());
   315                 int eq = s.indexOf('=');
   316                 String key = (eq < 0) ? s : s.substring(0, eq);
   317                 String value = (eq < 0) ? s : s.substring(eq+1);
   318                 compOpts.put(key, value);
   319             }
   320             // call doclet for its options
   321             // other arg starts with - is invalid
   322             else if ( arg.startsWith("-") ) {
   323                 int optionLength;
   324                 optionLength = docletInvoker.optionLength(arg);
   325                 if (optionLength < 0) {
   326                     // error already displayed
   327                     exit();
   328                 } else if (optionLength == 0) {
   329                     // option not found
   330                     usageError("main.invalid_flag", arg);
   331                 } else {
   332                     // doclet added option
   333                     if ((i + optionLength) > argv.length) {
   334                         usageError("main.requires_argument", arg);
   335                     }
   336                     ListBuffer<String> args = new ListBuffer<String>();
   337                     for (int j = 0; j < optionLength-1; ++j) {
   338                         args.append(argv[++i]);
   339                     }
   340                     setOption(arg, args.toList());
   341                 }
   342             } else {
   343                 javaNames.append(arg);
   344             }
   345         }
   347         if (javaNames.isEmpty() && subPackages.isEmpty()) {
   348             usageError("main.No_packages_or_classes_specified");
   349         }
   351         if (!docletInvoker.validOptions(options.toList())) {
   352             // error message already displayed
   353             exit();
   354         }
   356         JavadocTool comp = JavadocTool.make0(context);
   357         if (comp == null) return false;
   359         if (showAccess == null) {
   360             setFilter(defaultFilter);
   361         }
   363         LanguageVersion languageVersion = docletInvoker.languageVersion();
   364         RootDocImpl root = comp.getRootDocImpl(
   365                 docLocale, encoding, showAccess,
   366                 javaNames.toList(), options.toList(), breakiterator,
   367                 subPackages.toList(), excludedPackages.toList(),
   368                 docClasses,
   369                 // legacy?
   370                 languageVersion == null || languageVersion == LanguageVersion.JAVA_1_1, quiet);
   372         // pass off control to the doclet
   373         boolean ok = root != null;
   374         if (ok) ok = docletInvoker.start(root);
   376         // We're done.
   377         if (compOpts.get("-verbose") != null) {
   378             tm = System.currentTimeMillis() - tm;
   379             messager.notice("main.done_in", Long.toString(tm));
   380         }
   382         return ok;
   383     }
   385     private void setDocletInvoker(String[] argv) {
   386         String docletClassName = null;
   387         String docletPath = null;
   389         // Parse doclet specifying arguments
   390         for (int i = 0 ; i < argv.length ; i++) {
   391             String arg = argv[i];
   392             if (arg.equals("-doclet")) {
   393                 oneArg(argv, i++);
   394                 if (docletClassName != null) {
   395                     usageError("main.more_than_one_doclet_specified_0_and_1",
   396                                docletClassName, argv[i]);
   397                 }
   398                 docletClassName = argv[i];
   399             } else if (arg.equals("-docletpath")) {
   400                 oneArg(argv, i++);
   401                 if (docletPath == null) {
   402                     docletPath = argv[i];
   403                 } else {
   404                     docletPath += File.pathSeparator + argv[i];
   405                 }
   406             }
   407         }
   409         if (docletClassName == null) {
   410             docletClassName = defaultDocletClassName;
   411         }
   413         // attempt to find doclet
   414         docletInvoker = new DocletInvoker(messager,
   415                                           docletClassName, docletPath,
   416                                           docletParentClassLoader);
   417     }
   419     private void setFilter(long filterBits) {
   420         if (showAccess != null) {
   421             messager.error(null, "main.incompatible.access.flags");
   422             usage();
   423             exit();
   424         }
   425         showAccess = new ModifierFilter(filterBits);
   426     }
   428     /**
   429      * Set one arg option.
   430      * Error and exit if one argument is not provided.
   431      */
   432     private void oneArg(String[] args, int index) {
   433         if ((index + 1) < args.length) {
   434             setOption(args[index], args[index+1]);
   435         } else {
   436             usageError("main.requires_argument", args[index]);
   437         }
   438     }
   440     private void usageError(String key) {
   441         messager.error(null, key);
   442         usage();
   443         exit();
   444     }
   446     private void usageError(String key, String a1) {
   447         messager.error(null, key, a1);
   448         usage();
   449         exit();
   450     }
   452     private void usageError(String key, String a1, String a2) {
   453         messager.error(null, key, a1, a2);
   454         usage();
   455         exit();
   456     }
   458     /**
   459      * indicate an option with no arguments was given.
   460      */
   461     private void setOption(String opt) {
   462         String[] option = { opt };
   463         options.append(option);
   464     }
   466     /**
   467      * indicate an option with one argument was given.
   468      */
   469     private void setOption(String opt, String argument) {
   470         String[] option = { opt, argument };
   471         options.append(option);
   472     }
   474     /**
   475      * indicate an option with the specified list of arguments was given.
   476      */
   477     private void setOption(String opt, List<String> arguments) {
   478         String[] args = new String[arguments.length() + 1];
   479         int k = 0;
   480         args[k++] = opt;
   481         for (List<String> i = arguments; i.nonEmpty(); i=i.tail) {
   482             args[k++] = i.head;
   483         }
   484         options = options.append(args);
   485     }
   487 }

mercurial