package com.revolsys.doclet.java; import java.io.File; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.TreeMap; import com.revolsys.doclet.BaseDoclet; import com.revolsys.doclet.DocletUtil; import com.revolsys.io.FileUtil; import com.revolsys.util.HtmlAttr; import com.revolsys.util.HtmlElem; import com.sun.javadoc.ClassDoc; import com.sun.javadoc.ConstructorDoc; import com.sun.javadoc.DocErrorReporter; import com.sun.javadoc.ExecutableMemberDoc; import com.sun.javadoc.LanguageVersion; import com.sun.javadoc.MethodDoc; import com.sun.javadoc.PackageDoc; import com.sun.javadoc.Parameter; import com.sun.javadoc.RootDoc; import com.sun.javadoc.Tag; import com.sun.javadoc.Type; public class JavaDoclet extends BaseDoclet { public static LanguageVersion languageVersion() { return LanguageVersion.JAVA_1_5; } public static int optionLength(String optionName) { final int optionLength = DocletUtil.optionLength(optionName); if (optionLength == 0) { optionName = optionName.toLowerCase(); if (optionName.equals("-docid") || optionName.equals("-htmlfooter") || optionName.equals("-htmlheader")) { return 2; } } return optionLength; } public static boolean start(final RootDoc root) { new JavaDoclet(root).start(); return true; } public static boolean validOptions(final String options[][], final DocErrorReporter docerrorreporter) { final boolean flag = true; for (final String[] option : options) { final String argName = option[0].toLowerCase(); if (argName.equals("-d")) { final String destDir = option[1]; final File file = new File(destDir); if (!file.exists()) { docerrorreporter.printNotice("Create directory" + destDir); file.mkdirs(); } if (!file.isDirectory()) { docerrorreporter.printError("Destination not a directory" + file.getPath()); return false; } else if (!file.canWrite()) { docerrorreporter.printError("Destination directory not writable " + file.getPath()); return false; } } else if (argName.equals("-htmlheader")) { if (!new File(option[1]).exists()) { docerrorreporter.printError("Header file does not exist" + option[1]); return false; } } else if (argName.equals("-htmlfooter")) { if (!new File(option[1]).exists()) { docerrorreporter.printError("Footer file does not exist" + option[1]); return false; } } } return flag; } private String docId; private String header; private String footer; public JavaDoclet(final RootDoc root) { super(root); } public void bodyContent() { this.writer.element(HtmlElem.H1, this.docTitle); DocletUtil.description(this.writer, null, this.root); documentation(); } @Override public void documentation() { this.writer.startTag(HtmlElem.DIV); for (final PackageDoc packageDoc : this.root.specifiedPackages()) { documentationPackage(packageDoc); } this.writer.endTagLn(HtmlElem.DIV); } public void documentationClass(final ClassDoc classDoc) { this.writer.startTag(HtmlElem.DIV); this.writer.attribute(HtmlAttr.CLASS, "javaClass"); final String name = classDoc.name(); DocletUtil.title(this.writer, getClassId(classDoc), name); this.writer.startTag(HtmlElem.DIV); this.writer.attribute(HtmlAttr.CLASS, "content"); DocletUtil.description(this.writer, classDoc, classDoc); final ConstructorDoc[] constructors = classDoc.constructors(); if (constructors.length > 0) { DocletUtil.title(this.writer, HtmlElem.H3, "Constructors"); for (final ConstructorDoc method : constructors) { documentationMethod(method); } } final MethodDoc[] methods = classDoc.methods(); if (methods.length > 0) { DocletUtil.title(this.writer, HtmlElem.H3, "Methods"); for (final MethodDoc method : methods) { documentationMethod(method); } } this.writer.endTagLn(HtmlElem.DIV); this.writer.endTagLn(HtmlElem.DIV); } public void documentationMethod(final ExecutableMemberDoc member) { this.writer.startTag(HtmlElem.DIV); this.writer.attribute(HtmlAttr.CLASS, "javaMethod"); this.writer.startTag(HtmlElem.DIV); this.writer.attribute(HtmlAttr.CLASS, "title"); methodSignature(member); this.writer.endTagLn(HtmlElem.DIV); this.writer.startTag(HtmlElem.DIV); this.writer.attribute(HtmlAttr.CLASS, "content"); DocletUtil.description(this.writer, member.containingClass(), member); parameters(member); if (member instanceof MethodDoc) { final MethodDoc method = (MethodDoc)member; DocletUtil.documentationReturn(this.writer, method); } this.writer.endTagLn(HtmlElem.DIV); this.writer.endTagLn(HtmlElem.DIV); } public void documentationPackage(final PackageDoc packageDoc) { final String name = packageDoc.name(); this.writer.startTag(HtmlElem.A); this.writer.attribute(HtmlAttr.NAME, name); this.writer.text(""); this.writer.endTagLn(HtmlElem.A); this.writer.startTag(HtmlElem.DIV); this.writer.attribute(HtmlAttr.CLASS, "javaPackage"); DocletUtil.title(this.writer, name, name); this.writer.startTag(HtmlElem.DIV); this.writer.attribute(HtmlAttr.CLASS, "content"); DocletUtil.description(this.writer, null, packageDoc); final Map<String, ClassDoc> classes = new TreeMap<>(); for (final ClassDoc classDoc : packageDoc.ordinaryClasses()) { classes.put(classDoc.name(), classDoc); } for (final ClassDoc classDoc : classes.values()) { documentationClass(classDoc); } this.writer.endTagLn(HtmlElem.DIV); this.writer.endTagLn(HtmlElem.DIV); } public String getAnchor(final ExecutableMemberDoc member) { final StringBuilder anchor = new StringBuilder(); final ClassDoc classDoc = member.containingClass(); final String className = DocletUtil.qualifiedName(classDoc); anchor.append(className); anchor.append("."); anchor.append(member.name()); anchor.append("("); final Parameter[] parameters = member.parameters(); boolean first = true; for (final Parameter parameter : parameters) { if (first) { first = false; } else { anchor.append(","); } final Type type = parameter.type(); String typeName = type.qualifiedTypeName(); typeName = typeName.replaceAll("^java.lang.", ""); typeName = typeName.replaceAll("^java.io.", ""); typeName = typeName.replaceAll("^java.util.", ""); anchor.append(typeName); anchor.append(type.dimension()); } anchor.append(")"); return anchor.toString(); } public void methodSignature(final ExecutableMemberDoc member) { this.writer.startTag(HtmlElem.A); final String anchor = getAnchor(member); this.writer.attribute(HtmlAttr.NAME, anchor); if (member instanceof MethodDoc) { this.writer.startTag(HtmlElem.CODE); final MethodDoc method = (MethodDoc)member; final Type returnType = method.returnType(); DocletUtil.typeName(this.writer, returnType); this.writer.text(" "); this.writer.endTagLn(HtmlElem.CODE); } if (member.isStatic()) { this.writer.startTag(HtmlElem.I); } this.writer.text(member.name()); if (member.isStatic()) { this.writer.endTag(HtmlElem.I); } this.writer.startTag(HtmlElem.CODE); this.writer.text("("); final Parameter[] parameters = member.parameters(); boolean first = true; for (final Parameter parameter : parameters) { if (first) { first = false; } else { this.writer.text(", "); } DocletUtil.typeName(this.writer, parameter.type()); this.writer.text(" "); this.writer.text(parameter.name()); } this.writer.text(")"); this.writer.endTagLn(HtmlElem.CODE); this.writer.endTagLn(HtmlElem.A); } public void parameters(final ExecutableMemberDoc method) { final List<Parameter> parameters = new ArrayList<>(); for (final Parameter parameter : method.parameters()) { parameters.add(parameter); } if (!parameters.isEmpty()) { final ClassDoc containingClass = method.containingClass(); final Map<String, Tag[]> descriptions = DocletUtil.getParameterDescriptions(method); DocletUtil.title(this.writer, HtmlElem.H3, "Parameters"); this.writer.startTag(HtmlElem.DIV); this.writer.attribute(HtmlAttr.CLASS, "simpleDataTable parameters"); this.writer.startTag(HtmlElem.TABLE); this.writer.attribute(HtmlAttr.CLASS, "data"); this.writer.startTag(HtmlElem.THEAD); this.writer.startTag(HtmlElem.TR); this.writer.element(HtmlElem.TH, "Parameter"); this.writer.element(HtmlElem.TH, "Type"); this.writer.startTag(HtmlElem.TH); this.writer.attribute(HtmlAttr.CLASS, "description"); this.writer.text("Description"); this.writer.endTag(HtmlElem.TH); this.writer.endTagLn(HtmlElem.TR); this.writer.endTagLn(HtmlElem.THEAD); this.writer.startTag(HtmlElem.TBODY); for (final Parameter parameter : parameters) { this.writer.startTag(HtmlElem.TR); final String name = parameter.name(); this.writer.startTag(HtmlElem.TD); this.writer.attribute(HtmlAttr.CLASS, "name"); this.writer.text(parameter.name()); this.writer.endTagLn(HtmlElem.TD); this.writer.startTag(HtmlElem.TD); this.writer.attribute(HtmlAttr.CLASS, "type"); DocletUtil.typeNameLink(this.writer, parameter.type()); this.writer.endTagLn(HtmlElem.TD); DocletUtil.descriptionTd(this.writer, containingClass, descriptions, name); this.writer.endTagLn(HtmlElem.TR); } this.writer.endTagLn(HtmlElem.TBODY); this.writer.endTagLn(HtmlElem.TABLE); this.writer.endTagLn(HtmlElem.DIV); } } @Override protected void setOptions(final String[][] options) { for (final String[] option : options) { final String optionName = option[0]; if (optionName.equals("-docid")) { this.docId = option[1]; } else if (optionName.equals("-htmlheader")) { this.header = FileUtil.getFileAsString(option[1]); } else if (optionName.equals("-htmlfooter")) { this.footer = FileUtil.getFileAsString(option[1]); } } super.setOptions(options); FileUtil.copy(getClass().getResourceAsStream("/com/revolsys/doclet/javadoc.css"), new File(this.destDir, "javadoc.css")); FileUtil.copy(getClass().getResourceAsStream("/com/revolsys/doclet/javadoc.js"), new File(this.destDir, "javadoc.js")); } @Override protected void start() { try { setOptions(this.root.options()); if (this.header == null) { this.writer.startDocument("UTF-8", "1.0"); this.writer.docType("html", null); this.writer.startTag(HtmlElem.HTML); this.writer.attribute(HtmlAttr.LANG, "en"); DocletUtil.headOld(this.writer, this.docTitle); this.writer.startTag(HtmlElem.BODY); } else { this.header = this.header.replaceAll("\\$\\{docTitle\\}", this.docTitle); this.header = this.header.replaceAll("\\$\\{docId\\}", this.docId); this.writer.write(this.header); } bodyContent(); if (this.footer == null) { this.writer.endTagLn(HtmlElem.BODY); this.writer.endTagLn(HtmlElem.HTML); } else { this.footer = this.footer.replaceAll("\\$\\{docTitle\\}", this.docTitle); this.footer = this.footer.replaceAll("\\$\\{docId\\}", this.docId); this.writer.write(this.footer); } this.writer.endDocument(); } finally { if (this.writer != null) { this.writer.close(); } } } }