Thu, 15 Nov 2012 09:18:36 -0800
8000800: javadoc uses static non-final fields
Reviewed-by: bpatel
1 /*
2 * Copyright (c) 1997, 2012, Oracle and/or its affiliates. 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. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
26 package com.sun.tools.javadoc;
28 import java.io.File;
29 import java.io.FileNotFoundException;
30 import java.io.IOException;
31 import java.io.PrintWriter;
32 import java.util.StringTokenizer;
34 import com.sun.javadoc.*;
35 import com.sun.tools.javac.main.CommandLine;
36 import com.sun.tools.javac.util.Context;
37 import com.sun.tools.javac.util.List;
38 import com.sun.tools.javac.util.ListBuffer;
39 import com.sun.tools.javac.util.Log;
40 import com.sun.tools.javac.util.Options;
41 import static com.sun.tools.javac.code.Flags.*;
43 /**
44 * Main program of Javadoc.
45 * Previously named "Main".
46 *
47 * <p><b>This is NOT part of any supported API.
48 * If you write code that depends on this, you do so at your own risk.
49 * This code and its internal interfaces are subject to change or
50 * deletion without notice.</b>
51 *
52 * @since 1.2
53 * @author Robert Field
54 * @author Neal Gafter (rewrite)
55 */
56 class Start {
57 /** Context for this invocation. */
58 private final Context context;
60 private final String defaultDocletClassName;
61 private final ClassLoader docletParentClassLoader;
63 private static final String javadocName = "javadoc";
65 private static final String standardDocletClassName =
66 "com.sun.tools.doclets.standard.Standard";
68 private ListBuffer<String[]> options = new ListBuffer<String[]>();
70 private ModifierFilter showAccess = null;
72 private long defaultFilter = PUBLIC | PROTECTED;
74 private final Messager messager;
76 String docLocale = "";
78 boolean breakiterator = false;
79 boolean quiet = false;
80 String encoding = null;
82 private DocletInvoker docletInvoker;
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 * Usage
149 */
150 private void Xusage() {
151 messager.notice("main.Xusage");
152 }
154 /**
155 * Exit
156 */
157 private void exit() {
158 messager.exit();
159 }
162 /**
163 * Main program - external wrapper
164 */
165 int begin(String... argv) {
166 boolean failed = false;
168 try {
169 failed = !parseAndExecute(argv);
170 } catch(Messager.ExitJavadoc exc) {
171 // ignore, we just exit this way
172 } catch (OutOfMemoryError ee) {
173 messager.error(null, "main.out.of.memory");
174 failed = true;
175 } catch (Error ee) {
176 ee.printStackTrace(System.err);
177 messager.error(null, "main.fatal.error");
178 failed = true;
179 } catch (Exception ee) {
180 ee.printStackTrace(System.err);
181 messager.error(null, "main.fatal.exception");
182 failed = true;
183 } finally {
184 messager.exitNotice();
185 messager.flush();
186 }
187 failed |= messager.nerrors() > 0;
188 failed |= rejectWarnings && messager.nwarnings() > 0;
189 return failed ? 1 : 0;
190 }
192 private void addToList(ListBuffer<String> list, String str){
193 StringTokenizer st = new StringTokenizer(str, ":");
194 String current;
195 while(st.hasMoreTokens()){
196 current = st.nextToken();
197 list.append(current);
198 }
199 }
201 /**
202 * Main program - internal
203 */
204 private boolean parseAndExecute(String... argv) throws IOException {
205 long tm = System.currentTimeMillis();
207 ListBuffer<String> javaNames = new ListBuffer<String>();
209 // Preprocess @file arguments
210 try {
211 argv = CommandLine.parse(argv);
212 } catch (FileNotFoundException e) {
213 messager.error(null, "main.cant.read", e.getMessage());
214 exit();
215 } catch (IOException e) {
216 e.printStackTrace(System.err);
217 exit();
218 }
220 setDocletInvoker(argv);
221 ListBuffer<String> subPackages = new ListBuffer<String>();
222 ListBuffer<String> excludedPackages = new ListBuffer<String>();
224 Options compOpts = Options.instance(context);
225 boolean docClasses = false;
227 // Parse arguments
228 for (int i = 0 ; i < argv.length ; i++) {
229 String arg = argv[i];
230 if (arg.equals("-subpackages")) {
231 oneArg(argv, i++);
232 addToList(subPackages, argv[i]);
233 } else if (arg.equals("-exclude")){
234 oneArg(argv, i++);
235 addToList(excludedPackages, argv[i]);
236 } else if (arg.equals("-verbose")) {
237 setOption(arg);
238 compOpts.put("-verbose", "");
239 } else if (arg.equals("-encoding")) {
240 oneArg(argv, i++);
241 encoding = argv[i];
242 compOpts.put("-encoding", argv[i]);
243 } else if (arg.equals("-breakiterator")) {
244 breakiterator = true;
245 setOption("-breakiterator");
246 } else if (arg.equals("-quiet")) {
247 quiet = true;
248 setOption("-quiet");
249 } else if (arg.equals("-help")) {
250 usage();
251 exit();
252 } else if (arg.equals("-Xclasses")) {
253 setOption(arg);
254 docClasses = true;
255 } else if (arg.equals("-Xwerror")) {
256 setOption(arg);
257 rejectWarnings = true;
258 } else if (arg.equals("-private")) {
259 setOption(arg);
260 setFilter(ModifierFilter.ALL_ACCESS);
261 } else if (arg.equals("-package")) {
262 setOption(arg);
263 setFilter(PUBLIC | PROTECTED |
264 ModifierFilter.PACKAGE );
265 } else if (arg.equals("-protected")) {
266 setOption(arg);
267 setFilter(PUBLIC | PROTECTED );
268 } else if (arg.equals("-public")) {
269 setOption(arg);
270 setFilter(PUBLIC);
271 } else if (arg.equals("-source")) {
272 oneArg(argv, i++);
273 if (compOpts.get("-source") != null) {
274 usageError("main.option.already.seen", arg);
275 }
276 compOpts.put("-source", argv[i]);
277 } else if (arg.equals("-prompt")) {
278 compOpts.put("-prompt", "-prompt");
279 messager.promptOnError = true;
280 } else if (arg.equals("-sourcepath")) {
281 oneArg(argv, i++);
282 if (compOpts.get("-sourcepath") != null) {
283 usageError("main.option.already.seen", arg);
284 }
285 compOpts.put("-sourcepath", argv[i]);
286 } else if (arg.equals("-classpath")) {
287 oneArg(argv, i++);
288 if (compOpts.get("-classpath") != null) {
289 usageError("main.option.already.seen", arg);
290 }
291 compOpts.put("-classpath", argv[i]);
292 } else if (arg.equals("-sysclasspath")) {
293 oneArg(argv, i++);
294 if (compOpts.get("-bootclasspath") != null) {
295 usageError("main.option.already.seen", arg);
296 }
297 compOpts.put("-bootclasspath", argv[i]);
298 } else if (arg.equals("-bootclasspath")) {
299 oneArg(argv, i++);
300 if (compOpts.get("-bootclasspath") != null) {
301 usageError("main.option.already.seen", arg);
302 }
303 compOpts.put("-bootclasspath", argv[i]);
304 } else if (arg.equals("-extdirs")) {
305 oneArg(argv, i++);
306 if (compOpts.get("-extdirs") != null) {
307 usageError("main.option.already.seen", arg);
308 }
309 compOpts.put("-extdirs", argv[i]);
310 } else if (arg.equals("-overview")) {
311 oneArg(argv, i++);
312 } else if (arg.equals("-doclet")) {
313 i++; // handled in setDocletInvoker
314 } else if (arg.equals("-docletpath")) {
315 i++; // handled in setDocletInvoker
316 } else if (arg.equals("-locale")) {
317 if (i != 0)
318 usageError("main.locale_first");
319 oneArg(argv, i++);
320 docLocale = argv[i];
321 } else if (arg.equals("-Xmaxerrs") || arg.equals("-Xmaxwarns")) {
322 oneArg(argv, i++);
323 if (compOpts.get(arg) != null) {
324 usageError("main.option.already.seen", arg);
325 }
326 compOpts.put(arg, argv[i]);
327 } else if (arg.equals("-X")) {
328 Xusage();
329 exit();
330 } else if (arg.startsWith("-XD")) {
331 String s = arg.substring("-XD".length());
332 int eq = s.indexOf('=');
333 String key = (eq < 0) ? s : s.substring(0, eq);
334 String value = (eq < 0) ? s : s.substring(eq+1);
335 compOpts.put(key, value);
336 }
337 // call doclet for its options
338 // other arg starts with - is invalid
339 else if ( arg.startsWith("-") ) {
340 int optionLength;
341 optionLength = docletInvoker.optionLength(arg);
342 if (optionLength < 0) {
343 // error already displayed
344 exit();
345 } else if (optionLength == 0) {
346 // option not found
347 usageError("main.invalid_flag", arg);
348 } else {
349 // doclet added option
350 if ((i + optionLength) > argv.length) {
351 usageError("main.requires_argument", arg);
352 }
353 ListBuffer<String> args = new ListBuffer<String>();
354 for (int j = 0; j < optionLength-1; ++j) {
355 args.append(argv[++i]);
356 }
357 setOption(arg, args.toList());
358 }
359 } else {
360 javaNames.append(arg);
361 }
362 }
363 compOpts.notifyListeners();
365 if (javaNames.isEmpty() && subPackages.isEmpty()) {
366 usageError("main.No_packages_or_classes_specified");
367 }
369 if (!docletInvoker.validOptions(options.toList())) {
370 // error message already displayed
371 exit();
372 }
374 JavadocTool comp = JavadocTool.make0(context);
375 if (comp == null) return false;
377 if (showAccess == null) {
378 setFilter(defaultFilter);
379 }
381 LanguageVersion languageVersion = docletInvoker.languageVersion();
382 RootDocImpl root = comp.getRootDocImpl(
383 docLocale, encoding, showAccess,
384 javaNames.toList(), options.toList(), breakiterator,
385 subPackages.toList(), excludedPackages.toList(),
386 docClasses,
387 // legacy?
388 languageVersion == null || languageVersion == LanguageVersion.JAVA_1_1, quiet);
390 // release resources
391 comp = null;
393 // pass off control to the doclet
394 boolean ok = root != null;
395 if (ok) ok = docletInvoker.start(root);
397 // We're done.
398 if (compOpts.get("-verbose") != null) {
399 tm = System.currentTimeMillis() - tm;
400 messager.notice("main.done_in", Long.toString(tm));
401 }
403 return ok;
404 }
406 private void setDocletInvoker(String[] argv) {
407 String docletClassName = null;
408 String docletPath = null;
410 // Parse doclet specifying arguments
411 for (int i = 0 ; i < argv.length ; i++) {
412 String arg = argv[i];
413 if (arg.equals("-doclet")) {
414 oneArg(argv, i++);
415 if (docletClassName != null) {
416 usageError("main.more_than_one_doclet_specified_0_and_1",
417 docletClassName, argv[i]);
418 }
419 docletClassName = argv[i];
420 } else if (arg.equals("-docletpath")) {
421 oneArg(argv, i++);
422 if (docletPath == null) {
423 docletPath = argv[i];
424 } else {
425 docletPath += File.pathSeparator + argv[i];
426 }
427 }
428 }
430 if (docletClassName == null) {
431 docletClassName = defaultDocletClassName;
432 }
434 // attempt to find doclet
435 docletInvoker = new DocletInvoker(messager,
436 docletClassName, docletPath,
437 docletParentClassLoader);
438 }
440 private void setFilter(long filterBits) {
441 if (showAccess != null) {
442 messager.error(null, "main.incompatible.access.flags");
443 usage();
444 exit();
445 }
446 showAccess = new ModifierFilter(filterBits);
447 }
449 /**
450 * Set one arg option.
451 * Error and exit if one argument is not provided.
452 */
453 private void oneArg(String[] args, int index) {
454 if ((index + 1) < args.length) {
455 setOption(args[index], args[index+1]);
456 } else {
457 usageError("main.requires_argument", args[index]);
458 }
459 }
461 private void usageError(String key) {
462 messager.error(null, key);
463 usage();
464 exit();
465 }
467 private void usageError(String key, String a1) {
468 messager.error(null, key, a1);
469 usage();
470 exit();
471 }
473 private void usageError(String key, String a1, String a2) {
474 messager.error(null, key, a1, a2);
475 usage();
476 exit();
477 }
479 /**
480 * indicate an option with no arguments was given.
481 */
482 private void setOption(String opt) {
483 String[] option = { opt };
484 options.append(option);
485 }
487 /**
488 * indicate an option with one argument was given.
489 */
490 private void setOption(String opt, String argument) {
491 String[] option = { opt, argument };
492 options.append(option);
493 }
495 /**
496 * indicate an option with the specified list of arguments was given.
497 */
498 private void setOption(String opt, List<String> arguments) {
499 String[] args = new String[arguments.length() + 1];
500 int k = 0;
501 args[k++] = opt;
502 for (List<String> i = arguments; i.nonEmpty(); i=i.tail) {
503 args[k++] = i.head;
504 }
505 options = options.append(args);
506 }
508 }