diff -r a494e861787c -r d213951c811b langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/Start.java --- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/Start.java Fri Apr 29 14:18:09 2016 -0700 +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/Start.java Fri Apr 29 15:35:51 2016 -0700 @@ -66,6 +66,7 @@ import jdk.javadoc.doclet.DocletEnvironment; import static com.sun.tools.javac.main.Option.*; + /** * Main program of Javadoc. * Previously named "Main". @@ -79,6 +80,12 @@ * @author Neal Gafter (rewrite) */ public class Start extends ToolOption.Helper { + + private static final Class OldStdDoclet = + com.sun.tools.doclets.standard.Standard.class; + + private static final Class StdDoclet = + jdk.javadoc.internal.doclets.standard.Standard.class; /** Context for this invocation. */ private final Context context; @@ -193,18 +200,26 @@ if (foot != null) messager.notice(foot); - if (exit) exit(); + if (exit) + throw new Messager.ExitJavadoc(); } + /** - * Exit - */ - private void exit() { - messager.exit(); - } - - /** - * Main program - external wrapper + * Main program - external wrapper. In order to maintain backward + * CLI compatibility, we dispatch to the old tool or the old doclet's + * Start mechanism, based on the options present on the command line + * with the following precedence: + * 1. presence of -Xold, dispatch to old tool + * 2. doclet variant, if old, dispatch to old Start + * 3. taglet variant, if old, dispatch to old Start + * + * Thus the presence of -Xold switches the tool, soon after command files + * if any, are expanded, this is performed here, noting that the messager + * is available at this point in time. + * The doclet/taglet tests are performed in the begin method, further on, + * this is to minimize argument processing and most importantly the impact + * of class loader creation, needed to detect the doclet/taglet class variants. */ int begin(String... argv) { // Preprocess @file arguments @@ -212,14 +227,18 @@ argv = CommandLine.parse(argv); } catch (FileNotFoundException e) { messager.error("main.cant.read", e.getMessage()); - exit(); + throw new Messager.ExitJavadoc(); } catch (IOException e) { e.printStackTrace(System.err); - exit(); + throw new Messager.ExitJavadoc(); } - List argList = Arrays.asList(argv); - boolean ok = begin(argList, Collections. emptySet()); + if (argv.length > 0 && "-Xold".equals(argv[0])) { + messager.warning("main.legacy_api"); + String[] nargv = Arrays.copyOfRange(argv, 1, argv.length); + return com.sun.tools.javadoc.Main.execute(nargv); + } + boolean ok = begin(Arrays.asList(argv), Collections. emptySet()); return ok ? 0 : 1; } @@ -231,11 +250,11 @@ List opts = new ArrayList<>(); for (String opt: options) opts.add(opt); + return begin(opts, fileObjects); } private boolean begin(List options, Iterable fileObjects) { - fileManager = context.get(JavaFileManager.class); if (fileManager == null) { JavacFileManager.preRegister(context); @@ -244,9 +263,8 @@ ((BaseFileManager) fileManager).autoClose = true; } } - // locale and doclet needs to be determined first + // locale, doclet and maybe taglet, needs to be determined first docletClass = preProcess(fileManager, options); - if (jdk.javadoc.doclet.Doclet.class.isAssignableFrom(docletClass)) { // no need to dispatch to old, safe to init now initMessager(); @@ -257,7 +275,7 @@ exc.printStackTrace(); if (!apiMode) { error("main.could_not_instantiate_class", docletClass); - messager.exit(); + throw new Messager.ExitJavadoc(); } throw new ClientCodeException(exc); } @@ -267,6 +285,7 @@ = new com.sun.tools.javadoc.Start(context); return ostart.begin(docletClass, options, fileObjects); } + warn("main.legacy_api"); String[] array = options.toArray(new String[options.size()]); return com.sun.tools.javadoc.Main.execute(array) == 0; } @@ -459,6 +478,11 @@ String userDocletPath = null; String userDocletName = null; + // taglet specifying arguments, since tagletpath is a doclet + // functionality, assume they are repeated and inspect all. + List userTagletPath = new ArrayList<>(); + List userTagletNames = new ArrayList<>(); + // Step 1: loop through the args, set locale early on, if found. for (int i = 0 ; i < argv.size() ; i++) { String arg = argv.get(i); @@ -470,7 +494,7 @@ oneArg(argv, i++); if (userDocletName != null) { usageError("main.more_than_one_doclet_specified_0_and_1", - userDocletName, argv.get(i)); + userDocletName, argv.get(i)); } if (docletName != null) { usageError("main.more_than_one_doclet_specified_0_and_1", @@ -484,13 +508,20 @@ } else { userDocletPath += File.pathSeparator + argv.get(i); } + } else if ("-taglet".equals(arg)) { + userTagletNames.add(argv.get(i + 1)); + } else if ("-tagletpath".equals(arg)) { + for (String pathname : argv.get(i + 1).split(File.pathSeparator)) { + userTagletPath.add(new File(pathname)); + } } } - // Step 2: a doclet has already been provided, - // nothing more to do. + + // Step 2: a doclet is provided, nothing more to do. if (docletClass != null) { return docletClass; } + // Step 3: doclet name specified ? if so find a ClassLoader, // and load it. if (userDocletName != null) { @@ -506,38 +537,80 @@ try { ((StandardJavaFileManager)fileManager).setLocation(DOCLET_PATH, paths); } catch (IOException ioe) { - panic("main.doclet_no_classloader_found", ioe); - return null; // keep compiler happy + error("main.doclet_could_not_set_location", paths); + throw new Messager.ExitJavadoc(); } } cl = fileManager.getClassLoader(DOCLET_PATH); if (cl == null) { // despite doclet specified on cmdline no classloader found! - panic("main.doclet_no_classloader_found", userDocletName); - return null; // keep compiler happy - } - try { - Class klass = cl.loadClass(userDocletName); - ensureReadable(klass); - return klass; - } catch (ClassNotFoundException cnfe) { - panic("main.doclet_class_not_found", userDocletName); - return null; // keep compiler happy + error("main.doclet_no_classloader_found", userDocletName); + throw new Messager.ExitJavadoc(); } } + try { + Class klass = cl.loadClass(userDocletName); + ensureReadable(klass); + return klass; + } catch (ClassNotFoundException cnfe) { + error("main.doclet_class_not_found", userDocletName); + throw new Messager.ExitJavadoc(); + } } - // Step 4: we have a doclet, try loading it, otherwise - // return back the standard doclet + + // Step 4: we have a doclet, try loading it if (docletName != null) { try { return Class.forName(docletName, true, getClass().getClassLoader()); } catch (ClassNotFoundException cnfe) { - panic("main.doclet_class_not_found", userDocletName); - return null; // happy compiler, should not happen + error("main.doclet_class_not_found", userDocletName); + throw new Messager.ExitJavadoc(); } - } else { - return jdk.javadoc.internal.doclets.standard.Standard.class; + } + + // Step 5: we don't have a doclet specified, do we have taglets ? + if (!userTagletNames.isEmpty() && hasOldTaglet(userTagletNames, userTagletPath)) { + // found a bogey, return the old doclet + return OldStdDoclet; } + + // finally + return StdDoclet; + } + + /* + * This method returns true iff it finds a legacy taglet, but for + * all other conditions including errors it returns false, allowing + * nature to take its own course. + */ + private boolean hasOldTaglet(List tagletNames, List tagletPaths) { + if (!fileManager.hasLocation(TAGLET_PATH)) { + try { + ((StandardJavaFileManager) fileManager).setLocation(TAGLET_PATH, tagletPaths); + } catch (IOException ioe) { + error("main.doclet_could_not_set_location", tagletPaths); + throw new Messager.ExitJavadoc(); + } + } + ClassLoader cl = fileManager.getClassLoader(TAGLET_PATH); + if (cl == null) { + // no classloader found! + error("main.doclet_no_classloader_found", tagletNames.get(0)); + throw new Messager.ExitJavadoc(); + } + for (String tagletName : tagletNames) { + try { + Class klass = cl.loadClass(tagletName); + ensureReadable(klass); + if (com.sun.tools.doclets.Taglet.class.isAssignableFrom(klass)) { + return true; + } + } catch (ClassNotFoundException cnfe) { + error("main.doclet_class_not_found", tagletName); + throw new Messager.ExitJavadoc(); + } + } + return false; } private void parseArgs(List args, List javaNames) { @@ -595,14 +668,12 @@ usage(true); } - // a terminal call, will not return - void panic(String key, Object... args) { - error(key, args); - messager.exit(); + void error(String key, Object... args) { + messager.error(key, args); } - void error(String key, Object... args) { - messager.error(key, args); + void warn(String key, Object... args) { + messager.warning(key, args); } /**