langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/Start.java
changeset 37750 d213951c811b
parent 37393 a9ba8bd6697b
child 37757 f38cc75b6fa0
equal deleted inserted replaced
37749:a494e861787c 37750:d213951c811b
    64 import jdk.javadoc.doclet.Doclet;
    64 import jdk.javadoc.doclet.Doclet;
    65 import jdk.javadoc.doclet.Doclet.Option;
    65 import jdk.javadoc.doclet.Doclet.Option;
    66 import jdk.javadoc.doclet.DocletEnvironment;
    66 import jdk.javadoc.doclet.DocletEnvironment;
    67 
    67 
    68 import static com.sun.tools.javac.main.Option.*;
    68 import static com.sun.tools.javac.main.Option.*;
       
    69 
    69 /**
    70 /**
    70  * Main program of Javadoc.
    71  * Main program of Javadoc.
    71  * Previously named "Main".
    72  * Previously named "Main".
    72  *
    73  *
    73  *  <p><b>This is NOT part of any supported API.
    74  *  <p><b>This is NOT part of any supported API.
    77  *
    78  *
    78  * @author Robert Field
    79  * @author Robert Field
    79  * @author Neal Gafter (rewrite)
    80  * @author Neal Gafter (rewrite)
    80  */
    81  */
    81 public class Start extends ToolOption.Helper {
    82 public class Start extends ToolOption.Helper {
       
    83 
       
    84     private static final Class<?> OldStdDoclet =
       
    85             com.sun.tools.doclets.standard.Standard.class;
       
    86 
       
    87     private static final Class<?> StdDoclet =
       
    88             jdk.javadoc.internal.doclets.standard.Standard.class;
    82     /** Context for this invocation. */
    89     /** Context for this invocation. */
    83     private final Context context;
    90     private final Context context;
    84 
    91 
    85     private static final String ProgramName = "javadoc";
    92     private static final String ProgramName = "javadoc";
    86 
    93 
   191                     .forEach(opt -> messager.printNotice(opt.toString()));
   198                     .forEach(opt -> messager.printNotice(opt.toString()));
   192         }
   199         }
   193         if (foot != null)
   200         if (foot != null)
   194             messager.notice(foot);
   201             messager.notice(foot);
   195 
   202 
   196         if (exit) exit();
   203         if (exit)
   197     }
   204             throw new Messager.ExitJavadoc();
   198 
   205     }
   199     /**
   206 
   200      * Exit
   207 
   201      */
   208     /**
   202     private void exit() {
   209      * Main program - external wrapper. In order to maintain backward
   203         messager.exit();
   210      * CLI  compatibility, we dispatch to the old tool or the old doclet's
   204     }
   211      * Start mechanism, based on the options present on the command line
   205 
   212      * with the following precedence:
   206     /**
   213      *   1. presence of -Xold, dispatch to old tool
   207      * Main program - external wrapper
   214      *   2. doclet variant, if old, dispatch to old Start
       
   215      *   3. taglet variant, if old, dispatch to old Start
       
   216      *
       
   217      * Thus the presence of -Xold switches the tool, soon after command files
       
   218      * if any, are expanded, this is performed here, noting that the messager
       
   219      * is available at this point in time.
       
   220      * The doclet/taglet tests are performed in the begin method, further on,
       
   221      * this is to minimize argument processing and most importantly the impact
       
   222      * of class loader creation, needed to detect the doclet/taglet class variants.
   208      */
   223      */
   209     int begin(String... argv) {
   224     int begin(String... argv) {
   210         // Preprocess @file arguments
   225         // Preprocess @file arguments
   211         try {
   226         try {
   212             argv = CommandLine.parse(argv);
   227             argv = CommandLine.parse(argv);
   213         } catch (FileNotFoundException e) {
   228         } catch (FileNotFoundException e) {
   214             messager.error("main.cant.read", e.getMessage());
   229             messager.error("main.cant.read", e.getMessage());
   215             exit();
   230             throw new Messager.ExitJavadoc();
   216         } catch (IOException e) {
   231         } catch (IOException e) {
   217             e.printStackTrace(System.err);
   232             e.printStackTrace(System.err);
   218             exit();
   233             throw new Messager.ExitJavadoc();
   219         }
   234         }
   220 
   235 
   221         List<String> argList = Arrays.asList(argv);
   236         if (argv.length > 0 && "-Xold".equals(argv[0])) {
   222         boolean ok = begin(argList, Collections.<JavaFileObject> emptySet());
   237             messager.warning("main.legacy_api");
       
   238             String[] nargv = Arrays.copyOfRange(argv, 1, argv.length);
       
   239             return com.sun.tools.javadoc.Main.execute(nargv);
       
   240         }
       
   241         boolean ok = begin(Arrays.asList(argv), Collections.<JavaFileObject> emptySet());
   223         return ok ? 0 : 1;
   242         return ok ? 0 : 1;
   224     }
   243     }
   225 
   244 
   226     // Called by 199 API.
   245     // Called by 199 API.
   227     public boolean begin(Class<?> docletClass,
   246     public boolean begin(Class<?> docletClass,
   229             Iterable<? extends JavaFileObject> fileObjects) {
   248             Iterable<? extends JavaFileObject> fileObjects) {
   230         this.docletClass = docletClass;
   249         this.docletClass = docletClass;
   231         List<String> opts = new ArrayList<>();
   250         List<String> opts = new ArrayList<>();
   232         for (String opt: options)
   251         for (String opt: options)
   233             opts.add(opt);
   252             opts.add(opt);
       
   253 
   234         return begin(opts, fileObjects);
   254         return begin(opts, fileObjects);
   235     }
   255     }
   236 
   256 
   237     private boolean begin(List<String> options, Iterable<? extends JavaFileObject> fileObjects) {
   257     private boolean begin(List<String> options, Iterable<? extends JavaFileObject> fileObjects) {
   238 
       
   239         fileManager = context.get(JavaFileManager.class);
   258         fileManager = context.get(JavaFileManager.class);
   240         if (fileManager == null) {
   259         if (fileManager == null) {
   241             JavacFileManager.preRegister(context);
   260             JavacFileManager.preRegister(context);
   242             fileManager = context.get(JavaFileManager.class);
   261             fileManager = context.get(JavaFileManager.class);
   243             if (fileManager instanceof BaseFileManager) {
   262             if (fileManager instanceof BaseFileManager) {
   244                 ((BaseFileManager) fileManager).autoClose = true;
   263                 ((BaseFileManager) fileManager).autoClose = true;
   245             }
   264             }
   246         }
   265         }
   247         // locale and doclet needs to be determined first
   266         // locale, doclet and maybe taglet, needs to be determined first
   248         docletClass = preProcess(fileManager, options);
   267         docletClass = preProcess(fileManager, options);
   249 
       
   250         if (jdk.javadoc.doclet.Doclet.class.isAssignableFrom(docletClass)) {
   268         if (jdk.javadoc.doclet.Doclet.class.isAssignableFrom(docletClass)) {
   251             // no need to dispatch to old, safe to init now
   269             // no need to dispatch to old, safe to init now
   252             initMessager();
   270             initMessager();
   253             messager.setLocale(locale);
   271             messager.setLocale(locale);
   254             try {
   272             try {
   255                 doclet = (Doclet) docletClass.newInstance();
   273                 doclet = (Doclet) docletClass.newInstance();
   256             } catch (InstantiationException | IllegalAccessException exc) {
   274             } catch (InstantiationException | IllegalAccessException exc) {
   257                 exc.printStackTrace();
   275                 exc.printStackTrace();
   258                 if (!apiMode) {
   276                 if (!apiMode) {
   259                     error("main.could_not_instantiate_class", docletClass);
   277                     error("main.could_not_instantiate_class", docletClass);
   260                     messager.exit();
   278                     throw new Messager.ExitJavadoc();
   261                 }
   279                 }
   262                 throw new ClientCodeException(exc);
   280                 throw new ClientCodeException(exc);
   263             }
   281             }
   264         } else {
   282         } else {
   265             if (this.apiMode) {
   283             if (this.apiMode) {
   266                 com.sun.tools.javadoc.Start ostart
   284                 com.sun.tools.javadoc.Start ostart
   267                         = new com.sun.tools.javadoc.Start(context);
   285                         = new com.sun.tools.javadoc.Start(context);
   268                 return ostart.begin(docletClass, options, fileObjects);
   286                 return ostart.begin(docletClass, options, fileObjects);
   269             }
   287             }
       
   288             warn("main.legacy_api");
   270             String[] array = options.toArray(new String[options.size()]);
   289             String[] array = options.toArray(new String[options.size()]);
   271             return com.sun.tools.javadoc.Main.execute(array) == 0;
   290             return com.sun.tools.javadoc.Main.execute(array) == 0;
   272         }
   291         }
   273 
   292 
   274         boolean failed = false;
   293         boolean failed = false;
   457     private Class<?> preProcess(JavaFileManager jfm, List<String> argv) {
   476     private Class<?> preProcess(JavaFileManager jfm, List<String> argv) {
   458         // doclet specifying arguments
   477         // doclet specifying arguments
   459         String userDocletPath = null;
   478         String userDocletPath = null;
   460         String userDocletName = null;
   479         String userDocletName = null;
   461 
   480 
       
   481         // taglet specifying arguments, since tagletpath is a doclet
       
   482         // functionality, assume they are repeated and inspect all.
       
   483         List<File> userTagletPath = new ArrayList<>();
       
   484         List<String> userTagletNames = new ArrayList<>();
       
   485 
   462         // Step 1: loop through the args, set locale early on, if found.
   486         // Step 1: loop through the args, set locale early on, if found.
   463         for (int i = 0 ; i < argv.size() ; i++) {
   487         for (int i = 0 ; i < argv.size() ; i++) {
   464             String arg = argv.get(i);
   488             String arg = argv.get(i);
   465             if (arg.equals(ToolOption.LOCALE.opt)) {
   489             if (arg.equals(ToolOption.LOCALE.opt)) {
   466                 oneArg(argv, i++);
   490                 oneArg(argv, i++);
   468                 locale = getLocale(lname);
   492                 locale = getLocale(lname);
   469             } else if (arg.equals(ToolOption.DOCLET.opt)) {
   493             } else if (arg.equals(ToolOption.DOCLET.opt)) {
   470                 oneArg(argv, i++);
   494                 oneArg(argv, i++);
   471                 if (userDocletName != null) {
   495                 if (userDocletName != null) {
   472                     usageError("main.more_than_one_doclet_specified_0_and_1",
   496                     usageError("main.more_than_one_doclet_specified_0_and_1",
   473                                userDocletName, argv.get(i));
   497                             userDocletName, argv.get(i));
   474                 }
   498                 }
   475                 if (docletName != null) {
   499                 if (docletName != null) {
   476                     usageError("main.more_than_one_doclet_specified_0_and_1",
   500                     usageError("main.more_than_one_doclet_specified_0_and_1",
   477                             docletName, argv.get(i));
   501                             docletName, argv.get(i));
   478                 }
   502                 }
   482                 if (userDocletPath == null) {
   506                 if (userDocletPath == null) {
   483                     userDocletPath = argv.get(i);
   507                     userDocletPath = argv.get(i);
   484                 } else {
   508                 } else {
   485                     userDocletPath += File.pathSeparator + argv.get(i);
   509                     userDocletPath += File.pathSeparator + argv.get(i);
   486                 }
   510                 }
   487             }
   511             } else if ("-taglet".equals(arg)) {
   488         }
   512                 userTagletNames.add(argv.get(i + 1));
   489         // Step 2: a doclet has already been provided,
   513             } else if ("-tagletpath".equals(arg)) {
   490         // nothing more to do.
   514                 for (String pathname : argv.get(i + 1).split(File.pathSeparator)) {
       
   515                     userTagletPath.add(new File(pathname));
       
   516                 }
       
   517             }
       
   518         }
       
   519 
       
   520         // Step 2: a doclet is provided, nothing more to do.
   491         if (docletClass != null) {
   521         if (docletClass != null) {
   492             return docletClass;
   522             return docletClass;
   493         }
   523         }
       
   524 
   494         // Step 3: doclet name specified ? if so find a ClassLoader,
   525         // Step 3: doclet name specified ? if so find a ClassLoader,
   495         // and load it.
   526         // and load it.
   496         if (userDocletName != null) {
   527         if (userDocletName != null) {
   497             ClassLoader cl = classLoader;
   528             ClassLoader cl = classLoader;
   498             if (cl == null) {
   529             if (cl == null) {
   504                         }
   535                         }
   505                     }
   536                     }
   506                     try {
   537                     try {
   507                         ((StandardJavaFileManager)fileManager).setLocation(DOCLET_PATH, paths);
   538                         ((StandardJavaFileManager)fileManager).setLocation(DOCLET_PATH, paths);
   508                     } catch (IOException ioe) {
   539                     } catch (IOException ioe) {
   509                         panic("main.doclet_no_classloader_found", ioe);
   540                         error("main.doclet_could_not_set_location", paths);
   510                         return null; // keep compiler happy
   541                         throw new Messager.ExitJavadoc();
   511                     }
   542                     }
   512                 }
   543                 }
   513                 cl = fileManager.getClassLoader(DOCLET_PATH);
   544                 cl = fileManager.getClassLoader(DOCLET_PATH);
   514                 if (cl == null) {
   545                 if (cl == null) {
   515                     // despite doclet specified on cmdline no classloader found!
   546                     // despite doclet specified on cmdline no classloader found!
   516                     panic("main.doclet_no_classloader_found", userDocletName);
   547                     error("main.doclet_no_classloader_found", userDocletName);
   517                     return null; // keep compiler happy
   548                     throw new Messager.ExitJavadoc();
   518                 }
   549                 }
   519                 try {
   550             }
   520                     Class<?> klass = cl.loadClass(userDocletName);
   551             try {
   521                     ensureReadable(klass);
   552                 Class<?> klass = cl.loadClass(userDocletName);
   522                     return klass;
   553                 ensureReadable(klass);
   523                 } catch (ClassNotFoundException cnfe) {
   554                 return klass;
   524                     panic("main.doclet_class_not_found", userDocletName);
   555             } catch (ClassNotFoundException cnfe) {
   525                     return null; // keep compiler happy
   556                 error("main.doclet_class_not_found", userDocletName);
   526                 }
   557                 throw new Messager.ExitJavadoc();
   527             }
   558             }
   528         }
   559         }
   529         // Step 4: we have a doclet, try loading it, otherwise
   560 
   530         // return back the standard doclet
   561         // Step 4: we have a doclet, try loading it
   531         if (docletName != null) {
   562         if (docletName != null) {
   532             try {
   563             try {
   533                 return Class.forName(docletName, true, getClass().getClassLoader());
   564                 return Class.forName(docletName, true, getClass().getClassLoader());
   534             } catch (ClassNotFoundException cnfe) {
   565             } catch (ClassNotFoundException cnfe) {
   535                 panic("main.doclet_class_not_found", userDocletName);
   566                 error("main.doclet_class_not_found", userDocletName);
   536                 return null; // happy compiler, should not happen
   567                 throw new Messager.ExitJavadoc();
   537             }
   568             }
   538         } else {
   569         }
   539             return jdk.javadoc.internal.doclets.standard.Standard.class;
   570 
   540         }
   571         // Step 5: we don't have a doclet specified, do we have taglets ?
       
   572         if (!userTagletNames.isEmpty() && hasOldTaglet(userTagletNames, userTagletPath)) {
       
   573             // found a bogey, return the old doclet
       
   574             return OldStdDoclet;
       
   575         }
       
   576 
       
   577         // finally
       
   578         return StdDoclet;
       
   579     }
       
   580 
       
   581     /*
       
   582      * This method returns true iff it finds a legacy taglet, but for
       
   583      * all other conditions including errors it returns false, allowing
       
   584      * nature to take its own course.
       
   585      */
       
   586     private boolean hasOldTaglet(List<String> tagletNames, List<File> tagletPaths) {
       
   587         if (!fileManager.hasLocation(TAGLET_PATH)) {
       
   588             try {
       
   589                 ((StandardJavaFileManager) fileManager).setLocation(TAGLET_PATH, tagletPaths);
       
   590             } catch (IOException ioe) {
       
   591                 error("main.doclet_could_not_set_location", tagletPaths);
       
   592                 throw new Messager.ExitJavadoc();
       
   593             }
       
   594         }
       
   595         ClassLoader cl = fileManager.getClassLoader(TAGLET_PATH);
       
   596         if (cl == null) {
       
   597             // no classloader found!
       
   598             error("main.doclet_no_classloader_found", tagletNames.get(0));
       
   599             throw new Messager.ExitJavadoc();
       
   600         }
       
   601         for (String tagletName : tagletNames) {
       
   602             try {
       
   603                 Class<?> klass = cl.loadClass(tagletName);
       
   604                 ensureReadable(klass);
       
   605                 if (com.sun.tools.doclets.Taglet.class.isAssignableFrom(klass)) {
       
   606                     return true;
       
   607                 }
       
   608             } catch (ClassNotFoundException cnfe) {
       
   609                 error("main.doclet_class_not_found", tagletName);
       
   610                 throw new Messager.ExitJavadoc();
       
   611             }
       
   612         }
       
   613         return false;
   541     }
   614     }
   542 
   615 
   543     private void parseArgs(List<String> args, List<String> javaNames) {
   616     private void parseArgs(List<String> args, List<String> javaNames) {
   544         for (int i = 0 ; i < args.size() ; i++) {
   617         for (int i = 0 ; i < args.size() ; i++) {
   545             String arg = args.get(i);
   618             String arg = args.get(i);
   593     void usageError(String key, Object... args) {
   666     void usageError(String key, Object... args) {
   594         error(key, args);
   667         error(key, args);
   595         usage(true);
   668         usage(true);
   596     }
   669     }
   597 
   670 
   598     // a terminal call, will not return
       
   599     void panic(String key, Object... args) {
       
   600         error(key, args);
       
   601         messager.exit();
       
   602     }
       
   603 
       
   604     void error(String key, Object... args) {
   671     void error(String key, Object... args) {
   605         messager.error(key, args);
   672         messager.error(key, args);
       
   673     }
       
   674 
       
   675     void warn(String key, Object... args)  {
       
   676         messager.warning(key, args);
   606     }
   677     }
   607 
   678 
   608     /**
   679     /**
   609      * indicate an option with no arguments was given.
   680      * indicate an option with no arguments was given.
   610      */
   681      */