Start.java revision 3294:9adfb22ff08f
1238384Sjkim/* 2238384Sjkim * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. 3238384Sjkim * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4238384Sjkim * 5238384Sjkim * This code is free software; you can redistribute it and/or modify it 6238384Sjkim * under the terms of the GNU General Public License version 2 only, as 7238384Sjkim * published by the Free Software Foundation. Oracle designates this 8238384Sjkim * particular file as subject to the "Classpath" exception as provided 9238384Sjkim * by Oracle in the LICENSE file that accompanied this code. 10238384Sjkim * 11238384Sjkim * This code is distributed in the hope that it will be useful, but WITHOUT 12238384Sjkim * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13238384Sjkim * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14238384Sjkim * version 2 for more details (a copy is included in the LICENSE file that 15238384Sjkim * accompanied this code). 16238384Sjkim * 17238384Sjkim * You should have received a copy of the GNU General Public License version 18238384Sjkim * 2 along with this work; if not, write to the Free Software Foundation, 19238384Sjkim * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20238384Sjkim * 21238384Sjkim * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22238384Sjkim * or visit www.oracle.com if you need additional information or have any 23238384Sjkim * questions. 24238384Sjkim */ 25238384Sjkim 26238384Sjkimpackage jdk.javadoc.internal.tool; 27238384Sjkim 28238384Sjkimimport java.io.File; 29238384Sjkimimport java.io.FileNotFoundException; 30238384Sjkimimport java.io.IOException; 31280297Sjkimimport java.io.PrintWriter; 32280297Sjkimimport java.lang.reflect.Method; 33280297Sjkimimport java.nio.file.Path; 34280297Sjkimimport java.text.BreakIterator; 35280297Sjkimimport java.util.ArrayList; 36238384Sjkimimport java.util.Arrays; 37280297Sjkimimport java.util.Collection; 38280297Sjkimimport java.util.Collections; 39280297Sjkimimport java.util.List; 40352193Sjkimimport java.util.Locale; 41238384Sjkimimport java.util.Objects; 42280297Sjkimimport java.util.Set; 43238384Sjkim 44280297Sjkimimport static javax.tools.DocumentationTool.Location.*; 45280297Sjkim 46280297Sjkimimport javax.tools.JavaFileManager; 47280297Sjkimimport javax.tools.JavaFileObject; 48280297Sjkimimport javax.tools.StandardJavaFileManager; 49238384Sjkimimport javax.tools.StandardLocation; 50238384Sjkim 51238384Sjkimimport com.sun.tools.javac.api.JavacTrees; 52238384Sjkimimport com.sun.tools.javac.file.BaseFileManager; 53238384Sjkimimport com.sun.tools.javac.file.JavacFileManager; 54280297Sjkimimport com.sun.tools.javac.main.CommandLine; 55280297Sjkimimport com.sun.tools.javac.platform.PlatformDescription; 56238384Sjkimimport com.sun.tools.javac.platform.PlatformUtils; 57238384Sjkimimport com.sun.tools.javac.util.ClientCodeException; 58238384Sjkimimport com.sun.tools.javac.util.Context; 59238384Sjkimimport com.sun.tools.javac.util.Log; 60238384Sjkimimport com.sun.tools.javac.util.Options; 61238384Sjkim 62238384Sjkimimport jdk.javadoc.doclet.Doclet; 63238384Sjkimimport jdk.javadoc.doclet.Doclet.Option; 64238384Sjkimimport jdk.javadoc.doclet.DocletEnvironment; 65238384Sjkim 66238384Sjkimimport static com.sun.tools.javac.main.Option.*; 67238384Sjkim/** 68238384Sjkim * Main program of Javadoc. 69238384Sjkim * Previously named "Main". 70238384Sjkim * 71238384Sjkim * <p><b>This is NOT part of any supported API. 72238384Sjkim * If you write code that depends on this, you do so at your own risk. 73238384Sjkim * This code and its internal interfaces are subject to change or 74238384Sjkim * deletion without notice.</b> 75238384Sjkim * 76238384Sjkim * @author Robert Field 77238384Sjkim * @author Neal Gafter (rewrite) 78238384Sjkim */ 79280297Sjkimpublic class Start extends ToolOption.Helper { 80280297Sjkim /** Context for this invocation. */ 81280297Sjkim private final Context context; 82280297Sjkim 83280297Sjkim private static final String ProgramName = "javadoc"; 84238384Sjkim 85238384Sjkim // meaning we allow all visibility of PROTECTED and PUBLIC 86238384Sjkim private static final String defaultModifier = "protected"; 87280297Sjkim 88280297Sjkim private Messager messager; 89280297Sjkim 90280297Sjkim private final String docletName; 91280297Sjkim 92280297Sjkim private final ClassLoader classLoader; 93280297Sjkim 94280297Sjkim private Class<?> docletClass; 95280297Sjkim 96280297Sjkim private Doclet doclet; 97280297Sjkim 98280297Sjkim // used to determine the locale for the messager 99280297Sjkim private Locale locale; 100280297Sjkim 101280297Sjkim 102238384Sjkim /** 103238384Sjkim * In API mode, exceptions thrown while calling the doclet are 104280297Sjkim * propagated using ClientCodeException. 105280297Sjkim */ 106238384Sjkim private boolean apiMode; 107238384Sjkim 108238384Sjkim private JavaFileManager fileManager; 109238384Sjkim 110238384Sjkim Start() { 111238384Sjkim this(null, null, null, null, null); 112238384Sjkim } 113238384Sjkim 114238384Sjkim Start(PrintWriter writer) { 115238384Sjkim this(null, null, writer, null, null); 116238384Sjkim } 117238384Sjkim 118238384Sjkim Start(Context context, String programName, PrintWriter writer, 119238384Sjkim String docletName, ClassLoader classLoader) { 120238384Sjkim this.context = context == null ? new Context() : context; 121238384Sjkim String pname = programName == null ? ProgramName : programName; 122238384Sjkim this.messager = writer == null 123238384Sjkim ? new Messager(this.context, pname) 124238384Sjkim : new Messager(this.context, pname, writer, writer); 125238384Sjkim this.docletName = docletName; 126238384Sjkim this.classLoader = classLoader; 127238384Sjkim this.docletClass = null; 128238384Sjkim this.locale = Locale.getDefault(); 129238384Sjkim } 130238384Sjkim 131238384Sjkim public Start(Context context) { 132238384Sjkim this.docletClass = null; 133238384Sjkim this.context = Objects.requireNonNull(context); 134238384Sjkim this.apiMode = true; 135280297Sjkim this.docletName = null; 136280297Sjkim this.classLoader = null; 137280297Sjkim this.locale = Locale.getDefault(); 138280297Sjkim } 139280297Sjkim 140280297Sjkim void initMessager() { 141280297Sjkim if (!apiMode) 142280297Sjkim return; 143280297Sjkim if (messager == null) { 144280297Sjkim Log log = context.get(Log.logKey); 145280297Sjkim if (log instanceof Messager) { 146280297Sjkim messager = (Messager) log; 147280297Sjkim } else { 148280297Sjkim PrintWriter out = context.get(Log.outKey); 149280297Sjkim messager = (out == null) 150280297Sjkim ? new Messager(context, ProgramName) 151280297Sjkim : new Messager(context, ProgramName, out, out); 152280297Sjkim } 153280297Sjkim } 154280297Sjkim } 155280297Sjkim 156280297Sjkim /** 157280297Sjkim * Usage 158280297Sjkim */ 159280297Sjkim @Override 160280297Sjkim void usage() { 161280297Sjkim usage(true); 162280297Sjkim } 163280297Sjkim 164280297Sjkim void usage(boolean exit) { 165280297Sjkim usage("main.usage", "-help", null, exit); 166280297Sjkim } 167280297Sjkim 168280297Sjkim @Override 169280297Sjkim void Xusage() { 170280297Sjkim Xusage(true); 171280297Sjkim } 172280297Sjkim 173280297Sjkim void Xusage(boolean exit) { 174280297Sjkim usage("main.Xusage", "-X", "main.Xusage.foot", exit); 175280297Sjkim } 176280297Sjkim 177280297Sjkim private void usage(String main, String option, String foot, boolean exit) { 178280297Sjkim messager.notice(main); 179280297Sjkim // let doclet print usage information (does nothing on error) 180280297Sjkim if (docletClass != null) { 181280297Sjkim String name = doclet.getName(); 182280297Sjkim Set<Option> supportedOptions = doclet.getSupportedOptions(); 183280297Sjkim messager.notice("main.doclet.usage.header", name); 184280297Sjkim Option.Kind myKind = option.equals("-X") 185280297Sjkim ? Option.Kind.EXTENDED 186280297Sjkim : Option.Kind.STANDARD; 187280297Sjkim supportedOptions.stream() 188280297Sjkim .filter(opt -> opt.getKind() == myKind) 189280297Sjkim .forEach(opt -> messager.printNotice(opt.toString())); 190280297Sjkim } 191280297Sjkim if (foot != null) 192280297Sjkim messager.notice(foot); 193280297Sjkim 194280297Sjkim if (exit) exit(); 195280297Sjkim } 196280297Sjkim 197280297Sjkim /** 198280297Sjkim * Exit 199280297Sjkim */ 200280297Sjkim private void exit() { 201280297Sjkim messager.exit(); 202280297Sjkim } 203280297Sjkim 204280297Sjkim /** 205280297Sjkim * Main program - external wrapper 206280297Sjkim */ 207280297Sjkim int begin(String... argv) { 208280297Sjkim // Preprocess @file arguments 209280297Sjkim try { 210280297Sjkim argv = CommandLine.parse(argv); 211280297Sjkim } catch (FileNotFoundException e) { 212280297Sjkim messager.error("main.cant.read", e.getMessage()); 213280297Sjkim exit(); 214280297Sjkim } catch (IOException e) { 215280297Sjkim e.printStackTrace(System.err); 216280297Sjkim exit(); 217280297Sjkim } 218280297Sjkim 219280297Sjkim List<String> argList = Arrays.asList(argv); 220280297Sjkim boolean ok = begin(argList, Collections.<JavaFileObject> emptySet()); 221280297Sjkim return ok ? 0 : 1; 222280297Sjkim } 223280297Sjkim 224280297Sjkim // Called by 199 API. 225280297Sjkim public boolean begin(Class<?> docletClass, 226280297Sjkim Iterable<String> options, 227280297Sjkim Iterable<? extends JavaFileObject> fileObjects) { 228280297Sjkim this.docletClass = docletClass; 229280297Sjkim List<String> opts = new ArrayList<>(); 230280297Sjkim for (String opt: options) 231280297Sjkim opts.add(opt); 232280297Sjkim return begin(opts, fileObjects); 233280297Sjkim } 234280297Sjkim 235280297Sjkim private boolean begin(List<String> options, Iterable<? extends JavaFileObject> fileObjects) { 236280297Sjkim 237280297Sjkim fileManager = context.get(JavaFileManager.class); 238280297Sjkim if (fileManager == null) { 239280297Sjkim JavacFileManager.preRegister(context); 240280297Sjkim fileManager = context.get(JavaFileManager.class); 241280297Sjkim if (fileManager instanceof BaseFileManager) { 242280297Sjkim ((BaseFileManager) fileManager).autoClose = true; 243280297Sjkim } 244280297Sjkim } 245280297Sjkim // locale and doclet needs to be determined first 246280297Sjkim docletClass = preProcess(fileManager, options); 247280297Sjkim 248280297Sjkim if (jdk.javadoc.doclet.Doclet.class.isAssignableFrom(docletClass)) { 249280297Sjkim // no need to dispatch to old, safe to init now 250280297Sjkim initMessager(); 251280297Sjkim messager.setLocale(locale); 252280297Sjkim try { 253280297Sjkim doclet = (Doclet) docletClass.newInstance(); 254280297Sjkim } catch (InstantiationException | IllegalAccessException exc) { 255280297Sjkim exc.printStackTrace(); 256280297Sjkim if (!apiMode) { 257280297Sjkim error("main.could_not_instantiate_class", docletClass); 258280297Sjkim messager.exit(); 259280297Sjkim } 260280297Sjkim throw new ClientCodeException(exc); 261280297Sjkim } 262238384Sjkim } else { 263238384Sjkim if (this.apiMode) { 264238384Sjkim com.sun.tools.javadoc.Start ostart 265280297Sjkim = new com.sun.tools.javadoc.Start(context); 266280297Sjkim return ostart.begin(docletClass, options, fileObjects); 267238384Sjkim } 268238384Sjkim String[] array = options.toArray(new String[options.size()]); 269238384Sjkim return com.sun.tools.javadoc.Main.execute(array) == 0; 270280297Sjkim } 271280297Sjkim 272280297Sjkim boolean failed = false; 273280297Sjkim try { 274280297Sjkim failed = !parseAndExecute(options, fileObjects); 275280297Sjkim } catch (Messager.ExitJavadoc exc) { 276280297Sjkim // ignore, we just exit this way 277280297Sjkim } catch (OutOfMemoryError ee) { 278280297Sjkim messager.error("main.out.of.memory"); 279280297Sjkim failed = true; 280280297Sjkim } catch (ClientCodeException e) { 281280297Sjkim // simply rethrow these exceptions, to be caught and handled by JavadocTaskImpl 282280297Sjkim throw e; 283280297Sjkim } catch (Error ee) { 284280297Sjkim ee.printStackTrace(System.err); 285280297Sjkim messager.error("main.fatal.error"); 286280297Sjkim failed = true; 287280297Sjkim } catch (Exception ee) { 288280297Sjkim ee.printStackTrace(System.err); 289280297Sjkim messager.error("main.fatal.exception"); 290280297Sjkim failed = true; 291280297Sjkim } finally { 292280297Sjkim if (fileManager != null 293280297Sjkim && fileManager instanceof BaseFileManager 294280297Sjkim && ((BaseFileManager) fileManager).autoClose) { 295280297Sjkim try { 296280297Sjkim fileManager.close(); 297280297Sjkim } catch (IOException ignore) {} 298280297Sjkim } 299280297Sjkim boolean haveErrorWarnings = messager.nerrors() > 0 || 300280297Sjkim (rejectWarnings && messager.nwarnings() > 0); 301280297Sjkim if (failed && !haveErrorWarnings) { 302280297Sjkim // the doclet failed, but nothing reported, flag it!. 303280297Sjkim messager.error("main.unknown.error"); 304280297Sjkim } 305280297Sjkim failed |= haveErrorWarnings; 306280297Sjkim messager.exitNotice(); 307280297Sjkim messager.flush(); 308280297Sjkim } 309280297Sjkim return !failed; 310280297Sjkim } 311280297Sjkim 312238384Sjkim /** 313280297Sjkim * Ensures that the module of the given class is readable to this 314280297Sjkim * module. 315238384Sjkim * @param targetClass class in module to be made readable 316280297Sjkim */ 317280297Sjkim private void ensureReadable(Class<?> targetClass) { 318280297Sjkim try { 319238384Sjkim Method getModuleMethod = Class.class.getMethod("getModule"); 320280297Sjkim Object thisModule = getModuleMethod.invoke(this.getClass()); 321280297Sjkim Object targetModule = getModuleMethod.invoke(targetClass); 322280297Sjkim 323280297Sjkim Class<?> moduleClass = getModuleMethod.getReturnType(); 324280297Sjkim Method addReadsMethod = moduleClass.getMethod("addReads", moduleClass); 325280297Sjkim addReadsMethod.invoke(thisModule, targetModule); 326238384Sjkim } catch (NoSuchMethodException e) { 327238384Sjkim // ignore 328280297Sjkim } catch (Exception e) { 329280297Sjkim throw new InternalError(e); 330280297Sjkim } 331280297Sjkim } 332280297Sjkim 333280297Sjkim /** 334280297Sjkim * Main program - internal 335280297Sjkim */ 336280297Sjkim private boolean parseAndExecute(List<String> argList, 337238384Sjkim Iterable<? extends JavaFileObject> fileObjects) throws IOException { 338238384Sjkim long tm = System.currentTimeMillis(); 339238384Sjkim 340280297Sjkim List<String> javaNames = new ArrayList<>(); 341280297Sjkim 342352193Sjkim compOpts = Options.instance(context); 343238384Sjkim 344352193Sjkim // Make sure no obsolete source/target messages are reported 345280297Sjkim compOpts.put("-Xlint:-options", "-Xlint:-options"); 346280297Sjkim 347280297Sjkim doclet.init(locale, messager); 348352193Sjkim parseArgs(argList, javaNames); 349352193Sjkim 350280297Sjkim if (fileManager instanceof BaseFileManager) { 351280297Sjkim ((BaseFileManager) fileManager).handleOptions(fileManagerOpts); 352280297Sjkim } 353280297Sjkim 354280297Sjkim String platformString = compOpts.get("-release"); 355280297Sjkim 356238384Sjkim if (platformString != null) { 357238384Sjkim if (compOpts.isSet("-source")) { 358238384Sjkim usageError("main.release.bootclasspath.conflict", "-source"); 359280297Sjkim } 360352193Sjkim if (fileManagerOpts.containsKey(BOOTCLASSPATH)) { 361352193Sjkim usageError("main.release.bootclasspath.conflict", BOOTCLASSPATH.getText()); 362352193Sjkim } 363280297Sjkim 364238384Sjkim PlatformDescription platformDescription = 365238384Sjkim PlatformUtils.lookupPlatformDescription(platformString); 366280297Sjkim 367280297Sjkim if (platformDescription == null) { 368238384Sjkim usageError("main.unsupported.release.version", platformString); 369238384Sjkim } 370238384Sjkim 371238384Sjkim compOpts.put(SOURCE, platformDescription.getSourceVersion()); 372238384Sjkim 373238384Sjkim context.put(PlatformDescription.class, platformDescription); 374238384Sjkim 375238384Sjkim Collection<Path> platformCP = platformDescription.getPlatformPath(); 376238384Sjkim 377280297Sjkim if (platformCP != null) { 378280297Sjkim if (fileManager instanceof StandardJavaFileManager) { 379280297Sjkim StandardJavaFileManager sfm = (StandardJavaFileManager) fileManager; 380280297Sjkim 381280297Sjkim sfm.setLocationFromPaths(StandardLocation.PLATFORM_CLASS_PATH, platformCP); 382280297Sjkim } else { 383238384Sjkim usageError("main.release.not.standard.file.manager", platformString); 384238384Sjkim } 385280297Sjkim } 386280297Sjkim } 387280297Sjkim 388280297Sjkim compOpts.notifyListeners(); 389280297Sjkim 390280297Sjkim if (javaNames.isEmpty() && subPackages.isEmpty() && isEmpty(fileObjects)) { 391238384Sjkim usageError("main.No_packages_or_classes_specified"); 392238384Sjkim } 393238384Sjkim 394280297Sjkim JavadocTool comp = JavadocTool.make0(context); 395280297Sjkim if (comp == null) return false; 396280297Sjkim 397280297Sjkim if (showAccess == null) { 398280297Sjkim setFilter(defaultModifier); 399280297Sjkim } 400238384Sjkim 401238384Sjkim DocletEnvironment root = comp.getEnvironment( 402238384Sjkim encoding, 403238384Sjkim showAccess, 404280297Sjkim overviewpath, 405280297Sjkim javaNames, 406280297Sjkim fileObjects, 407280297Sjkim subPackages, 408280297Sjkim excludedPackages, 409238384Sjkim docClasses, 410280297Sjkim quiet); 411280297Sjkim 412280297Sjkim // release resources 413280297Sjkim comp = null; 414280297Sjkim 415280297Sjkim if (breakiterator || !locale.getLanguage().equals(Locale.ENGLISH.getLanguage())) { 416238384Sjkim JavacTrees trees = JavacTrees.instance(context); 417238384Sjkim trees.setBreakIterator(BreakIterator.getSentenceInstance(locale)); 418238384Sjkim } 419238384Sjkim // pass off control to the doclet 420280297Sjkim boolean ok = root != null; 421280297Sjkim if (ok) ok = doclet.run(root); 422280297Sjkim 423280297Sjkim // We're done. 424280297Sjkim if (compOpts.get("-verbose") != null) { 425238384Sjkim tm = System.currentTimeMillis() - tm; 426280297Sjkim messager.notice("main.done_in", Long.toString(tm)); 427280297Sjkim } 428280297Sjkim 429280297Sjkim return ok; 430280297Sjkim } 431238384Sjkim 432280297Sjkim Set<Doclet.Option> docletOptions = null; 433280297Sjkim int handleDocletOptions(int idx, List<String> args, boolean isToolOption) { 434280297Sjkim if (docletOptions == null) { 435280297Sjkim docletOptions = doclet.getSupportedOptions(); 436280297Sjkim } 437238384Sjkim String arg = args.get(idx); 438238384Sjkim 439238384Sjkim for (Doclet.Option opt : docletOptions) { 440238384Sjkim if (opt.matches(arg)) { 441280297Sjkim if (args.size() - idx < opt.getArgumentCount()) { 442280297Sjkim usageError("main.requires_argument", arg); 443280297Sjkim } 444280297Sjkim opt.process(arg, args.listIterator(idx + 1)); 445280297Sjkim idx += opt.getArgumentCount(); 446280297Sjkim return idx; 447238384Sjkim } 448280297Sjkim } 449280297Sjkim // check if arg is accepted by the tool before emitting error 450280297Sjkim if (!isToolOption) 451280297Sjkim usageError("main.invalid_flag", arg); 452280297Sjkim return idx; 453280297Sjkim } 454280297Sjkim 455280297Sjkim private Class<?> preProcess(JavaFileManager jfm, List<String> argv) { 456238384Sjkim // doclet specifying arguments 457280297Sjkim String userDocletPath = null; 458280297Sjkim String userDocletName = null; 459280297Sjkim 460280297Sjkim // Step 1: loop through the args, set locale early on, if found. 461280297Sjkim for (int i = 0 ; i < argv.size() ; i++) { 462280297Sjkim String arg = argv.get(i); 463280297Sjkim if (arg.equals(ToolOption.LOCALE.opt)) { 464280297Sjkim oneArg(argv, i++); 465238384Sjkim String lname = argv.get(i); 466238384Sjkim locale = getLocale(lname); 467238384Sjkim } else if (arg.equals(ToolOption.DOCLET.opt)) { 468238384Sjkim oneArg(argv, i++); 469280297Sjkim if (userDocletName != null) { 470280297Sjkim usageError("main.more_than_one_doclet_specified_0_and_1", 471280297Sjkim userDocletName, argv.get(i)); 472280297Sjkim } 473280297Sjkim if (docletName != null) { 474280297Sjkim usageError("main.more_than_one_doclet_specified_0_and_1", 475280297Sjkim docletName, argv.get(i)); 476238384Sjkim } 477280297Sjkim userDocletName = argv.get(i); 478280297Sjkim } else if (arg.equals(ToolOption.DOCLETPATH.opt)) { 479280297Sjkim oneArg(argv, i++); 480280297Sjkim if (userDocletPath == null) { 481280297Sjkim userDocletPath = argv.get(i); 482238384Sjkim } else { 483280297Sjkim userDocletPath += File.pathSeparator + argv.get(i); 484280297Sjkim } 485280297Sjkim } 486280297Sjkim } 487280297Sjkim // Step 2: a doclet has already been provided, 488238384Sjkim // nothing more to do. 489280297Sjkim if (docletClass != null) { 490280297Sjkim return docletClass; 491280297Sjkim } 492280297Sjkim // Step 3: doclet name specified ? if so find a ClassLoader, 493238384Sjkim // and load it. 494280297Sjkim if (userDocletName != null) { 495280297Sjkim ClassLoader cl = classLoader; 496280297Sjkim if (cl == null) { 497280297Sjkim if (!fileManager.hasLocation(DOCLET_PATH)) { 498280297Sjkim List<File> paths = new ArrayList<>(); 499280297Sjkim if (userDocletPath != null) { 500238384Sjkim for (String pathname : userDocletPath.split(File.pathSeparator)) { 501280297Sjkim paths.add(new File(pathname)); 502280297Sjkim } 503280297Sjkim } 504280297Sjkim try { 505238384Sjkim ((StandardJavaFileManager)fileManager).setLocation(DOCLET_PATH, paths); 506280297Sjkim } catch (IOException ioe) { 507280297Sjkim panic("main.doclet_no_classloader_found", ioe); 508280297Sjkim return null; // keep compiler happy 509280297Sjkim } 510280297Sjkim } 511280297Sjkim cl = fileManager.getClassLoader(DOCLET_PATH); 512280297Sjkim if (cl == null) { 513280297Sjkim // despite doclet specified on cmdline no classloader found! 514280297Sjkim panic("main.doclet_no_classloader_found", userDocletName); 515238384Sjkim return null; // keep compiler happy 516238384Sjkim } 517238384Sjkim try { 518280297Sjkim Class<?> klass = cl.loadClass(userDocletName); 519280297Sjkim ensureReadable(klass); 520280297Sjkim return klass; 521280297Sjkim } catch (ClassNotFoundException cnfe) { 522280297Sjkim panic("main.doclet_class_not_found", userDocletName); 523280297Sjkim return null; // keep compiler happy 524280297Sjkim } 525280297Sjkim } 526280297Sjkim } 527280297Sjkim // Step 4: we have a doclet, try loading it, otherwise 528280297Sjkim // return back the standard doclet 529280297Sjkim if (docletName != null) { 530280297Sjkim try { 531238384Sjkim return Class.forName(docletName, true, getClass().getClassLoader()); 532238384Sjkim } catch (ClassNotFoundException cnfe) { 533238384Sjkim panic("main.doclet_class_not_found", userDocletName); 534280297Sjkim return null; // happy compiler, should not happen 535280297Sjkim } 536280297Sjkim } else { 537280297Sjkim return jdk.javadoc.internal.doclets.standard.Standard.class; 538280297Sjkim } 539280297Sjkim } 540280297Sjkim 541280297Sjkim private void parseArgs(List<String> args, List<String> javaNames) { 542280297Sjkim for (int i = 0 ; i < args.size() ; i++) { 543280297Sjkim String arg = args.get(i); 544280297Sjkim ToolOption o = ToolOption.get(arg); 545280297Sjkim if (o != null) { 546238384Sjkim // handle a doclet argument that may be needed however 547280297Sjkim // don't increment the index, and allow the tool to consume args 548280297Sjkim handleDocletOptions(i, args, true); 549238384Sjkim 550238384Sjkim if (o.hasArg) { 551238384Sjkim oneArg(args, i++); 552280297Sjkim o.process(this, args.get(i)); 553280297Sjkim } else { 554280297Sjkim setOption(arg); 555280297Sjkim o.process(this); 556280297Sjkim } 557280297Sjkim } else if (arg.startsWith("-XD")) { 558280297Sjkim // hidden javac options 559280297Sjkim String s = arg.substring("-XD".length()); 560238384Sjkim int eq = s.indexOf('='); 561280297Sjkim String key = (eq < 0) ? s : s.substring(0, eq); 562280297Sjkim String value = (eq < 0) ? s : s.substring(eq+1); 563280297Sjkim compOpts.put(key, value); 564280297Sjkim } else if (arg.startsWith("-")) { 565280297Sjkim i = handleDocletOptions(i, args, false); 566280297Sjkim } else { 567238384Sjkim javaNames.add(arg); 568280297Sjkim } 569280297Sjkim } 570280297Sjkim } 571280297Sjkim 572238384Sjkim private <T> boolean isEmpty(Iterable<T> iter) { 573280297Sjkim return !iter.iterator().hasNext(); 574280297Sjkim } 575280297Sjkim 576238384Sjkim /** 577280297Sjkim * Set one arg option. 578280297Sjkim * Error and exit if one argument is not provided. 579280297Sjkim */ 580238384Sjkim private void oneArg(List<String> args, int index) { 581280297Sjkim if ((index + 1) < args.size()) { 582280297Sjkim setOption(args.get(index), args.get(index+1)); 583280297Sjkim } else { 584238384Sjkim usageError("main.requires_argument", args.get(index)); 585280297Sjkim } 586280297Sjkim } 587238384Sjkim 588280297Sjkim @Override 589238384Sjkim void usageError(String key, Object... args) { 590280297Sjkim error(key, args); 591280297Sjkim usage(true); 592280297Sjkim } 593280297Sjkim 594280297Sjkim // a terminal call, will not return 595238384Sjkim void panic(String key, Object... args) { 596280297Sjkim error(key, args); 597280297Sjkim messager.exit(); 598280297Sjkim } 599238384Sjkim 600280297Sjkim void error(String key, Object... args) { 601280297Sjkim messager.error(key, args); 602280297Sjkim } 603280297Sjkim 604280297Sjkim /** 605280297Sjkim * indicate an option with no arguments was given. 606238384Sjkim */ 607280297Sjkim private void setOption(String opt) { 608280297Sjkim String[] option = { opt }; 609280297Sjkim options.add(Arrays.asList(option)); 610280297Sjkim } 611280297Sjkim 612280297Sjkim /** 613280297Sjkim * indicate an option with one argument was given. 614238384Sjkim */ 615238384Sjkim private void setOption(String opt, String argument) { 616280297Sjkim String[] option = { opt, argument }; 617280297Sjkim options.add(Arrays.asList(option)); 618280297Sjkim } 619280297Sjkim 620280297Sjkim /** 621238384Sjkim * indicate an option with the specified list of arguments was given. 622238384Sjkim */ 623280297Sjkim private void setOption(String opt, List<String> arguments) { 624280297Sjkim List<String> args = new ArrayList<>(arguments.size() + 1); 625280297Sjkim args.add(opt); 626280297Sjkim args.addAll(arguments); 627280297Sjkim options.add(args); 628238384Sjkim } 629280297Sjkim 630280297Sjkim /** 631280297Sjkim * Get the locale if specified on the command line 632280297Sjkim * else return null and if locale option is not used 633238384Sjkim * then return default locale. 634280297Sjkim */ 635280297Sjkim private Locale getLocale(String localeName) { 636280297Sjkim Locale userlocale = null; 637280297Sjkim if (localeName == null || localeName.isEmpty()) { 638280297Sjkim return Locale.getDefault(); 639280297Sjkim } 640280297Sjkim int firstuscore = localeName.indexOf('_'); 641280297Sjkim int seconduscore = -1; 642280297Sjkim String language = null; 643280297Sjkim String country = null; 644280297Sjkim String variant = null; 645280297Sjkim if (firstuscore == 2) { 646280297Sjkim language = localeName.substring(0, firstuscore); 647280297Sjkim seconduscore = localeName.indexOf('_', firstuscore + 1); 648280297Sjkim if (seconduscore > 0) { 649280297Sjkim if (seconduscore != firstuscore + 3 650280297Sjkim || localeName.length() <= seconduscore + 1) { 651280297Sjkim usageError("main.malformed_locale_name", localeName); 652280297Sjkim return null; 653280297Sjkim } 654280297Sjkim country = localeName.substring(firstuscore + 1, 655280297Sjkim seconduscore); 656280297Sjkim variant = localeName.substring(seconduscore + 1); 657280297Sjkim } else if (localeName.length() == firstuscore + 3) { 658280297Sjkim country = localeName.substring(firstuscore + 1); 659280297Sjkim } else { 660280297Sjkim usageError("main.malformed_locale_name", localeName); 661280297Sjkim return null; 662238384Sjkim } 663280297Sjkim } else if (firstuscore == -1 && localeName.length() == 2) { 664280297Sjkim language = localeName; 665280297Sjkim } else { 666280297Sjkim usageError("main.malformed_locale_name", localeName); 667280297Sjkim return null; 668280297Sjkim } 669280297Sjkim userlocale = searchLocale(language, country, variant); 670238384Sjkim if (userlocale == null) { 671280297Sjkim usageError("main.illegal_locale_name", localeName); 672280297Sjkim return null; 673280297Sjkim } else { 674238384Sjkim return userlocale; 675280297Sjkim } 676280297Sjkim } 677238384Sjkim 678280297Sjkim /** 679280297Sjkim * Search the locale for specified language, specified country and 680280297Sjkim * specified variant. 681280297Sjkim */ 682280297Sjkim private Locale searchLocale(String language, String country, 683280297Sjkim String variant) { 684238384Sjkim for (Locale loc : Locale.getAvailableLocales()) { 685280297Sjkim if (loc.getLanguage().equals(language) && 686280297Sjkim (country == null || loc.getCountry().equals(country)) && 687280297Sjkim (variant == null || loc.getVariant().equals(variant))) { 688280297Sjkim return loc; 689280297Sjkim } 690238384Sjkim } 691280297Sjkim return null; 692280297Sjkim } 693238384Sjkim} 694280297Sjkim