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); |