| /* gnu.classpath.tools.gjdoc.Main |
| Copyright (C) 2001 Free Software Foundation, Inc. |
| |
| This file is part of GNU Classpath. |
| |
| GNU Classpath is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 2, or (at your option) |
| any later version. |
| |
| GNU Classpath is distributed in the hope that it will be useful, but |
| WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with GNU Classpath; see the file COPYING. If not, write to the |
| Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA |
| 02111-1307 USA. */ |
| |
| package gnu.classpath.tools.gjdoc; |
| |
| import com.sun.javadoc.*; |
| import java.io.*; |
| import java.util.*; |
| import java.lang.reflect.*; |
| import java.text.Collator; |
| |
| import gnu.classpath.tools.FileSystemClassLoader; |
| |
| /** |
| * Class that will launch the gjdoc tool. |
| */ |
| public final class Main |
| { |
| |
| /** |
| * Do we load classes that are referenced as base class? |
| */ |
| static final boolean DESCEND_SUPERCLASS = true; |
| |
| /** |
| * Do we load classes that are referenced as interface? |
| */ |
| static final boolean DESCEND_INTERFACES = false; |
| |
| /** |
| * Do we load classes that are imported in a source file? |
| */ |
| static final boolean DESCEND_IMPORTED = true; |
| |
| /** |
| * Document only public members. |
| */ |
| static final int COVERAGE_PUBLIC = 0; |
| |
| /** |
| * Document only public and protected members. |
| */ |
| static final int COVERAGE_PROTECTED = 1; |
| |
| /** |
| * Document public, protected and package private members. |
| */ |
| static final int COVERAGE_PACKAGE = 2; |
| |
| /** |
| * Document all members. |
| */ |
| static final int COVERAGE_PRIVATE = 3; |
| |
| /* |
| * FIXME: This should come from a ResourceBundle |
| */ |
| private static final String STRING_TRY_GJDOC_HELP = |
| "Try `gjdoc --help' for more information."; |
| |
| /** |
| * Grid for looking up whether a particular access level is included in the |
| * documentation. |
| */ |
| static final boolean[][] coverageTemplates = new boolean[][] |
| { new boolean[] |
| { true, false, false, false }, // public |
| new boolean[] |
| { true, true, false, false }, // protected |
| new boolean[] |
| { true, true, true, false }, // package |
| new boolean[] |
| { true, true, true, true }, // private |
| }; |
| |
| /** |
| * Holds the Singleton instance of this class. |
| */ |
| private static Main instance = new Main(); |
| |
| /** |
| * Avoid re-instantiation of this class. |
| */ |
| private Main() |
| { |
| } |
| |
| private static RootDocImpl rootDoc; |
| |
| private ErrorReporter reporter; |
| |
| /** |
| * Cache for version string from resource /version.properties |
| */ |
| private String gjdocVersion; |
| |
| /** |
| * <code>false</code> during Phase I: preparation of the documentation data. |
| * <code>true</code> during Phase II: documentation output by doclet. |
| */ |
| boolean docletRunning = false; |
| |
| //---- Command line options |
| |
| /** |
| * Option "-doclet": name of the Doclet class to use. |
| */ |
| private String option_doclet = "gnu.classpath.tools.doclets.htmldoclet.HtmlDoclet"; |
| |
| /** |
| * Option "-overview": path to the special overview file. |
| */ |
| private String option_overview; |
| |
| /** |
| * Option "-coverage": which members to include in generated documentation. |
| */ |
| private int option_coverage = COVERAGE_PROTECTED; |
| |
| /** |
| * Option "-help": display command line usage. |
| */ |
| private boolean option_help; |
| |
| /** |
| * Option "-docletpath": path to doclet classes. |
| */ |
| private String option_docletpath; |
| |
| /** |
| * Option "-classpath": path to additional classes. |
| */ |
| private String option_classpath; |
| |
| /** |
| * Option "-sourcepath": path to the Java source files to be documented. |
| * FIXME: this should be a list of paths |
| */ |
| private List option_sourcepath = new ArrayList(); |
| |
| /** |
| * Option "-extdirs": path to Java extension files. |
| */ |
| private String option_extdirs; |
| |
| /** |
| * Option "-verbose": Be verbose when generating documentation. |
| */ |
| private boolean option_verbose; |
| |
| /** |
| * Option "-nowarn": Do not print warnings. |
| */ |
| private boolean option_nowarn; |
| |
| /** |
| * Option "-locale:" Specify the locale charset of Java source files. |
| */ |
| private Locale option_locale = new Locale("en", "us"); |
| |
| /** |
| * Option "-encoding": Specify character encoding of Java source files. |
| */ |
| private String option_encoding; |
| |
| /** |
| * Option "-J": Specify flags to be passed to Java runtime. |
| */ |
| private List option_java_flags = new LinkedList(); //ArrayList(); |
| |
| /** |
| * Option "-source:" should be 1.4 to handle assertions, 1.1 is no |
| * longer supported. |
| */ |
| private String option_source = "1.2"; |
| |
| /** |
| * Option "-subpackages": list of subpackages to be recursively |
| * added. |
| */ |
| private List option_subpackages = new ArrayList(); |
| |
| /** |
| * Option "-exclude": list of subpackages to exclude. |
| */ |
| private List option_exclude = new ArrayList(); |
| |
| /** |
| * Option "-breakiterator" - whether to use BreakIterator for |
| * detecting the end of the first sentence. |
| */ |
| private boolean option_breakiterator; |
| |
| /** |
| * Option "-licensetext" - whether to copy license text. |
| */ |
| private boolean option_licensetext; |
| |
| /** |
| * The locale-dependent collator used for sorting. |
| */ |
| private Collator collator; |
| |
| /** |
| * true when --version has been specified on the command line. |
| */ |
| private boolean option_showVersion; |
| |
| /** |
| * true when -bootclasspath has been specified on the command line. |
| */ |
| private boolean option_bootclasspath_specified; |
| |
| /** |
| * true when -all has been specified on the command line. |
| */ |
| private boolean option_all; |
| |
| /** |
| * true when -reflection has been specified on the command line. |
| */ |
| private boolean option_reflection; |
| |
| // TODO: add the rest of the options as instance variables |
| |
| /** |
| * Parse all source files/packages and subsequentially start the Doclet given |
| * on the command line. |
| * |
| * @param allOptions List of all command line tokens |
| */ |
| private boolean startDoclet(List allOptions) |
| { |
| |
| try |
| { |
| |
| //--- Fetch the Class object for the Doclet. |
| |
| Debug.log(1, "loading doclet class..."); |
| |
| Class docletClass; |
| |
| if (null != option_docletpath) { |
| try { |
| FileSystemClassLoader docletPathClassLoader |
| = new FileSystemClassLoader(option_docletpath); |
| System.err.println("trying to load class " + option_doclet + " from path " + option_docletpath); |
| docletClass = docletPathClassLoader.findClass(option_doclet); |
| } |
| catch (Exception e) { |
| docletClass = Class.forName(option_doclet); |
| } |
| } |
| else { |
| docletClass = Class.forName(option_doclet); |
| } |
| //Object docletInstance = docletClass.newInstance(); |
| |
| Debug.log(1, "doclet class loaded..."); |
| |
| Method startTempMethod = null; |
| Method startMethod = null; |
| Method optionLenMethod = null; |
| Method validOptionsMethod = null; |
| |
| //--- Try to find the optionLength method in the Doclet class. |
| |
| try |
| { |
| optionLenMethod = docletClass.getMethod("optionLength", new Class[] |
| { String.class }); |
| } |
| catch (NoSuchMethodException e) |
| { |
| // Ignore if not found; it's OK it the Doclet class doesn't define |
| // this method. |
| } |
| |
| //--- Try to find the validOptions method in the Doclet class. |
| |
| try |
| { |
| validOptionsMethod = docletClass.getMethod("validOptions", new Class[] |
| { String[][].class, DocErrorReporter.class }); |
| } |
| catch (NoSuchMethodException e) |
| { |
| // Ignore if not found; it's OK it the Doclet class doesn't define |
| // this method. |
| } |
| |
| //--- Find the start method in the Doclet class; complain if not found |
| |
| try |
| { |
| startTempMethod = docletClass.getMethod("start", new Class[] |
| { TemporaryStore.class }); |
| } |
| catch (Exception e) |
| { |
| // ignore |
| } |
| startMethod = docletClass.getMethod("start", new Class[] |
| { RootDoc.class }); |
| |
| //--- Feed the custom command line tokens to the Doclet |
| |
| // stores all recognized options |
| List options = new LinkedList(); |
| |
| // stores packages and classes defined on the command line |
| List packageAndClasses = new LinkedList(); |
| |
| for (Iterator it = allOptions.iterator(); it.hasNext();) |
| { |
| String option = (String) it.next(); |
| |
| Debug.log(9, "parsing option '" + option + "'"); |
| |
| if (option.startsWith("-")) |
| { |
| |
| //--- Parse option |
| |
| int optlen = optionLength(option); |
| |
| //--- Try to get option length from Doclet class |
| |
| if (optlen <= 0 && optionLenMethod != null) |
| { |
| |
| optionLenMethod.invoke(null, new Object[] |
| { option }); |
| |
| Debug.log(3, "invoking optionLen method"); |
| |
| optlen = ((Integer) optionLenMethod.invoke(null, new Object[] |
| { option })).intValue(); |
| |
| Debug.log(3, "done"); |
| } |
| |
| if (optlen <= 0) { |
| |
| if (option.startsWith("-JD")) { |
| // Simulate VM option -D |
| String propertyValue = option.substring(3); |
| int ndx = propertyValue.indexOf('='); |
| if (ndx <= 0) { |
| reporter.printError("Illegal format in option " + option + ": use -JDproperty=value"); |
| return false; |
| } |
| else { |
| String property = propertyValue.substring(0, ndx); |
| String value = propertyValue.substring(ndx + 1); |
| System.setProperty(property, value); |
| } |
| } |
| else if (option.startsWith("-J")) { |
| //--- Warn if VM option is encountered |
| reporter.printWarning("Ignored option " + option + ". Pass this option to the VM if required."); |
| } |
| else { |
| //--- Complain if not found |
| |
| reporter.printError("Unknown option " + option); |
| reporter.printNotice(STRING_TRY_GJDOC_HELP); |
| return false; |
| } |
| } |
| else |
| { |
| |
| //--- Read option values |
| |
| String[] optionAndValues = new String[optlen]; |
| optionAndValues[0] = option; |
| for (int i = 1; i < optlen; ++i) |
| { |
| if (!it.hasNext()) |
| { |
| reporter.printError("Missing value for option " + option); |
| return false; |
| } |
| else |
| { |
| optionAndValues[i] = (String) it.next(); |
| } |
| } |
| |
| //--- Store option for processing later |
| |
| options.add(optionAndValues); |
| } |
| } |
| else if (option.length() > 0) |
| { |
| |
| //--- Add to list of packages/classes if not option or option |
| // value |
| |
| packageAndClasses.add(option); |
| } |
| } |
| |
| Debug.log(9, "options parsed..."); |
| |
| //--- For each package specified with the -subpackages option on |
| // the command line, recursively find all valid java files |
| // beneath it. |
| |
| //--- For each class or package specified on the command line, |
| // check that it exists and find out whether it is a class |
| // or a package |
| |
| for (Iterator it = option_subpackages.iterator(); it.hasNext();) |
| { |
| String subpackage = (String) it.next(); |
| Set foundPackages = new LinkedHashSet(); |
| |
| for (Iterator pit = option_sourcepath.iterator(); pit.hasNext(); ) { |
| File sourceDir = (File)pit.next(); |
| File packageDir = new File(sourceDir, subpackage.replace('.', File.separatorChar)); |
| findPackages(subpackage, packageDir, foundPackages); |
| } |
| |
| addFoundPackages(subpackage, foundPackages); |
| } |
| |
| if (option_all) { |
| Set foundPackages = new LinkedHashSet(); |
| for (Iterator pit = option_sourcepath.iterator(); pit.hasNext(); ) { |
| File sourceDir = (File)pit.next(); |
| findPackages("", sourceDir, foundPackages); |
| } |
| addFoundPackages(null, foundPackages); |
| for (Iterator packageIt = foundPackages.iterator(); packageIt.hasNext(); ) { |
| String packageName = (String)packageIt.next(); |
| if (null == packageName) { |
| packageName = ""; |
| } |
| rootDoc.addSpecifiedPackageName(packageName); |
| } |
| } |
| |
| for (Iterator it = packageAndClasses.iterator(); it.hasNext();) |
| { |
| |
| String classOrPackage = (String) it.next(); |
| |
| boolean foundSourceFile = false; |
| |
| if (classOrPackage.endsWith(".java")) { |
| for (Iterator pit = option_sourcepath.iterator(); pit.hasNext() && !foundSourceFile; ) { |
| File sourceDir = (File)pit.next(); |
| File sourceFile = new File(sourceDir, classOrPackage); |
| if (sourceFile.exists() && !sourceFile.isDirectory()) { |
| rootDoc.addSpecifiedSourceFile(sourceFile); |
| foundSourceFile = true; |
| break; |
| } |
| } |
| if (!foundSourceFile) { |
| File sourceFile = new File(classOrPackage); |
| if (sourceFile.exists() && !sourceFile.isDirectory()) { |
| rootDoc.addSpecifiedSourceFile(sourceFile); |
| foundSourceFile = true; |
| } |
| } |
| } |
| |
| if (!foundSourceFile) { |
| //--- Check for illegal name |
| |
| if (classOrPackage.startsWith(".") |
| || classOrPackage.endsWith(".") |
| || classOrPackage.indexOf("..") > 0 |
| || !checkCharSet(classOrPackage, |
| "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890_.")) |
| { |
| throw new ParseException("Illegal class or package name '" |
| + classOrPackage + "'"); |
| } |
| |
| //--- Assemble absolute path to package |
| |
| String classOrPackageRelPath = classOrPackage.replace('.', |
| File.separatorChar); |
| |
| //--- Create one file object each for a possible package directory |
| // and a possible class file, and find out if they exist. |
| |
| List packageDirs = rootDoc.findSourceFiles(classOrPackageRelPath); |
| List sourceFiles = rootDoc.findSourceFiles(classOrPackageRelPath + ".java"); |
| |
| boolean packageDirExists = !packageDirs.isEmpty(); |
| boolean sourceFileExists = !sourceFiles.isEmpty(); |
| |
| //--- Complain if neither exists: not found |
| |
| if (!packageDirExists && !sourceFileExists) |
| { |
| reporter.printError("Class or package " + classOrPackage |
| + " not found."); |
| return false; |
| } |
| |
| //--- Complain if both exist: ambigious |
| |
| else |
| if (packageDirExists && sourceFileExists) |
| { |
| reporter.printError("Ambigious class/package name " |
| + classOrPackage + "."); |
| return false; |
| } |
| |
| //--- Otherwise, if the package directory exists, it is a package |
| |
| else |
| if (packageDirExists) { |
| Iterator packageDirIt = packageDirs.iterator(); |
| boolean packageDirFound = false; |
| while (packageDirIt.hasNext()) { |
| File packageDir = (File)packageDirIt.next(); |
| if (packageDir.isDirectory()) { |
| rootDoc.addSpecifiedPackageName(classOrPackage); |
| packageDirFound = true; |
| break; |
| } |
| } |
| if (!packageDirFound) { |
| reporter.printError("No suitable file or directory found for" + classOrPackage); |
| return false; |
| } |
| } |
| |
| //--- Otherwise, emit error message |
| |
| else { |
| reporter.printError("No sources files found for package " + classOrPackage); |
| } |
| } |
| } |
| |
| //--- Complain if no packages or classes specified |
| |
| if (option_help) { |
| usage(); |
| return true; |
| } |
| |
| //--- Validate custom options passed on command line |
| // by asking the Doclet if they are OK. |
| |
| String[][] customOptionArr = (String[][]) options |
| .toArray(new String[0][0]); |
| if (validOptionsMethod != null |
| && !((Boolean) validOptionsMethod.invoke(null, new Object[] |
| { customOptionArr, reporter })).booleanValue()) |
| { |
| // Not ok: shutdown system. |
| reporter.printNotice(STRING_TRY_GJDOC_HELP); |
| return false; |
| } |
| |
| if (!rootDoc.hasSpecifiedPackagesOrClasses()) { |
| reporter.printError("No packages or classes specified."); |
| reporter.printNotice(STRING_TRY_GJDOC_HELP); |
| return false; |
| } |
| |
| rootDoc.setOptions(customOptionArr); |
| |
| rootDoc.build(); |
| |
| //--- Bail out if no classes found |
| |
| if (0 == rootDoc.classes().length |
| && 0 == rootDoc.specifiedPackages().length |
| && 0 == rootDoc.specifiedClasses().length) |
| { |
| reporter.printError("No packages or classes found(!)."); |
| return false; |
| } |
| |
| //--- Our work is done, tidy up memory |
| |
| System.gc(); |
| System.gc(); |
| |
| //--- Set flag indicating Phase II of documentation generation |
| |
| docletRunning = true; |
| |
| //--- Invoke the start method on the Doclet: produce output |
| |
| reporter.printNotice("Running doclet..."); |
| |
| TemporaryStore tstore = new TemporaryStore(Main.rootDoc); |
| |
| Thread.currentThread().setContextClassLoader(docletClass.getClassLoader()); |
| |
| if (null != startTempMethod) |
| { |
| startTempMethod.invoke(null, new Object[] |
| { tstore }); |
| } |
| else |
| { |
| startMethod.invoke(null, new Object[] |
| { tstore.getAndClear() }); |
| } |
| |
| //--- Let the user know how many warnings/errors occured |
| |
| if (reporter.getWarningCount() > 0) |
| { |
| reporter.printNotice(reporter.getWarningCount() + " warnings"); |
| } |
| |
| if (reporter.getErrorCount() > 0) |
| { |
| reporter.printNotice(reporter.getErrorCount() + " errors"); |
| } |
| |
| System.gc(); |
| |
| //--- Done. |
| return true; |
| } |
| catch (Exception e) |
| { |
| e.printStackTrace(); |
| return false; |
| } |
| } |
| |
| private void addFoundPackages(String subpackage, Set foundPackages) |
| { |
| if (foundPackages.isEmpty()) { |
| reporter.printWarning("No classes found under subpackage " + subpackage); |
| } |
| else { |
| boolean onePackageAdded = false; |
| for (Iterator rit = foundPackages.iterator(); rit.hasNext();) { |
| String foundPackage = (String)rit.next(); |
| boolean excludeThisPackage = false; |
| |
| for (Iterator eit = option_exclude.iterator(); eit.hasNext();) { |
| String excludePackage = (String)eit.next(); |
| if (foundPackage.equals(excludePackage) || |
| foundPackage.startsWith(excludePackage + ":")) { |
| excludeThisPackage = true; |
| break; |
| } |
| } |
| |
| if (!excludeThisPackage) { |
| rootDoc.addSpecifiedPackageName(foundPackage); |
| onePackageAdded = true; |
| } |
| } |
| if (!onePackageAdded) { |
| if (null != subpackage) { |
| reporter.printWarning("No non-excluded classes found under subpackage " + subpackage); |
| } |
| else { |
| reporter.printWarning("No non-excluded classes found."); |
| } |
| } |
| } |
| } |
| |
| /** |
| * Verify that the given file is a valid Java source file and that |
| * it specifies the given package. |
| */ |
| private boolean isValidJavaFile(File file, |
| String expectedPackage) |
| { |
| try { |
| InputStream in = new BufferedInputStream(new FileInputStream(file)); |
| |
| int ch, prevChar = 0; |
| |
| final int STATE_DEFAULT = 0; |
| final int STATE_COMMENT = 1; |
| final int STATE_LINE_COMMENT = 2; |
| |
| int state = STATE_DEFAULT; |
| |
| StringBuffer word = new StringBuffer(); |
| int wordIndex = 0; |
| |
| while ((ch = in.read()) >= 0) { |
| String completeWord = null; |
| |
| switch (state) { |
| case STATE_COMMENT: |
| if (prevChar == '*' && ch == '/') { |
| state = STATE_DEFAULT; |
| } |
| break; |
| |
| case STATE_LINE_COMMENT: |
| if (ch == '\n') { |
| state = STATE_DEFAULT; |
| } |
| break; |
| |
| case STATE_DEFAULT: |
| if (prevChar == '/' && ch == '*') { |
| word.deleteCharAt(word.length() - 1); |
| if (word.length() > 0) { |
| completeWord = word.toString(); |
| word.setLength(0); |
| } |
| state = STATE_COMMENT; |
| } |
| else if (prevChar == '/' && ch == '/') { |
| word.deleteCharAt(word.length() - 1); |
| if (word.length() > 0) { |
| completeWord = word.toString(); |
| word.setLength(0); |
| } |
| state = STATE_LINE_COMMENT; |
| } |
| else if (" \t\r\n".indexOf(ch) >= 0) { |
| if (word.length() > 0) { |
| completeWord = word.toString(); |
| word.setLength(0); |
| } |
| } |
| else if (1 == wordIndex && ';' == ch) { |
| if (word.length() > 0) { |
| completeWord = word.toString(); |
| word.setLength(0); |
| } |
| else { |
| // empty package name in source file: "package ;" -> invalid source file |
| in.close(); |
| return false; |
| } |
| } |
| else { |
| word.append((char)ch); |
| } |
| break; |
| } |
| |
| if (null != completeWord) { |
| if (0 == wordIndex && !"package".equals(completeWord)) { |
| in.close(); |
| return "".equals(expectedPackage); |
| } |
| else if (1 == wordIndex) { |
| in.close(); |
| return expectedPackage.equals(completeWord); |
| } |
| ++ wordIndex; |
| } |
| |
| prevChar = ch; |
| } |
| |
| // no package or class found before end-of-file -> invalid source file |
| |
| in.close(); |
| return false; |
| } |
| catch (IOException e) { |
| reporter.printWarning("Could not examine file " + file + ": " + e); |
| return false; |
| } |
| } |
| |
| /** |
| * Recursively try to locate valid Java packages under the given |
| * package specified by its name and its directory. Add the names |
| * of all valid packages to the result list. |
| */ |
| private void findPackages(String subpackage, |
| File packageDir, |
| Set result) |
| { |
| File[] files = packageDir.listFiles(); |
| if (null != files) { |
| for (int i=0; i<files.length; ++i) { |
| File file = files[i]; |
| if (!file.isDirectory() && file.getName().endsWith(".java")) { |
| if (isValidJavaFile(file, subpackage)) { |
| if ("".equals(subpackage)) { |
| result.add(null); |
| } |
| else { |
| result.add(subpackage); |
| } |
| break; |
| } |
| } |
| } |
| for (int i=0; i<files.length; ++i) { |
| File file = files[i]; |
| if (file.isDirectory()) { |
| String newSubpackage; |
| if (null != subpackage && subpackage.length() > 0) { |
| newSubpackage = subpackage + "." + file.getName(); |
| } |
| else { |
| newSubpackage = file.getName(); |
| } |
| findPackages(newSubpackage, file, result); |
| } |
| } |
| } |
| } |
| |
| /** |
| * |
| */ |
| private static boolean validOptions(String options[][], |
| DocErrorReporter reporter) |
| { |
| |
| boolean foundDocletOption = false; |
| for (int i = 0; i < options.length; i++) |
| { |
| String[] opt = options[i]; |
| if (opt[0].equalsIgnoreCase("-doclet")) |
| { |
| if (foundDocletOption) |
| { |
| reporter.printError("Only one -doclet option allowed."); |
| return false; |
| } |
| else |
| { |
| foundDocletOption = true; |
| } |
| } |
| } |
| |
| return true; |
| } |
| |
| /** |
| * Main entry point. This is the method called when gjdoc is invoked from the |
| * command line. |
| * |
| * @param args |
| * command line arguments |
| */ |
| public static void main(String[] args) |
| { |
| |
| try |
| { |
| //--- Remember current time for profiling purposes |
| |
| Timer.setStartTime(); |
| |
| //--- Handle control to the Singleton instance of this class |
| |
| int result = instance.start(args); |
| |
| if (result < 0) { |
| // fatal error |
| System.exit(5); |
| } |
| else if (result > 0) { |
| // errors encountered |
| System.exit(1); |
| } |
| else { |
| // success |
| System.exit(0); |
| } |
| } |
| catch (Exception e) |
| { |
| //--- unexpected error |
| e.printStackTrace(); |
| System.exit(1); |
| } |
| } |
| |
| /** |
| * Parses command line arguments and subsequentially handles control to the |
| * startDoclet() method |
| * |
| * @param args The command line parameters. |
| */ |
| public static int execute(String[] args) |
| { |
| try |
| { |
| int result = instance.start(args); |
| if (result < 0) { |
| // fatal error |
| return 5; |
| } |
| else if (result > 0) { |
| // errors encountered |
| return 1; |
| } |
| else { |
| // success |
| return 0; |
| } |
| } |
| catch (Exception e) |
| { |
| // unexpected error |
| return 1; |
| } |
| } |
| |
| /** |
| * @param programName Name of the program (for error messages). *disregarded* |
| * @param args The command line parameters. |
| * @returns The return code. |
| */ |
| public static int execute(String programName, |
| String[] args) |
| { |
| return execute(args); |
| } |
| |
| /** |
| * @param programName Name of the program (for error messages). |
| * @param defaultDocletClassName Fully qualified class name. |
| * @param args The command line parameters. |
| * @returns The return code. |
| *//* |
| public static int execute(String programName, |
| String defaultDocletClassName, |
| String[] args) |
| { |
| // not yet implemented |
| }*/ |
| |
| /** |
| * @param programName Name of the program (for error messages). |
| * @param defaultDocletClassName Fully qualified class name. |
| * @param args The command line parameters. |
| * @returns The return code. |
| *//* |
| public static int execute(String programName, |
| String defaultDocletClassName, |
| String[] args) |
| { |
| // not yet implemented |
| }*/ |
| |
| /** |
| * @param programName Name of the program (for error messages). |
| * @param errWriter PrintWriter to receive error messages. |
| * @param warnWriter PrintWriter to receive error messages. |
| * @param noticeWriter PrintWriter to receive error messages. |
| * @param defaultDocletClassName Fully qualified class name. |
| * @param args The command line parameters. |
| * @returns The return code. |
| *//* |
| public static int execute(String programName, |
| PrintWriter errWriter, |
| PrintWriter warnWriter, |
| PrintWriter noticeWriter, |
| String defaultDocletClassName, |
| String[] args) |
| { |
| // not yet implemented |
| }*/ |
| |
| /** |
| * Parses command line arguments and subsequentially handles control to the |
| * startDoclet() method |
| * |
| * @param args |
| * Command line arguments, as passed to the main() method |
| * @return {@code -1} in case of a fatal error (invalid arguments), |
| * or the number of errors encountered. |
| * @exception ParseException |
| * FIXME |
| * @exception IOException |
| * if an IO problem occur |
| */ |
| public int start(String[] args) throws ParseException, IOException |
| { |
| |
| //--- Collect unparsed arguments in array and resolve references |
| // to external argument files. |
| |
| List arguments = new ArrayList(args.length); |
| |
| for (int i = 0; i < args.length; ++i) |
| { |
| if (!args[i].startsWith("@")) |
| { |
| arguments.add(args[i]); |
| } |
| else |
| { |
| FileReader reader = new FileReader(args[i].substring(1)); |
| StreamTokenizer st = new StreamTokenizer(reader); |
| st.resetSyntax(); |
| st.wordChars('\u0000', '\uffff'); |
| st.quoteChar('\"'); |
| st.quoteChar('\''); |
| st.whitespaceChars(' ', ' '); |
| st.whitespaceChars('\t', '\t'); |
| st.whitespaceChars('\r', '\r'); |
| st.whitespaceChars('\n', '\n'); |
| while (st.nextToken() != StreamTokenizer.TT_EOF) |
| { |
| arguments.add(st.sval); |
| } |
| } |
| } |
| |
| //--- Initialize Map for option parsing |
| |
| initOptions(); |
| |
| //--- This will hold all options recognized by gjdoc itself |
| // and their associated arguments. |
| // Contains objects of type String[], where each entry |
| // specifies an option along with its aguments. |
| |
| List options = new LinkedList(); |
| |
| //--- This will hold all command line tokens not recognized |
| // to be part of a standard option. |
| // These options are intended to be processed by the doclet |
| // Contains objects of type String, where each entry is |
| // one unrecognized token. |
| |
| List customOptions = new LinkedList(); |
| |
| rootDoc = new RootDocImpl(); |
| reporter = rootDoc.getReporter(); |
| |
| //--- Iterate over all options given on the command line |
| |
| for (Iterator it = arguments.iterator(); it.hasNext();) |
| { |
| |
| String arg = (String) it.next(); |
| |
| //--- Check if gjdoc recognizes this option as a standard option |
| // and remember the options' argument count |
| |
| int optlen = optionLength(arg); |
| |
| //--- Argument count == 0 indicates that the option is not recognized. |
| // Add it to the list of custom option tokens |
| |
| //--- Otherwise the option is recognized as a standard option. |
| // if all required arguments are supplied. Create a new String |
| // array for the option and its arguments, and store it |
| // in the options array. |
| |
| if (optlen > 0) |
| { |
| String[] option = new String[optlen]; |
| option[0] = arg; |
| boolean optargs_ok = true; |
| for (int j = 1; j < optlen && optargs_ok; ++j) |
| { |
| if (it.hasNext()) |
| { |
| option[j] = (String) it.next(); |
| if (option[j].startsWith("-")) |
| { |
| optargs_ok = false; |
| } |
| } |
| else |
| { |
| optargs_ok = false; |
| } |
| } |
| if (optargs_ok) |
| options.add(option); |
| else |
| { |
| // If the option requires more arguments than given on the |
| // command line, issue a fatal error |
| |
| reporter.printFatal("Missing value for option " + arg + "."); |
| } |
| } |
| } |
| |
| //--- Create an array of String arrays from the dynamic array built above |
| |
| String[][] optionArr = (String[][]) options.toArray(new String[options |
| .size()][0]); |
| |
| //--- Validate all options and issue warnings/errors |
| |
| if (validOptions(optionArr, rootDoc)) |
| { |
| |
| //--- We got valid options; parse them and store the parsed values |
| // in 'option_*' fields. |
| |
| readOptions(optionArr); |
| |
| //--- Show version and exit if requested by user |
| |
| if (option_showVersion) { |
| System.out.println("gjdoc " + getGjdocVersion()); |
| System.exit(0); |
| } |
| |
| if (option_bootclasspath_specified) { |
| reporter.printWarning("-bootclasspath ignored: not supported by" |
| + " gjdoc wrapper script, or no wrapper script in use."); |
| } |
| |
| // If we have an empty source path list, add the current directory ('.') |
| |
| if (option_sourcepath.size() == 0) |
| option_sourcepath.add(new File(".")); |
| |
| //--- We have all information we need to start the doclet at this time |
| |
| if (null != option_encoding) { |
| rootDoc.setSourceEncoding(option_encoding); |
| } |
| else { |
| // be quiet about this for now: |
| // reporter.printNotice("No encoding specified, using platform default: " + System.getProperty("file.encoding")); |
| rootDoc.setSourceEncoding(System.getProperty("file.encoding")); |
| } |
| rootDoc.setSourcePath(option_sourcepath); |
| |
| //addJavaLangClasses(); |
| |
| if (!startDoclet(arguments)) { |
| return -1; |
| } |
| } |
| |
| return reporter.getErrorCount(); |
| } |
| |
| private void addJavaLangClasses() |
| throws IOException |
| { |
| String resourceName = "/java.lang-classes-" + option_source + ".txt"; |
| InputStream in = getClass().getResourceAsStream(resourceName); |
| BufferedReader reader = new BufferedReader(new InputStreamReader(in)); |
| String line; |
| while ((line = reader.readLine()) != null) { |
| |
| String className = line.trim(); |
| if (className.length() > 0) { |
| ClassDocImpl classDoc = |
| new ClassDocImpl(null, new PackageDocImpl("java.lang"), |
| ProgramElementDocImpl.ACCESS_PUBLIC, |
| false, false, null); |
| classDoc.setClass(className); |
| rootDoc.addClassDoc(classDoc); |
| } |
| } |
| } |
| |
| /** |
| * Helper class for parsing command line arguments. An instance of this class |
| * represents a particular option accepted by gjdoc (e.g. '-sourcepath') along |
| * with the number of expected arguments and behavior to parse the arguments. |
| */ |
| private abstract class OptionProcessor |
| { |
| |
| /** |
| * Number of arguments expected by this option. |
| */ |
| private int argCount; |
| |
| /** |
| * Initializes this instance. |
| * |
| * @param argCount |
| * number of arguments |
| */ |
| public OptionProcessor(int argCount) |
| { |
| this.argCount = argCount; |
| } |
| |
| /** |
| * Overridden by derived classes with behavior to parse the arguments |
| * specified with this option. |
| * |
| * @param args |
| * command line arguments |
| */ |
| abstract void process(String[] args); |
| } |
| |
| /** |
| * Maps option tags (e.g. '-sourcepath') to OptionProcessor objects. |
| * Initialized only once by method initOptions(). FIXME: Rename to |
| * 'optionProcessors'. |
| */ |
| private static Map options = null; |
| |
| /** |
| * Initialize all OptionProcessor objects needed to scan/parse command line |
| * options. This cannot be done in a static initializer block because |
| * OptionProcessors need access to the Singleton instance of the Main class. |
| */ |
| private void initOptions() |
| { |
| |
| options = new HashMap(); |
| |
| //--- Put one OptionProcessor object into the map |
| // for each option recognized. |
| |
| options.put("-overview", new OptionProcessor(2) |
| { |
| |
| void process(String[] args) |
| { |
| option_overview = args[0]; |
| } |
| }); |
| options.put("-public", new OptionProcessor(1) |
| { |
| |
| void process(String[] args) |
| { |
| option_coverage = COVERAGE_PUBLIC; |
| } |
| }); |
| options.put("-protected", new OptionProcessor(1) |
| { |
| |
| void process(String[] args) |
| { |
| option_coverage = COVERAGE_PROTECTED; |
| } |
| }); |
| options.put("-package", new OptionProcessor(1) |
| { |
| |
| void process(String[] args) |
| { |
| option_coverage = COVERAGE_PACKAGE; |
| } |
| }); |
| options.put("-private", new OptionProcessor(1) |
| { |
| |
| void process(String[] args) |
| { |
| option_coverage = COVERAGE_PRIVATE; |
| } |
| }); |
| OptionProcessor helpProcessor = new OptionProcessor(1) |
| { |
| |
| void process(String[] args) |
| { |
| option_help = true; |
| } |
| }; |
| |
| options.put("-help", helpProcessor); |
| options.put("--help", helpProcessor); |
| options.put("-doclet", new OptionProcessor(2) |
| { |
| |
| void process(String[] args) |
| { |
| option_doclet = args[0]; |
| } |
| }); |
| options.put("-docletpath", new OptionProcessor(2) |
| { |
| |
| void process(String[] args) |
| { |
| option_docletpath = args[0]; |
| } |
| }); |
| options.put("-nowarn", new OptionProcessor(1) |
| { |
| |
| void process(String[] args) |
| { |
| option_nowarn = true; |
| } |
| }); |
| options.put("-source", new OptionProcessor(2) |
| { |
| |
| void process(String[] args) |
| { |
| option_source = args[0]; |
| if (!"1.2".equals(option_source) |
| && !"1.3".equals(option_source) |
| && !"1.4".equals(option_source)) { |
| |
| throw new RuntimeException("Only he following values are currently" |
| + " supported for option -source: 1.2, 1.3, 1.4."); |
| } |
| } |
| }); |
| OptionProcessor sourcePathProcessor = new OptionProcessor(2) { |
| void process(String[] args) |
| { |
| Debug.log(1, "-sourcepath is '" + args[0] + "'"); |
| for (StringTokenizer st = new StringTokenizer(args[0], |
| File.pathSeparator); st.hasMoreTokens();) |
| { |
| String path = st.nextToken(); |
| File file = new File(path); |
| if (!(file.exists())) |
| { |
| throw new RuntimeException("The source path " + path |
| + " does not exist."); |
| } |
| option_sourcepath.add(file); |
| } |
| } |
| }; |
| options.put("-s", sourcePathProcessor); |
| options.put("-sourcepath", sourcePathProcessor); |
| options.put("-subpackages", new OptionProcessor(2) |
| { |
| void process(String[] args) |
| { |
| StringTokenizer st = new StringTokenizer(args[0], ":"); |
| while (st.hasMoreTokens()) { |
| String packageName = st.nextToken(); |
| |
| if (packageName.startsWith(".") |
| || packageName.endsWith(".") |
| || packageName.indexOf("..") > 0 |
| || !checkCharSet(packageName, |
| "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890_.")) { |
| throw new RuntimeException("Illegal package name '" |
| + packageName + "'"); |
| } |
| option_subpackages.add(packageName); |
| } |
| } |
| }); |
| options.put("-exclude", new OptionProcessor(2) |
| { |
| void process(String[] args) |
| { |
| StringTokenizer st = new StringTokenizer(args[0], ":"); |
| while (st.hasMoreTokens()) { |
| String packageName = st.nextToken(); |
| |
| if (packageName.startsWith(".") |
| || packageName.endsWith(".") |
| || packageName.indexOf("..") > 0 |
| || !checkCharSet(packageName, |
| "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890_.")) { |
| throw new RuntimeException("Illegal package name '" |
| + packageName + "'"); |
| } |
| option_exclude.add(packageName); |
| } |
| } |
| }); |
| // TODO include other options here |
| options.put("-verbose", new OptionProcessor(1) |
| { |
| |
| void process(String[] args) |
| { |
| option_verbose = true; |
| System.err.println("WARNING: Unsupported option -verbose ignored"); |
| } |
| }); |
| options.put("-quiet", new OptionProcessor(1) |
| { |
| |
| void process(String[] args) |
| { |
| reporter.setQuiet(true); |
| } |
| }); |
| options.put("-locale", new OptionProcessor(2) |
| { |
| |
| void process(String[] args) |
| { |
| String localeName = args[0]; |
| String language = null; |
| String country = null; |
| String variant = null; |
| StringTokenizer st = new StringTokenizer(localeName, "_"); |
| if (st.hasMoreTokens()) { |
| language = st.nextToken(); |
| } |
| if (st.hasMoreTokens()) { |
| country = st.nextToken(); |
| } |
| if (st.hasMoreTokens()) { |
| variant = st.nextToken(); |
| } |
| if (variant != null) { |
| option_locale = new Locale(language, country, variant); |
| } |
| else if (country != null) { |
| option_locale = new Locale(language, country); |
| } |
| else if (language != null) { |
| option_locale = new Locale(language); |
| } |
| else { |
| throw new RuntimeException("Illegal locale specification '" |
| + localeName + "'"); |
| } |
| } |
| }); |
| options.put("-encoding", new OptionProcessor(2) |
| { |
| |
| void process(String[] args) |
| { |
| option_encoding = args[0]; |
| } |
| }); |
| options.put("-breakiterator", new OptionProcessor(1) |
| { |
| void process(String[] args) |
| { |
| option_breakiterator = true; |
| } |
| }); |
| options.put("-licensetext", new OptionProcessor(1) |
| { |
| void process(String[] args) |
| { |
| option_licensetext = true; |
| } |
| }); |
| options.put("-overview", new OptionProcessor(2) |
| { |
| void process(String[] args) |
| { |
| try { |
| getRootDoc().setRawCommentText(RootDocImpl.readHtmlBody(new File(args[0]))); |
| } |
| catch (IOException e) { |
| throw new RuntimeException("Cannot read file specified in option -overview: " + e.getMessage()); |
| } |
| } |
| }); |
| options.put("-classpath", new OptionProcessor(2) |
| { |
| void process(String[] args) |
| { |
| reporter.printWarning("-classpath option could not be passed to the VM. Faking it with "); |
| reporter.printWarning(" System.setProperty(\"java.class.path\", \"" + args[0] + "\");"); |
| System.setProperty("java.class.path", args[0]); |
| } |
| }); |
| options.put("--version", new OptionProcessor(1) |
| { |
| void process(String[] args) |
| { |
| option_showVersion = true; |
| } |
| }); |
| options.put("-bootclasspath", new OptionProcessor(1) |
| { |
| void process(String[] args) |
| { |
| option_bootclasspath_specified = true; |
| } |
| }); |
| options.put("-all", new OptionProcessor(1) |
| { |
| void process(String[] args) |
| { |
| option_all = true; |
| } |
| }); |
| options.put("-reflection", new OptionProcessor(1) |
| { |
| void process(String[] args) |
| { |
| option_reflection = true; |
| } |
| }); |
| } |
| |
| /** |
| * Determine how many arguments the given option requires. |
| * |
| * @param option |
| * The name of the option without leading dash. |
| */ |
| private static int optionLength(String option) |
| { |
| |
| OptionProcessor op = (OptionProcessor) options.get(option.toLowerCase()); |
| if (op != null) |
| return op.argCount; |
| else |
| return 0; |
| } |
| |
| /** |
| * Process all given options. Assumes that the options have been validated |
| * before. |
| * |
| * @param optionArr |
| * Each element is a series of Strings where [0] is the name of the |
| * option and [1..n] are the arguments to the option. |
| */ |
| private void readOptions(String[][] optionArr) |
| { |
| |
| //--- For each option, find the appropriate OptionProcessor |
| // and call its process() method |
| |
| for (int i = 0; i < optionArr.length; ++i) |
| { |
| String[] opt = optionArr[i]; |
| String[] args = new String[opt.length - 1]; |
| System.arraycopy(opt, 1, args, 0, opt.length - 1); |
| OptionProcessor op = (OptionProcessor) options.get(opt[0].toLowerCase()); |
| op.process(args); |
| } |
| } |
| |
| /** |
| * Print command line usage. |
| */ |
| private static void usage() |
| { |
| System.out |
| .print("\n" |
| + "USAGE: gjdoc [options] [packagenames] " |
| + "[sourcefiles] [@files]\n\n" |
| + " --version Show version information and exit\n" |
| + " -all Process all source files found in the source path\n" |
| + " -overview <file> Read overview documentation from HTML file\n" |
| + " -public Include only public classes and members\n" |
| + " -protected Include protected and public classes and members\n" |
| + " This is the default\n" |
| + " -package Include package/protected/public classes and members\n" |
| + " -private Include all classes and members\n" |
| + " -help, --help Show this information\n" |
| + " -doclet <class> Doclet class to use for generating output\n" |
| + " -docletpath <classpath> Specifies the search path for the doclet and\n" |
| + " dependencies\n" |
| + " -source <release> Provide source compatibility with specified\n" |
| + " release (1.4 to handle assertion)\n" |
| + " -sourcepath <pathlist> Where to look for source files\n" |
| + " -s <pathlist> Alias for -sourcepath\n" |
| + " -subpackages <spkglist> List of subpackages to recursively load\n" |
| + " -exclude <pkglist> List of packages to exclude\n" |
| + " -verbose Output messages about what Gjdoc is doing [ignored]\n" |
| + " -quiet Do not print non-error and non-warning messages\n" |
| + " -locale <name> Locale to be used, e.g. en_US or en_US_WIN\n" |
| + " -encoding <name> Source file encoding name\n" |
| + " -breakiterator Compute first sentence with BreakIterator\n" |
| + " -classpath <pathlist> Set the path used for loading auxilliary classes\n" |
| + "\n" |
| + "Standard doclet options:\n" |
| + " -d Set target directory\n" |
| + " -use Includes the 'Use' page for each documented class\n" |
| + " and package\n" |
| + " -version Includes the '@version' tag\n" |
| + " -author Includes the '@author' tag\n" |
| + " -splitindex Splits the index file into multiple files\n" |
| + " -windowtitle <text> Browser window title\n" |
| + " -doctitle <text> Title near the top of the overview summary file\n" |
| + " (HTML allowed)\n" |
| + " -title <text> Title for this set of API documentation\n" |
| + " (deprecated, -doctitle should be used instead)\n" |
| + " -header <text> Text to include in the top navigation bar\n" |
| + " (HTML allowed)\n" |
| + " -footer <text> Text to include in the bottom navigation bar\n" |
| + " (HTML allowed)\n" |
| + " -bottom <text> Text to include at the bottom of each output file\n" |
| + " (HTML allowed)\n" |
| + " -link <extdoc URL> Link to external generated documentation at URL\n" |
| + " -linkoffline <extdoc URL> <packagelistLoc>\n" |
| + " Link to external generated documentation for\n" |
| + " the specified package-list\n" |
| + " -linksource Creates an HTML version of each source file\n" |
| + " -group <groupheading> <packagepattern:packagepattern:...>\n" |
| + " Separates packages on the overview page into groups\n" |
| + " -nodeprecated Prevents the generation of any deprecated API\n" |
| + " -nodeprecatedlist Prevents the generation of the file containing\n" |
| + " the list of deprecated APIs and the link to the\n" |
| + " navigation bar to that page\n" |
| + " -nosince Omit the '@since' tag\n" |
| + " -notree Do not generate the class/interface hierarchy page\n" |
| + " -noindex Do not generate the index file\n" |
| + " -nohelp Do not generate the help link\n" |
| + " -nonavbar Do not generate the navbar, header and footer\n" |
| + " -helpfile <filen> Path to an alternate help file\n" |
| + " -stylesheetfile <file> Path to an alternate CSS stylesheet\n" |
| + " -addstylesheet <file> Path to an additional CSS stylesheet\n" |
| + " -serialwarn Complain about missing '@serial' tags [ignored]\n" |
| + " -charset <IANACharset> Specifies the HTML charset\n" |
| + " -docencoding <IANACharset>\n" |
| + " Specifies the encoding of the generated HTML files\n" |
| + " -tag <tagname>:Xaoptcmf:\"<taghead>\"\n" |
| + " Enables gjdoc to interpret a custom tag\n" |
| + " -taglet Adds a Taglet class to the map of taglets\n" |
| + " -tagletpath Sets the CLASSPATH to load subsequent Taglets from\n" |
| + " -docfilessubdirs Enables deep copy of 'doc-files' directories\n" |
| + " -excludedocfilessubdir <name1:name2:...>\n" |
| + " Excludes 'doc-files' subdirectories with a give name\n" |
| + " -noqualifier all|<packagename1:packagename2:...>\n" |
| + " Do never fully qualify given package names\n" |
| + " -nocomment Suppress the entire comment body including the main\n" |
| + " description and all tags, only generate declarations\n" |
| + "\n" |
| + "Gjdoc extension options:\n" |
| + " -reflection Use reflection for resolving unqualified class names\n" |
| + " -licensetext Include license text from source files\n" |
| + " -validhtml Use valid HTML/XML names (breaks compatibility)\n" |
| + " -baseurl <url> Hardwire the given base URL into generated pages\n" |
| /** |
| + " -genhtml Generate HTML code instead of XML code. This is the\n" |
| + " default.\n" |
| + " -geninfo Generate Info code instead of XML code.\n" |
| + " -xslsheet <file> If specified, XML files will be written to a\n" |
| + " temporary directory and transformed using the\n" |
| + " given XSL sheet. The result of the transformation\n" |
| + " is written to the output directory. Not required if\n" |
| + " -genhtml or -geninfo has been specified.\n" |
| + " -xmlonly Generate XML code only, do not generate HTML code.\n" |
| + " -bottomnote HTML code to include at the bottom of each page.\n" |
| + " -nofixhtml If not specified, heurestics will be applied to\n" |
| + " fix broken HTML code in comments.\n" |
| + " -nohtmlwarn Do not emit warnings when encountering broken HTML\n" |
| + " code.\n" |
| + " -noemailwarn Do not emit warnings when encountering strings like\n" |
| + " <abc@foo.com>.\n" |
| + " -indentstep <n> How many spaces to indent each tag level in\n" |
| + " generated XML code.\n" |
| + " -xsltdriver <class> Specifies the XSLT driver to use for transformation.\n" |
| + " By default, xsltproc is used.\n" |
| + " -postprocess <class> XmlDoclet postprocessor class to apply after XSL\n" |
| + " transformation.\n" |
| + " -compress Generated info pages will be Zip-compressed.\n" |
| + " -workpath Specify a temporary directory to use.\n" |
| + " -authormail <type> Specify handling of mail addresses in @author tags.\n" |
| + " no-replace do not replace mail addresses (default).\n" |
| + " mailto-name replace by <a>Real Name</a>.\n" |
| + " name-mailto-address replace by Real Name (<a>abc@foo.com</a>).\n" |
| + " name-mangled-address replace by Real Name (<a>abc AT foo DOT com</a>).\n" |
| **/ |
| ); |
| } |
| |
| /** |
| * The root of the gjdoc tool. |
| * |
| * @return all the options of the gjdoc application. |
| */ |
| public static RootDocImpl getRootDoc() |
| { |
| return rootDoc; |
| } |
| |
| /** |
| * Get the gjdoc singleton. |
| * |
| * @return the gjdoc instance. |
| */ |
| public static Main getInstance() |
| { |
| return instance; |
| } |
| |
| /** |
| * Is this access level covered? |
| * |
| * @param accessLevel |
| * the access level we want to know if it is covered. |
| * @return true if the access level is covered. |
| */ |
| public boolean includeAccessLevel(int accessLevel) |
| { |
| return coverageTemplates[option_coverage][accessLevel]; |
| } |
| |
| /** |
| * Is the doclet running? |
| * |
| * @return true if it's running |
| */ |
| public boolean isDocletRunning() |
| { |
| return docletRunning; |
| } |
| |
| /** |
| * Check the charset. Check that all the characters of the string 'toCheck' |
| * and query if they exist in the 'charSet'. The order does not matter. The |
| * number of times a character is in the variable does not matter. |
| * |
| * @param toCheck |
| * the charset to check. |
| * @param charSet |
| * the reference charset |
| * @return true if they match. |
| */ |
| public static boolean checkCharSet(String toCheck, String charSet) |
| { |
| for (int i = 0; i < toCheck.length(); ++i) |
| { |
| if (charSet.indexOf(toCheck.charAt(i)) < 0) |
| return false; |
| } |
| return true; |
| } |
| |
| /** |
| * Makes the RootDoc eligible for the GC. |
| */ |
| public static void releaseRootDoc() |
| { |
| rootDoc.flush(); |
| } |
| |
| /** |
| * Return whether the -breakiterator option has been specified. |
| */ |
| public boolean isUseBreakIterator() |
| { |
| return this.option_breakiterator |
| || !getLocale().getLanguage().equals(Locale.ENGLISH.getLanguage()); |
| } |
| |
| /** |
| * Return whether boilerplate license text should be copied. |
| */ |
| public boolean isCopyLicenseText() |
| { |
| return this.option_licensetext; |
| } |
| |
| /** |
| * Return the locale specified using the -locale option or the |
| * default locale; |
| */ |
| public Locale getLocale() |
| { |
| return this.option_locale; |
| } |
| |
| /** |
| * Return the collator to use based on the specified -locale |
| * option. If no collator can be found for the given locale, a |
| * warning is emitted and the default collator is used instead. |
| */ |
| public Collator getCollator() |
| { |
| if (null == this.collator) { |
| Locale locale = getLocale(); |
| this.collator = Collator.getInstance(locale); |
| Locale defaultLocale = Locale.getDefault(); |
| if (null == this.collator |
| && !defaultLocale.equals(locale)) { |
| this.collator = Collator.getInstance(defaultLocale); |
| if (null != this.collator) { |
| reporter.printWarning("No collator found for locale " |
| + locale.getDisplayName() |
| + "; using collator for default locale " |
| + defaultLocale.getDisplayName() |
| + "."); |
| } |
| else { |
| this.collator = Collator.getInstance(); |
| reporter.printWarning("No collator found for specified locale " |
| + locale.getDisplayName() |
| + " or default locale " |
| + defaultLocale.getDisplayName() |
| + ": using default collator."); |
| } |
| } |
| if (null == this.collator) { |
| this.collator = Collator.getInstance(); |
| reporter.printWarning("No collator found for locale " |
| + locale.getDisplayName() |
| + ": using default collator."); |
| } |
| } |
| return this.collator; |
| } |
| |
| public boolean isCacheRawComments() |
| { |
| return true; |
| } |
| |
| public String getGjdocVersion() |
| { |
| if (null == gjdocVersion) { |
| try { |
| Properties versionProperties = new Properties(); |
| versionProperties.load(getClass().getResourceAsStream("version.properties")); |
| gjdocVersion = versionProperties.getProperty("gjdoc.version"); |
| } |
| catch (IOException ignore) { |
| } |
| if (null == gjdocVersion) { |
| gjdocVersion = "unknown"; |
| } |
| } |
| return gjdocVersion; |
| } |
| |
| public boolean isReflectionEnabled() |
| { |
| return this.option_reflection; |
| } |
| } |