package org.tldgen; import static org.tldgen.util.JavadocUtils.getEnumAttribute; import static org.tldgen.util.JavadocUtils.getStringAttribute; import java.io.File; import java.io.IOException; import java.io.PrintStream; import java.lang.reflect.Field; import java.util.Set; import java.util.TreeSet; import org.apache.commons.io.FileUtils; import org.tldgen.util.ArrayUtilities; import org.apache.commons.lang.ArrayUtils; import org.apache.commons.lang.StringUtils; import org.tldgen.annotations.License; import org.tldgen.annotations.TldVersion; import org.tldgen.model.Library; import org.tldgen.model.LibrarySignature; import org.tldgen.util.JavadocUtils; import com.sun.javadoc.AnnotationDesc; import com.sun.javadoc.PackageDoc; import com.sun.javadoc.RootDoc; /** * Parse doclet options and create TLD documentation * * @author ccoloma */ public class TldDoclet { private static String DEFAULT_HTML_FOLDER = "build/docs/tlddoc"; private static String DEFAULT_TLD_FOLDER = "src/main/resources/META-INF"; /** TLD file display-name */ private static String displayName; /** TLD version */ private static String version; /** TLD file short-name */ private static String name; /** TLD file uri */ private static String uri; /** HTML documentation target directory */ private static String htmlFolder = DEFAULT_HTML_FOLDER; /** TLD target directory */ private static String tldFolder = DEFAULT_TLD_FOLDER; /** TLD File ident */ private static String indentSpaces; /** TLD File license */ private static String license; /** true to format output, false otherwise. Default true */ private static String formatOutput; /** options accepted by this Doclet */ private static Set<String> options; /** for testing purposes */ public static Library library; static { options = new TreeSet<String>(); options.add("displayName"); options.add("formatOutput"); options.add("htmlFolder"); options.add("license"); options.add("name"); options.add("tabSpaces"); options.add("tldFolder"); options.add("uri"); options.add("version"); } /** * @throws IllegalArgumentException * if illegal or inappropriate TLD filename or creating output * stream. * @throws IllegalStateException * if closing a output stream that it is not opened */ public static boolean start(RootDoc root) { boolean result = false; try { DocletOptions options = parseOptions(root.options()); TldWorker worker = new TldWorker(options); if (name != null && uri != null) { library = worker.processLibrary(root.classes(), createLibrarySignatureFromCommandLine(), tldFolder, htmlFolder); result = true; } else { for (PackageDoc tagsPackage : root.specifiedPackages()) { AnnotationDesc libraryAnnotation = JavadocUtils.getAnnotation(tagsPackage, org.tldgen.annotations.Library.class); if (libraryAnnotation != null) { library = worker.processLibrary(tagsPackage.allClasses(), createLibrarySignatureFromAnnotation(libraryAnnotation), tldFolder, htmlFolder); // if uri is not specified then use the reverse package name if (library.getLibrarySignature().getUri() == null) { library.getLibrarySignature().setUri("http://" + new String(ArrayUtilities.reverseTokens(tagsPackage.name().toCharArray(), '.'))); } result = true; } } } } finally { if (!result) { showUsage(); } } return result; } public static LibrarySignature createLibrarySignatureFromCommandLine() { LibrarySignature librarySignature = new LibrarySignature(); librarySignature.setDisplayName(displayName); librarySignature.setLicense(convertLicense()); librarySignature.setShortName(name); librarySignature.setUri(uri); librarySignature.setVersion(convertVersion()); return librarySignature; } public static LibrarySignature createLibrarySignatureFromAnnotation(AnnotationDesc libraryAnnotation) { LibrarySignature librarySignature = new LibrarySignature(); librarySignature.setDescription(getStringAttribute(libraryAnnotation, "description")); librarySignature.setDisplayName(getStringAttribute(libraryAnnotation, "displayName")); librarySignature.setSmallIcon(getStringAttribute(libraryAnnotation, "smallIcon")); librarySignature.setLargeIcon(getStringAttribute(libraryAnnotation, "largeIcon")); librarySignature.setShortName(getStringAttribute(libraryAnnotation, "shortName")); librarySignature.setUri(getStringAttribute(libraryAnnotation, "uri")); license = getEnumAttribute(libraryAnnotation, "license"); librarySignature.setLicense(convertLicense()); version = TldVersion.valueOf(getEnumAttribute(libraryAnnotation, "version")).getId(); librarySignature.setVersion(convertVersion()); return librarySignature; } private static License convertLicense() { try { if (license == null) { return License.NONE; } return License.valueOf(license.toUpperCase()); } catch (IllegalArgumentException e) { try { File f = new File(license); if (!f.exists() || !f.isFile()) { String licenseNames = StringUtils.join(ArrayUtils.removeElement(License.values(), License.CUSTOM), ", "); throw new IllegalArgumentException("Invalid license. Available licenses are: " + licenseNames + ", or any valid file location."); } String licenseHeader = FileUtils.readFileToString(f); License license = License.CUSTOM; license.setLicenseHeader(licenseHeader); return license; } catch (IOException e1) { throw new RuntimeException(e1); } } } private static TldVersion convertVersion() { TldVersion v = TldVersion.convert(version); return v == null? TldVersion.VERSION_20 : v; } private static void showUsage() { PrintStream out = System.out; out.println("Usage: "); out.println("tldgen"); out.println(" -sourcepath {path to java source files}"); out.println(" -subpackages {tags package name}"); out.println(""); out.println(" -displayName {name}"); out.println(" -formatOutput {true | false}"); out.println(" -htmlFolder {HTML documentation directory}"); out.println(" -indentSpaces {number of indent spaces}"); out.println(" -license {APACHE | GPL | LGPL | MIT | MOZILLA | CC | NONE | [file location]}"); out.println(" -name {name}"); out.println(" -tldFolder {TLD folder name}"); out.println(" -uri {uri name}"); out.println(" -version {TLD version}"); out.println(""); out.println("This doclet accepts the following options:"); out.println(""); out.println(" -name: the <name> element of the TLD file"); out.println(" -uri: the <uri> element of the TLD file"); out.println(" -displayName (optional): the <display-name> element of the TLD file"); out.println(" -formatOutput (optional, default true): Indent the generated files."); out.println(" -htmlFolder (optional, default " + DEFAULT_HTML_FOLDER + "): the folder \n" + " where HTML documentation will be stored"); out.println(" -indentSpaces (optional, default 4): spaces used for indenting XML content."); out.println(" -license (optional, default NONE): The license to include."); out.println(" -tldFolder (optional, default src/main/resources/META-INF/): \n" + " the folder where the TLD file will be stored."); out.println(" -version (optional, default 2.0): The TLD version to use."); out.println(""); out.println("If -name or -uri is not present, TldGen will search for @Library annotations in "); out.println("the root packages"); out.println(""); } /** * Parse the user options received by this doclet * @param userOptions the list of extra options accepted by javadoc */ private static DocletOptions parseOptions(String[][] userOptions) { try { for (String[] option : userOptions) { String fieldName = option[0].substring(1); if (options.contains(fieldName)) { Field field = TldDoclet.class.getDeclaredField(fieldName); field.set(null, option[1]); } } DocletOptions options = new DocletOptions(); if (formatOutput != null) { options.withFormatOutput(Boolean.valueOf(formatOutput)); } if (indentSpaces != null) { options.withIndentSpaces(indentSpaces); } if (license != null) { options.withLicense(convertLicense()); } if (version != null) { options.withVersion(convertVersion()) ; } return options; } catch (NoSuchFieldException e) { throw new RuntimeException(e); } catch (IllegalAccessException e) { throw new RuntimeException(e); } } /** * Return the number of parameters available for each option. See * http://java * .sun.com/j2se/1.5.0/docs/guide/javadoc/doclet/overview.html#options * * @param option * the name of the option parameter * @return the number of expected value, 0 if unrecognized */ public static int optionLength(String option) { return options.contains("-" + option)? 0 : 2; } public static void reset() { displayName = version = name = uri = indentSpaces = license = formatOutput = null; library = null; htmlFolder = DEFAULT_HTML_FOLDER; tldFolder = DEFAULT_TLD_FOLDER; } }