package com.revolsys.doclet.client; import java.util.ArrayList; import java.util.List; import java.util.Map; import com.revolsys.doclet.BaseDoclet; import com.revolsys.doclet.DocletUtil; import com.revolsys.util.HtmlAttr; import com.revolsys.util.HtmlElem; import com.revolsys.util.HtmlUtil; import com.sun.javadoc.AnnotationTypeDoc; import com.sun.javadoc.AnnotationTypeElementDoc; import com.sun.javadoc.AnnotationValue; import com.sun.javadoc.ClassDoc; import com.sun.javadoc.ConstructorDoc; import com.sun.javadoc.DocErrorReporter; import com.sun.javadoc.ExecutableMemberDoc; import com.sun.javadoc.FieldDoc; 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 ClientDoclet extends BaseDoclet { public static LanguageVersion languageVersion() { return LanguageVersion.JAVA_1_5; } public static int optionLength(final String optionName) { return DocletUtil.optionLength(optionName); } public static boolean start(final RootDoc root) { new ClientDoclet(root).start(); return true; } public static boolean validOptions(final String options[][], final DocErrorReporter docerrorreporter) { return DocletUtil.validOptions(options, docerrorreporter); } public ClientDoclet(final RootDoc root) { super(root); } public void addResponseStatusDescription(final Map<String, List<String>> responseCodes, final String code, final String description) { List<String> descriptions = responseCodes.get(code); if (descriptions == null) { descriptions = new ArrayList<>(); responseCodes.put(code, descriptions); } descriptions.add(description); } @Override public void documentation() { DocletUtil.contentContainer(this.writer, "col-md-12"); this.writer.element(HtmlElem.H1, this.docTitle); DocletUtil.description(this.writer, null, this.root); for (final PackageDoc packageDoc : this.root.specifiedPackages()) { documentationPackage(packageDoc); } DocletUtil.endContentContainer(this.writer); } public void documentationAnnotation(final AnnotationTypeDoc annotationDoc) { final String name = annotationDoc.name(); final String id = getClassId(annotationDoc); DocletUtil.panelStart(this.writer, "panel-primary", HtmlElem.H3, id, "annotation", name, null); DocletUtil.description(this.writer, annotationDoc, annotationDoc); final AnnotationTypeElementDoc[] elements = annotationDoc.elements(); if (elements.length > 0) { this.writer.startTag(HtmlElem.DIV); this.writer.attribute(HtmlAttr.CLASS, "table-responsive parameters"); this.writer.startTag(HtmlElem.TABLE); this.writer.attribute(HtmlAttr.CLASS, "table table-striped table-bordered table-condensed"); this.writer.startTag(HtmlElem.THEAD); this.writer.startTag(HtmlElem.TR); this.writer.element(HtmlElem.TH, "Name"); this.writer.element(HtmlElem.TH, "Type"); this.writer.element(HtmlElem.TH, "Default"); 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 AnnotationTypeElementDoc element : elements) { this.writer.startTag(HtmlElem.TR); final String elementName = element.name(); this.writer.startTag(HtmlElem.TD); this.writer.attribute(HtmlAttr.CLASS, "name"); DocletUtil.anchor(this.writer, id + "." + elementName, elementName); this.writer.endTagLn(HtmlElem.TD); this.writer.startTag(HtmlElem.TD); this.writer.attribute(HtmlAttr.CLASS, "type"); DocletUtil.typeNameLink(this.writer, element.returnType()); this.writer.endTagLn(HtmlElem.TD); this.writer.startTag(HtmlElem.TD); this.writer.attribute(HtmlAttr.CLASS, "default"); final AnnotationValue defaultValue = element.defaultValue(); if (defaultValue == null) { this.writer.text("-"); } else { this.writer.text(defaultValue); } this.writer.endTagLn(HtmlElem.TD); this.writer.startTag(HtmlElem.TD); this.writer.attribute(HtmlAttr.CLASS, "description"); DocletUtil.description(this.writer, null, element); this.writer.endTagLn(HtmlElem.TD); this.writer.endTagLn(HtmlElem.TR); } this.writer.endTagLn(HtmlElem.TBODY); this.writer.endTagLn(HtmlElem.TABLE); this.writer.endTagLn(HtmlElem.DIV); } DocletUtil.panelEnd(this.writer); } public void documentationAnnotations(final PackageDoc packageDoc) { final Map<String, AnnotationTypeDoc> annotations = BaseDoclet.getAnnotations(packageDoc); if (!annotations.isEmpty()) { for (final AnnotationTypeDoc annotationDoc : annotations.values()) { documentationAnnotation(annotationDoc); } } } public void documentationClass(final String classType, final ClassDoc classDoc) { final String id = getClassId(classDoc); final String name = classDoc.name(); DocletUtil.panelStart(this.writer, "panel-primary", HtmlElem.H3, id, classType, name, null); DocletUtil.description(this.writer, classDoc, classDoc); final ConstructorDoc[] constructors = classDoc.constructors(); if (constructors.length > 0) { for (final ConstructorDoc method : constructors) { documentationMethod(method); } } final MethodDoc[] methods = classDoc.methods(); if (methods.length > 0) { for (final MethodDoc method : methods) { documentationMethod(method); } } DocletUtil.panelEnd(this.writer); } public void documentationClasses(final PackageDoc packageDoc) { final Map<String, ClassDoc> classes = BaseDoclet.getClasses(packageDoc); if (!classes.isEmpty()) { for (final ClassDoc classDoc : classes.values()) { documentationClass("class", classDoc); } } } public void documentationEnum(final ClassDoc enumDoc) { final String id = getClassId(enumDoc); final String name = enumDoc.name(); DocletUtil.panelStart(this.writer, "panel-primary", HtmlElem.H3, id, "enum", name, null); DocletUtil.description(this.writer, enumDoc, enumDoc); final FieldDoc[] elements = enumDoc.enumConstants(); if (elements.length > 0) { this.writer.startTag(HtmlElem.DIV); this.writer.attribute(HtmlAttr.CLASS, "table-responsive parameters"); this.writer.startTag(HtmlElem.TABLE); this.writer.attribute(HtmlAttr.CLASS, "table table-striped table-bordered"); this.writer.startTag(HtmlElem.THEAD); this.writer.startTag(HtmlElem.TR); this.writer.element(HtmlElem.TH, "Constant"); 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 FieldDoc element : elements) { this.writer.startTag(HtmlElem.TR); final String elementName = element.name(); this.writer.startTag(HtmlElem.TD); this.writer.attribute(HtmlAttr.CLASS, "constant"); this.writer.attribute(HtmlAttr.ID, id + "_" + elementName); HtmlUtil.elementWithId(this.writer, HtmlElem.SPAN, id + "." + elementName, elementName); this.writer.endTagLn(HtmlElem.TD); this.writer.startTag(HtmlElem.TD); this.writer.attribute(HtmlAttr.CLASS, "description"); DocletUtil.description(this.writer, null, element); this.writer.endTagLn(HtmlElem.TD); this.writer.endTagLn(HtmlElem.TR); } this.writer.endTagLn(HtmlElem.TBODY); this.writer.endTagLn(HtmlElem.TABLE); this.writer.endTagLn(HtmlElem.DIV); } DocletUtil.panelEnd(this.writer); } public void documentationEnums(final PackageDoc packageDoc) { final Map<String, ClassDoc> enums = BaseDoclet.getEnums(packageDoc); if (!enums.isEmpty()) { for (final ClassDoc enumDoc : enums.values()) { documentationEnum(enumDoc); } } } public void documentationInterfaces(final PackageDoc packageDoc) { final Map<String, ClassDoc> interfaces = BaseDoclet.getInterfaces(packageDoc); if (!interfaces.isEmpty()) { for (final ClassDoc classDoc : interfaces.values()) { documentationClass("interface", classDoc); } } } public void documentationMethod(final ExecutableMemberDoc member) { final String id = getMemberId(member); this.writer.startTag(HtmlElem.DIV); this.writer.attribute(HtmlAttr.CLASS, "panel panel-info"); this.writer.startTag(HtmlElem.DIV); this.writer.attribute(HtmlAttr.CLASS, "panel-heading"); final String simpleId = id.replaceAll("[^a-zA-Z0-9_]", "_"); this.writer.startTag(HtmlElem.A); this.writer.attribute(HtmlAttr.ID, id); this.writer.text(""); this.writer.endTag(HtmlElem.A); this.writer.startTag(HtmlElem.H4); this.writer.attribute(HtmlAttr.CLASS, "panel-title"); this.writer.attribute(HtmlAttr.ID, simpleId); methodSignature(member); this.writer.endTagLn(HtmlElem.H4); this.writer.endTagLn(HtmlElem.DIV); this.writer.startTag(HtmlElem.DIV); this.writer.attribute(HtmlAttr.CLASS, "panel-body"); DocletUtil.description(this.writer, member.containingClass(), member); parameters(member); if (member instanceof MethodDoc) { final MethodDoc method = (MethodDoc)member; DocletUtil.documentationReturn(this.writer, method); } DocletUtil.panelEnd(this.writer); } public void documentationPackage(final PackageDoc packageDoc) { final String name = packageDoc.name(); final String id = name; DocletUtil.panelStart(this.writer, "panel-default", HtmlElem.H2, id, "package", name, null); DocletUtil.description(this.writer, null, packageDoc); documentationAnnotations(packageDoc); documentationEnums(packageDoc); documentationInterfaces(packageDoc); documentationClasses(packageDoc); DocletUtil.panelEnd(this.writer); } private String getAnchor(final ExecutableMemberDoc member) { final StringBuilder anchor = new StringBuilder(); final ClassDoc classDoc = member.containingClass(); final String className = getClassId(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.SMALL); final MethodDoc method = (MethodDoc)member; final Type returnType = method.returnType(); DocletUtil.typeName(this.writer, returnType); this.writer.text(" "); this.writer.endTagLn(HtmlElem.SMALL); } 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.SMALL); 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.SMALL); this.writer.endTagLn(HtmlElem.A); } @Override public void navbar() { DocletUtil.navbarStart(this.writer, this.docTitle); for (final PackageDoc packageDoc : this.root.specifiedPackages()) { navMenus(getAnnotations(packageDoc)); navMenus(getEnums(packageDoc)); navMenus(getInterfaces(packageDoc)); navMenus(getClasses(packageDoc)); } DocletUtil.navbarEnd(this.writer); } public void navMenu(final ClassDoc classDoc) { final String name = classDoc.name(); final String id = getClassId(classDoc); DocletUtil.navDropdownStart(this.writer, name, "#" + id, false); for (final MethodDoc methodDoc : classDoc.methods()) { navMenu(classDoc, methodDoc); } DocletUtil.navDropdownEnd(this.writer); } public void navMenu(final ClassDoc classDoc, final MethodDoc methodDoc) { final String name = methodDoc.name(); final String id = getMemberId(methodDoc); DocletUtil.navMenuItem(this.writer, name, "#" + id); } protected void navMenus(final Map<String, ? extends ClassDoc> classes) { for (final ClassDoc classDoc : classes.values()) { navMenu(classDoc); } } private void parameters(final ExecutableMemberDoc method) { final List<Parameter> parameters = new ArrayList<>(); for (final Parameter parameter : method.parameters()) { parameters.add(parameter); } if (!parameters.isEmpty()) { final Map<String, Tag[]> descriptions = DocletUtil.getParameterDescriptions(method); this.writer.startTag(HtmlElem.DIV); this.writer.attribute(HtmlAttr.CLASS, "table-responsive parameters"); this.writer.startTag(HtmlElem.TABLE); this.writer.attribute(HtmlAttr.CLASS, "table table-striped table-bordered table-condensed"); 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"); final Type type = parameter.type(); DocletUtil.typeNameLink(this.writer, type); this.writer.endTagLn(HtmlElem.TD); DocletUtil.descriptionTd(this.writer, method.containingClass(), descriptions, name); this.writer.endTagLn(HtmlElem.TR); } this.writer.endTagLn(HtmlElem.TBODY); this.writer.endTagLn(HtmlElem.TABLE); this.writer.endTagLn(HtmlElem.DIV); } } }