diff --git a/src/main/java/org/umlgraph/doclet/ClassGraph.java b/src/main/java/org/umlgraph/doclet/ClassGraph.java index fe2e21e..83552ea 100644 --- a/src/main/java/org/umlgraph/doclet/ClassGraph.java +++ b/src/main/java/org/umlgraph/doclet/ClassGraph.java @@ -61,6 +61,7 @@ import com.sun.javadoc.WildcardType; /** * Class graph generation engine + * * @depend - - - StringUtil * @depend - - - Options * @composed - - * ClassInfo @@ -71,891 +72,896 @@ import com.sun.javadoc.WildcardType; */ class ClassGraph { enum Align { - LEFT, CENTER, RIGHT; + LEFT, CENTER, RIGHT; - public final String lower; + public final String lower; - private Align() { - this.lower = toString().toLowerCase(); - } + private Align() { + this.lower = toString().toLowerCase(); + } }; protected Map classnames = new HashMap(); protected Set rootClasses; - protected Map rootClassdocs = new HashMap(); + protected Map rootClassdocs = new HashMap(); protected OptionProvider optionProvider; protected PrintWriter w; protected ClassDoc collectionClassDoc; protected ClassDoc mapClassDoc; protected String linePostfix; protected String linePrefix; - - // used only when generating context class diagrams in UMLDoc, to generate the proper + + // used only when generating context class diagrams in UMLDoc, to generate the + // proper // relative links to other classes in the image map protected final String contextPackageName; - + /** - * Create a new ClassGraph.

The packages passed as an - * argument are the ones specified on the command line.

- *

Local URLs will be generated for these packages.

- * @param root The root of docs as provided by the javadoc API + * Create a new ClassGraph. + *

+ * The packages passed as an argument are the ones specified on the command + * line. + *

+ *

+ * Local URLs will be generated for these packages. + *

+ * + * @param root The root of docs as provided by the javadoc API * @param optionProvider The main option provider - * @param contextDoc The current context for generating relative links, may be a ClassDoc - * or a PackageDoc (used by UMLDoc) + * @param contextDoc The current context for generating relative links, may + * be a ClassDoc or a PackageDoc (used by UMLDoc) */ public ClassGraph(RootDoc root, OptionProvider optionProvider, Doc contextDoc) { - this.optionProvider = optionProvider; - this.collectionClassDoc = root.classNamed("java.util.Collection"); - this.mapClassDoc = root.classNamed("java.util.Map"); - - // to gather the packages containing specified classes, loop thru them and gather - // package definitions. User root.specifiedPackages is not safe, since the user - // may specify just a list of classes (human users usually don't, but automated tools do) - rootClasses = new HashSet(); - for (ClassDoc classDoc : root.classes()) { - rootClasses.add(classDoc.qualifiedName()); - rootClassdocs.put(classDoc.qualifiedName(), classDoc); - } - - // determine the context path, relative to the root - if (contextDoc instanceof ClassDoc) - contextPackageName = ((ClassDoc) contextDoc).containingPackage().name(); - else if (contextDoc instanceof PackageDoc) - contextPackageName = ((PackageDoc) contextDoc).name(); - else - contextPackageName = null; // Not available - - Options opt = optionProvider.getGlobalOptions(); - linePrefix = opt.compact ? "" : "\t"; - linePostfix = opt.compact ? "" : "\n"; - } + this.optionProvider = optionProvider; + this.collectionClassDoc = root.classNamed("java.util.Collection"); + this.mapClassDoc = root.classNamed("java.util.Map"); - + // to gather the packages containing specified classes, loop thru them and + // gather + // package definitions. User root.specifiedPackages is not safe, since the user + // may specify just a list of classes (human users usually don't, but automated + // tools do) + rootClasses = new HashSet(); + for (ClassDoc classDoc : root.classes()) { + rootClasses.add(classDoc.qualifiedName()); + rootClassdocs.put(classDoc.qualifiedName(), classDoc); + } + + // determine the context path, relative to the root + if (contextDoc instanceof ClassDoc) + contextPackageName = ((ClassDoc) contextDoc).containingPackage().name(); + else if (contextDoc instanceof PackageDoc) + contextPackageName = ((PackageDoc) contextDoc).name(); + else + contextPackageName = null; // Not available + + Options opt = optionProvider.getGlobalOptions(); + linePrefix = opt.compact ? "" : "\t"; + linePostfix = opt.compact ? "" : "\n"; + } /** Return the class's name, possibly by stripping the leading path */ private static String qualifiedName(Options opt, String r) { - if (opt.hideGenerics) - r = removeTemplate(r); - // Fast path - nothing to do: - if (opt.showQualified && (opt.showQualifiedGenerics || r.indexOf('<') < 0)) - return r; - StringBuilder buf = new StringBuilder(r.length()); - qualifiedNameInner(opt, r, buf, 0, !opt.showQualified); - return buf.toString(); + if (opt.hideGenerics) + r = removeTemplate(r); + // Fast path - nothing to do: + if (opt.showQualified && (opt.showQualifiedGenerics || r.indexOf('<') < 0)) + return r; + StringBuilder buf = new StringBuilder(r.length()); + qualifiedNameInner(opt, r, buf, 0, !opt.showQualified); + return buf.toString(); } private static int qualifiedNameInner(Options opt, String r, StringBuilder buf, int last, boolean strip) { - strip = strip && last < r.length() && Character.isLowerCase(r.charAt(last)); - for (int i = last; i < r.length(); i++) { - char c = r.charAt(i); - if (c == '.' || c == '$') { - if (strip) - last = i + 1; // skip dot - strip = strip && last < r.length() && Character.isLowerCase(r.charAt(last)); - continue; - } - if (Character.isJavaIdentifierPart(c)) - continue; - buf.append(r, last, i); - last = i; - // Handle nesting of generics - if (c == '<') { - buf.append('<'); - i = last = qualifiedNameInner(opt, r, buf, ++last, !opt.showQualifiedGenerics); - buf.append('>'); - } else if (c == '>') - return i + 1; - } - buf.append(r, last, r.length()); - return r.length(); + strip = strip && last < r.length() && Character.isLowerCase(r.charAt(last)); + for (int i = last; i < r.length(); i++) { + char c = r.charAt(i); + if (c == '.' || c == '$') { + if (strip) + last = i + 1; // skip dot + strip = strip && last < r.length() && Character.isLowerCase(r.charAt(last)); + continue; + } + if (Character.isJavaIdentifierPart(c)) + continue; + buf.append(r, last, i); + last = i; + // Handle nesting of generics + if (c == '<') { + buf.append('<'); + i = last = qualifiedNameInner(opt, r, buf, ++last, !opt.showQualifiedGenerics); + buf.append('>'); + } else if (c == '>') + return i + 1; + } + buf.append(r, last, r.length()); + return r.length(); } /** - * Print the visibility adornment of element e prefixed by - * any stereotypes + * Print the visibility adornment of element e prefixed by any stereotypes */ private String visibility(Options opt, ProgramElementDoc e) { - return opt.showVisibility ? Visibility.get(e).symbol : " "; + return opt.showVisibility ? Visibility.get(e).symbol : " "; } /** Print the method parameter p */ private String parameter(Options opt, Parameter p[]) { - StringBuilder par = new StringBuilder(1000); - for (int i = 0; i < p.length; i++) { - par.append(p[i].name() + typeAnnotation(opt, p[i].type())); - if (i + 1 < p.length) - par.append(", "); - } - return par.toString(); + StringBuilder par = new StringBuilder(1000); + for (int i = 0; i < p.length; i++) { + par.append(p[i].name() + typeAnnotation(opt, p[i].type())); + if (i + 1 < p.length) + par.append(", "); + } + return par.toString(); } /** Print a a basic type t */ private String type(Options opt, Type t, boolean generics) { - return ((generics ? opt.showQualifiedGenerics : opt.showQualified) ? // - t.qualifiedTypeName() : t.typeName()) // - + (opt.hideGenerics ? "" : typeParameters(opt, t.asParameterizedType())); + return ((generics ? opt.showQualifiedGenerics : opt.showQualified) ? // + t.qualifiedTypeName() : t.typeName()) // + + (opt.hideGenerics ? "" : typeParameters(opt, t.asParameterizedType())); } /** Print the parameters of the parameterized type t */ private String typeParameters(Options opt, ParameterizedType t) { - if (t == null) - return ""; - StringBuffer tp = new StringBuffer(1000).append("<"); - Type args[] = t.typeArguments(); - for (int i = 0; i < args.length; i++) { - tp.append(type(opt, args[i], true)); - if (i != args.length - 1) - tp.append(", "); - } - return tp.append(">").toString(); + if (t == null) + return ""; + StringBuffer tp = new StringBuffer(1000).append("<"); + Type args[] = t.typeArguments(); + for (int i = 0; i < args.length; i++) { + tp.append(type(opt, args[i], true)); + if (i != args.length - 1) + tp.append(", "); + } + return tp.append(">").toString(); } /** Annotate an field/argument with its type t */ private String typeAnnotation(Options opt, Type t) { - if (t.typeName().equals("void")) - return ""; - return " : " + type(opt, t, false) + t.dimension(); + if (t.typeName().equals("void")) + return ""; + return " : " + type(opt, t, false) + t.dimension(); } /** Print the class's attributes fd */ private void attributes(Options opt, FieldDoc fd[]) { - for (FieldDoc f : fd) { - if (hidden(f)) - continue; - stereotype(opt, f, Align.LEFT); - String att = visibility(opt, f) + f.name(); - if (opt.showType) - att += typeAnnotation(opt, f.type()); - tableLine(Align.LEFT, att); - tagvalue(opt, f); - } + for (FieldDoc f : fd) { + if (hidden(f)) + continue; + stereotype(opt, f, Align.LEFT); + String att = visibility(opt, f) + f.name(); + if (opt.showType) + att += typeAnnotation(opt, f.type()); + tableLine(Align.LEFT, att); + tagvalue(opt, f); + } } /* - * The following two methods look similar, but can't - * be refactored into one, because their common interface, - * ExecutableMemberDoc, doesn't support returnType for ctors. + * The following two methods look similar, but can't be refactored into one, + * because their common interface, ExecutableMemberDoc, doesn't support + * returnType for ctors. */ /** Print the class's constructors m */ private boolean operations(Options opt, ConstructorDoc m[]) { - boolean printed = false; - for (ConstructorDoc cd : m) { - if (hidden(cd)) - continue; - stereotype(opt, cd, Align.LEFT); - String cs = visibility(opt, cd) + cd.name() // - + (opt.showType ? "(" + parameter(opt, cd.parameters()) + ")" : "()"); - tableLine(Align.LEFT, cs); - tagvalue(opt, cd); - printed = true; - } - return printed; + boolean printed = false; + for (ConstructorDoc cd : m) { + if (hidden(cd)) + continue; + stereotype(opt, cd, Align.LEFT); + String cs = visibility(opt, cd) + cd.name() // + + (opt.showType ? "(" + parameter(opt, cd.parameters()) + ")" : "()"); + tableLine(Align.LEFT, cs); + tagvalue(opt, cd); + printed = true; + } + return printed; } /** Print the class's operations m */ private boolean operations(Options opt, MethodDoc m[]) { - boolean printed = false; - for (MethodDoc md : m) { - if (hidden(md)) - continue; - // Filter-out static initializer method - if (md.name().equals("") && md.isStatic() && md.isPackagePrivate()) - continue; - stereotype(opt, md, Align.LEFT); - String op = visibility(opt, md) + md.name() + // - (opt.showType ? "(" + parameter(opt, md.parameters()) + ")" + typeAnnotation(opt, md.returnType()) - : "()"); - tableLine(Align.LEFT, (md.isAbstract() ? Font.ABSTRACT : Font.NORMAL).wrap(opt, op)); - printed = true; + boolean printed = false; + for (MethodDoc md : m) { + if (hidden(md)) + continue; + // Filter-out static initializer method + if (md.name().equals("") && md.isStatic() && md.isPackagePrivate()) + continue; + stereotype(opt, md, Align.LEFT); + String op = visibility(opt, md) + md.name() + // + (opt.showType ? "(" + parameter(opt, md.parameters()) + ")" + typeAnnotation(opt, md.returnType()) + : "()"); + tableLine(Align.LEFT, (md.isAbstract() ? Font.ABSTRACT : Font.NORMAL).wrap(opt, op)); + printed = true; - tagvalue(opt, md); - } - return printed; + tagvalue(opt, md); + } + return printed; } /** Print the common class node's properties */ private void nodeProperties(Options opt) { - Options def = opt.getGlobalOptions(); - if (opt.nodeFontName != def.nodeFontName) - w.print(",fontname=\"" + opt.nodeFontName + "\""); - if (opt.nodeFontColor != def.nodeFontColor) - w.print(",fontcolor=\"" + opt.nodeFontColor + "\""); - if (opt.nodeFontSize != def.nodeFontSize) - w.print(",fontsize=" + fmt(opt.nodeFontSize)); - w.print(opt.shape.style); - w.println("];"); + Options def = opt.getGlobalOptions(); + if (opt.nodeFontName != def.nodeFontName) + w.print(",fontname=\"" + opt.nodeFontName + "\""); + if (opt.nodeFontColor != def.nodeFontColor) + w.print(",fontcolor=\"" + opt.nodeFontColor + "\""); + if (opt.nodeFontSize != def.nodeFontSize) + w.print(",fontsize=" + fmt(opt.nodeFontSize)); + w.print(opt.shape.style); + w.println("];"); } /** * Return as a string the tagged values associated with c - * @param opt the Options used to guess font names - * @param c the Doc entry to look for @tagvalue + * + * @param opt the Options used to guess font names + * @param c the Doc entry to look for @tagvalue * @param prevterm the termination string for the previous element - * @param term the termination character for each tagged value + * @param term the termination character for each tagged value */ private void tagvalue(Options opt, Doc c) { - Tag tags[] = c.tags("tagvalue"); - if (tags.length == 0) - return; - - for (Tag tag : tags) { - String t[] = tokenize(tag.text()); - if (t.length != 2) { - System.err.println("@tagvalue expects two fields: " + tag.text()); - continue; - } - tableLine(Align.RIGHT, Font.TAG.wrap(opt, "{" + t[0] + " = " + t[1] + "}")); - } + Tag tags[] = c.tags("tagvalue"); + if (tags.length == 0) + return; + + for (Tag tag : tags) { + String t[] = tokenize(tag.text()); + if (t.length != 2) { + System.err.println("@tagvalue expects two fields: " + tag.text()); + continue; + } + tableLine(Align.RIGHT, Font.TAG.wrap(opt, "{" + t[0] + " = " + t[1] + "}")); + } } /** - * Return as a string the stereotypes associated with c - * terminated by the escape character term + * Return as a string the stereotypes associated with c terminated by the escape + * character term */ private void stereotype(Options opt, Doc c, Align align) { - for (Tag tag : c.tags("stereotype")) { - String t[] = tokenize(tag.text()); - if (t.length != 1) { - System.err.println("@stereotype expects one field: " + tag.text()); - continue; - } - tableLine(align, guilWrap(opt, t[0])); - } + for (Tag tag : c.tags("stereotype")) { + String t[] = tokenize(tag.text()); + if (t.length != 1) { + System.err.println("@stereotype expects one field: " + tag.text()); + continue; + } + tableLine(align, guilWrap(opt, t[0])); + } } /** Return true if c has a @hidden tag associated with it */ private boolean hidden(ProgramElementDoc c) { - if (c.tags("hidden").length > 0 || c.tags("view").length > 0) - return true; - Options opt = optionProvider.getOptionsFor(c instanceof ClassDoc ? (ClassDoc) c : c.containingClass()); - return opt.matchesHideExpression(c.toString()) // - || (opt.hidePrivateInner && c instanceof ClassDoc && c.isPrivate() && ((ClassDoc) c).containingClass() != null); + if (c.tags("hidden").length > 0 || c.tags("view").length > 0) + return true; + Options opt = optionProvider.getOptionsFor(c instanceof ClassDoc ? (ClassDoc) c : c.containingClass()); + return opt.matchesHideExpression(c.toString()) // + || (opt.hidePrivateInner && c instanceof ClassDoc && c.isPrivate() + && ((ClassDoc) c).containingClass() != null); } protected ClassInfo getClassInfo(ClassDoc cd, boolean create) { - return getClassInfo(cd, cd.toString(), create); + return getClassInfo(cd, cd.toString(), create); } protected ClassInfo getClassInfo(String className, boolean create) { - return getClassInfo(null, className, create); + return getClassInfo(null, className, create); } protected ClassInfo getClassInfo(ClassDoc cd, String className, boolean create) { - className = removeTemplate(className); - ClassInfo ci = classnames.get(className); - if (ci == null && create) { - boolean hidden = cd != null ? hidden(cd) : optionProvider.getOptionsFor(className).matchesHideExpression(className); - ci = new ClassInfo(hidden); - classnames.put(className, ci); - } - return ci; + className = removeTemplate(className); + ClassInfo ci = classnames.get(className); + if (ci == null && create) { + boolean hidden = cd != null ? hidden(cd) + : optionProvider.getOptionsFor(className).matchesHideExpression(className); + ci = new ClassInfo(hidden); + classnames.put(className, ci); + } + return ci; } - /** Return true if the class name is associated to an hidden class or matches a hide expression */ + /** + * Return true if the class name is associated to an hidden class or matches a + * hide expression + */ private boolean hidden(String className) { - className = removeTemplate(className); - ClassInfo ci = classnames.get(className); - return ci != null ? ci.hidden : optionProvider.getOptionsFor(className).matchesHideExpression(className); + className = removeTemplate(className); + ClassInfo ci = classnames.get(className); + return ci != null ? ci.hidden : optionProvider.getOptionsFor(className).matchesHideExpression(className); } /** * Prints the class if needed. *

* A class is a rootClass if it's included among the classes returned by - * RootDoc.classes(), this information is used to properly compute - * relative links in diagrams for UMLDoc + * RootDoc.classes(), this information is used to properly compute relative + * links in diagrams for UMLDoc */ public String printClass(ClassDoc c, boolean rootClass) { - ClassInfo ci = getClassInfo(c, true); - if(ci.nodePrinted || ci.hidden) - return ci.name; - Options opt = optionProvider.getOptionsFor(c); - if (c.isEnum() && !opt.showEnumerations) - return ci.name; - String className = c.toString(); - // Associate classname's alias - w.println(linePrefix + "// " + className); - // Create label - w.print(linePrefix + ci.name + " [label="); + ClassInfo ci = getClassInfo(c, true); + if (ci.nodePrinted || ci.hidden) + return ci.name; + Options opt = optionProvider.getOptionsFor(c); + if (c.isEnum() && !opt.showEnumerations) + return ci.name; + String className = c.toString(); + // Associate classname's alias + w.println(linePrefix + "// " + className); + // Create label + w.print(linePrefix + ci.name + " [label="); - boolean showMembers = - (opt.showAttributes && c.fields().length > 0) || - (c.isEnum() && opt.showEnumConstants && c.enumConstants().length > 0) || - (opt.showOperations && c.methods().length > 0) || - (opt.showConstructors && c.constructors().length > 0); + boolean showMembers = (opt.showAttributes && c.fields().length > 0) + || (c.isEnum() && opt.showEnumConstants && c.enumConstants().length > 0) + || (opt.showOperations && c.methods().length > 0) + || (opt.showConstructors && c.constructors().length > 0); - final String url = classToUrl(c, rootClass); - externalTableStart(opt, c.qualifiedName(), url); + final String url = classToUrl(c, rootClass); + externalTableStart(opt, c.qualifiedName(), url); - firstInnerTableStart(opt); - if (c.isInterface()) - tableLine(Align.CENTER, guilWrap(opt, "interface")); - if (c.isEnum()) - tableLine(Align.CENTER, guilWrap(opt, "enumeration")); - stereotype(opt, c, Align.CENTER); - Font font = c.isAbstract() && !c.isInterface() ? Font.CLASS_ABSTRACT : Font.CLASS; - String qualifiedName = qualifiedName(opt, className); - int idx = splitPackageClass(qualifiedName); - if (opt.showComment) - tableLine(Align.LEFT, Font.CLASS.wrap(opt, htmlNewline(escape(c.commentText())))); - else if (opt.postfixPackage && idx > 0 && idx < (qualifiedName.length() - 1)) { - String packageName = qualifiedName.substring(0, idx); - String cn = qualifiedName.substring(idx + 1); - tableLine(Align.CENTER, font.wrap(opt, escape(cn))); - tableLine(Align.CENTER, Font.PACKAGE.wrap(opt, packageName)); - } else { - tableLine(Align.CENTER, font.wrap(opt, escape(qualifiedName))); - } - tagvalue(opt, c); - firstInnerTableEnd(opt); + firstInnerTableStart(opt); + if (c.isInterface()) + tableLine(Align.CENTER, guilWrap(opt, "interface")); + if (c.isEnum()) + tableLine(Align.CENTER, guilWrap(opt, "enumeration")); + stereotype(opt, c, Align.CENTER); + Font font = c.isAbstract() && !c.isInterface() ? Font.CLASS_ABSTRACT : Font.CLASS; + String qualifiedName = qualifiedName(opt, className); + int idx = splitPackageClass(qualifiedName); + if (opt.showComment) + tableLine(Align.LEFT, Font.CLASS.wrap(opt, htmlNewline(escape(c.commentText())))); + else if (opt.postfixPackage && idx > 0 && idx < (qualifiedName.length() - 1)) { + String packageName = qualifiedName.substring(0, idx); + String cn = qualifiedName.substring(idx + 1); + tableLine(Align.CENTER, font.wrap(opt, escape(cn))); + tableLine(Align.CENTER, Font.PACKAGE.wrap(opt, packageName)); + } else { + tableLine(Align.CENTER, font.wrap(opt, escape(qualifiedName))); + } + tagvalue(opt, c); + firstInnerTableEnd(opt); - /* - * Warning: The boolean expressions guarding innerTableStart() - * in this block, should match those in the code block above - * marked: "Calculate the number of innerTable rows we will emmit" - */ - if (showMembers) { - if (opt.showAttributes) { - innerTableStart(); - FieldDoc[] fields = c.fields(); - // if there are no fields, print an empty line to generate proper HTML - if (fields.length == 0) - tableLine(Align.LEFT, ""); - else - attributes(opt, c.fields()); - innerTableEnd(); - } else if(!c.isEnum() && (opt.showConstructors || opt.showOperations)) { - // show an emtpy box if we don't show attributes but - // we show operations - innerTableStart(); - tableLine(Align.LEFT, ""); - innerTableEnd(); - } - if (c.isEnum() && opt.showEnumConstants) { - innerTableStart(); - FieldDoc[] ecs = c.enumConstants(); - // if there are no constants, print an empty line to generate proper HTML - if (ecs.length == 0) { - tableLine(Align.LEFT, ""); - } else { - for (FieldDoc fd : c.enumConstants()) { - tableLine(Align.LEFT, fd.name()); - } - } - innerTableEnd(); - } - if (!c.isEnum() && (opt.showConstructors || opt.showOperations)) { - innerTableStart(); - boolean printedLines = false; - if (opt.showConstructors) - printedLines |= operations(opt, c.constructors()); - if (opt.showOperations) - printedLines |= operations(opt, c.methods()); + /* + * Warning: The boolean expressions guarding innerTableStart() in this block, + * should match those in the code block above marked: + * "Calculate the number of innerTable rows we will emmit" + */ + if (showMembers) { + if (opt.showAttributes) { + innerTableStart(); + FieldDoc[] fields = c.fields(); + // if there are no fields, print an empty line to generate proper HTML + if (fields.length == 0) + tableLine(Align.LEFT, ""); + else + attributes(opt, c.fields()); + innerTableEnd(); + } else if (!c.isEnum() && (opt.showConstructors || opt.showOperations)) { + // show an emtpy box if we don't show attributes but + // we show operations + innerTableStart(); + tableLine(Align.LEFT, ""); + innerTableEnd(); + } + if (c.isEnum() && opt.showEnumConstants) { + innerTableStart(); + FieldDoc[] ecs = c.enumConstants(); + // if there are no constants, print an empty line to generate proper HTML + if (ecs.length == 0) { + tableLine(Align.LEFT, ""); + } else { + for (FieldDoc fd : c.enumConstants()) { + tableLine(Align.LEFT, fd.name()); + } + } + innerTableEnd(); + } + if (!c.isEnum() && (opt.showConstructors || opt.showOperations)) { + innerTableStart(); + boolean printedLines = false; + if (opt.showConstructors) + printedLines |= operations(opt, c.constructors()); + if (opt.showOperations) + printedLines |= operations(opt, c.methods()); - if (!printedLines) - // if there are no operations nor constructors, - // print an empty line to generate proper HTML - tableLine(Align.LEFT, ""); + if (!printedLines) + // if there are no operations nor constructors, + // print an empty line to generate proper HTML + tableLine(Align.LEFT, ""); - innerTableEnd(); - } - } - externalTableEnd(); - if (url != null) - w.print(", URL=\"" + url + "\""); - nodeProperties(opt); + innerTableEnd(); + } + } + externalTableEnd(); + if (url != null) + w.print(", URL=\"" + url + "\""); + nodeProperties(opt); - // If needed, add a note for this node - int ni = 0; - for (Tag t : c.tags("note")) { - String noteName = "n" + ni + "c" + ci.name; - w.print(linePrefix + "// Note annotation\n"); - w.print(linePrefix + noteName + " [label="); - externalTableStart(UmlGraph.getCommentOptions(), c.qualifiedName(), url); - innerTableStart(); - tableLine(Align.LEFT, Font.CLASS.wrap(UmlGraph.getCommentOptions(), htmlNewline(escape(t.text())))); - innerTableEnd(); - externalTableEnd(); - nodeProperties(UmlGraph.getCommentOptions()); - ClassInfo ci1 = getClassInfo(c, true); - w.print(linePrefix + noteName + " -> " + ci1.name + "[arrowhead=none];\n"); - ni++; - } - ci.nodePrinted = true; - return ci.name; + // If needed, add a note for this node + int ni = 0; + for (Tag t : c.tags("note")) { + String noteName = "n" + ni + "c" + ci.name; + w.print(linePrefix + "// Note annotation\n"); + w.print(linePrefix + noteName + " [label="); + externalTableStart(UmlGraph.getCommentOptions(), c.qualifiedName(), url); + innerTableStart(); + tableLine(Align.LEFT, Font.CLASS.wrap(UmlGraph.getCommentOptions(), htmlNewline(escape(t.text())))); + innerTableEnd(); + externalTableEnd(); + nodeProperties(UmlGraph.getCommentOptions()); + ClassInfo ci1 = getClassInfo(c, true); + w.print(linePrefix + noteName + " -> " + ci1.name + "[arrowhead=none];\n"); + ni++; + } + ci.nodePrinted = true; + return ci.name; } /** * Print all relations for a given's class's tag - * @param tagname the tag containing the given relation - * @param from the source class + * + * @param tagname the tag containing the given relation + * @param from the source class * @param edgetype the dot edge specification */ private void allRelation(Options opt, RelationType rt, ClassDoc from) { - String tagname = rt.lower; - for (Tag tag : from.tags(tagname)) { - String t[] = tokenize(tag.text()); // l-src label l-dst target - t = t.length == 1 ? new String[] { "-", "-", "-", t[0] } : t; // Shorthand - if (t.length != 4) { - System.err.println("Error in " + from + "\n" + tagname + " expects four fields (l-src label l-dst target): " + tag.text()); - return; - } - ClassDoc to = from.findClass(t[3]); - if (to != null) { - if(hidden(to)) - continue; - relation(opt, rt, from, to, t[0], t[1], t[2]); - } else { - if(hidden(t[3])) - continue; - relation(opt, rt, from, from.toString(), to, t[3], t[0], t[1], t[2]); - } - } + String tagname = rt.lower; + for (Tag tag : from.tags(tagname)) { + String t[] = tokenize(tag.text()); // l-src label l-dst target + t = t.length == 1 ? new String[] { "-", "-", "-", t[0] } : t; // Shorthand + if (t.length != 4) { + System.err.println("Error in " + from + "\n" + tagname + + " expects four fields (l-src label l-dst target): " + tag.text()); + return; + } + ClassDoc to = from.findClass(t[3]); + if (to != null) { + if (hidden(to)) + continue; + relation(opt, rt, from, to, t[0], t[1], t[2]); + } else { + if (hidden(t[3])) + continue; + relation(opt, rt, from, from.toString(), to, t[3], t[0], t[1], t[2]); + } + } } /** * Print the specified relation - * @param from the source class (may be null) + * + * @param from the source class (may be null) * @param fromName the source class's name - * @param to the destination class (may be null) - * @param toName the destination class's name + * @param to the destination class (may be null) + * @param toName the destination class's name */ - private void relation(Options opt, RelationType rt, ClassDoc from, String fromName, - ClassDoc to, String toName, String tailLabel, String label, String headLabel) { - tailLabel = (tailLabel != null && !tailLabel.isEmpty()) ? ",taillabel=\"" + tailLabel + "\"" : ""; - label = (label != null && !label.isEmpty()) ? ",label=\"" + guillemize(opt, label) + "\"" : ""; - headLabel = (headLabel != null && !headLabel.isEmpty()) ? ",headlabel=\"" + headLabel + "\"" : ""; - boolean unLabeled = tailLabel.isEmpty() && label.isEmpty() && headLabel.isEmpty(); + private void relation(Options opt, RelationType rt, ClassDoc from, String fromName, ClassDoc to, String toName, + String tailLabel, String label, String headLabel) { + tailLabel = (tailLabel != null && !tailLabel.isEmpty()) ? ",taillabel=\"" + tailLabel + "\"" : ""; + label = (label != null && !label.isEmpty()) ? ",label=\"" + guillemize(opt, label) + "\"" : ""; + headLabel = (headLabel != null && !headLabel.isEmpty()) ? ",headlabel=\"" + headLabel + "\"" : ""; + boolean unLabeled = tailLabel.isEmpty() && label.isEmpty() && headLabel.isEmpty(); - ClassInfo ci1 = getClassInfo(from, fromName, true), ci2 = getClassInfo(to, toName, true); - String n1 = ci1.name, n2 = ci2.name; - // For ranking we need to output extends/implements backwards. - if (rt.backorder) { // Swap: - n1 = ci2.name; - n2 = ci1.name; - String tmp = tailLabel; - tailLabel = headLabel; - headLabel = tmp; - } - Options def = opt.getGlobalOptions(); - // print relation - w.println(linePrefix + "// " + fromName + " " + rt.lower + " " + toName); - w.println(linePrefix + n1 + " -> " + n2 + " [" + rt.style + - (opt.edgeColor != def.edgeColor ? ",color=\"" + opt.edgeColor + "\"" : "") + - (unLabeled ? "" : - (opt.edgeFontName != def.edgeFontName ? ",fontname=\"" + opt.edgeFontName + "\"" : "") + - (opt.edgeFontColor != def.edgeFontColor ? ",fontcolor=\"" + opt.edgeFontColor + "\"" : "") + - (opt.edgeFontSize != def.edgeFontSize ? ",fontsize=" + fmt(opt.edgeFontSize) : "")) + - tailLabel + label + headLabel + - "];"); - - // update relation info - RelationDirection d = RelationDirection.BOTH; - if(rt == RelationType.NAVASSOC || rt == RelationType.DEPEND) - d = RelationDirection.OUT; - ci1.addRelation(toName, rt, d); - ci2.addRelation(fromName, rt, d.inverse()); + ClassInfo ci1 = getClassInfo(from, fromName, true), ci2 = getClassInfo(to, toName, true); + String n1 = ci1.name, n2 = ci2.name; + // For ranking we need to output extends/implements backwards. + if (rt.backorder) { // Swap: + n1 = ci2.name; + n2 = ci1.name; + String tmp = tailLabel; + tailLabel = headLabel; + headLabel = tmp; + } + Options def = opt.getGlobalOptions(); + // print relation + w.println(linePrefix + "// " + fromName + " " + rt.lower + " " + toName); + w.println(linePrefix + n1 + " -> " + n2 + " [" + rt.style + + (opt.edgeColor != def.edgeColor ? ",color=\"" + opt.edgeColor + "\"" : "") + + (unLabeled ? "" + : (opt.edgeFontName != def.edgeFontName ? ",fontname=\"" + opt.edgeFontName + "\"" : "") + + (opt.edgeFontColor != def.edgeFontColor ? ",fontcolor=\"" + opt.edgeFontColor + "\"" + : "") + + (opt.edgeFontSize != def.edgeFontSize ? ",fontsize=" + fmt(opt.edgeFontSize) : "")) + + tailLabel + label + headLabel + "];"); + + // update relation info + RelationDirection d = RelationDirection.BOTH; + if (rt == RelationType.NAVASSOC || rt == RelationType.DEPEND) + d = RelationDirection.OUT; + ci1.addRelation(toName, rt, d); + ci2.addRelation(fromName, rt, d.inverse()); } /** * Print the specified relation + * * @param from the source class - * @param to the destination class + * @param to the destination class */ - private void relation(Options opt, RelationType rt, ClassDoc from, - ClassDoc to, String tailLabel, String label, String headLabel) { - relation(opt, rt, from, from.toString(), to, to.toString(), tailLabel, label, headLabel); + private void relation(Options opt, RelationType rt, ClassDoc from, ClassDoc to, String tailLabel, String label, + String headLabel) { + relation(opt, rt, from, from.toString(), to, to.toString(), tailLabel, label, headLabel); } - /** Print a class's relations */ public void printRelations(ClassDoc c) { - Options opt = optionProvider.getOptionsFor(c); - if (hidden(c) || c.name().equals("")) // avoid phantom classes, they may pop up when the source uses annotations - return; - // Print generalization (through the Java superclass) - Type s = c.superclassType(); - ClassDoc sc = s != null && !s.qualifiedTypeName().equals(Object.class.getName()) ? s.asClassDoc() : null; - if (sc != null && !c.isEnum() && !hidden(sc)) - relation(opt, RelationType.EXTENDS, c, sc, null, null, null); - // Print generalizations (through @extends tags) - for (Tag tag : c.tags("extends")) - if (!hidden(tag.text())) - relation(opt, RelationType.EXTENDS, c, c.findClass(tag.text()), null, null, null); - // Print realizations (Java interfaces) - for (Type iface : c.interfaceTypes()) { - ClassDoc ic = iface.asClassDoc(); - if (!hidden(ic)) - relation(opt, RelationType.IMPLEMENTS, c, ic, null, null, null); - } - // Print other associations - allRelation(opt, RelationType.COMPOSED, c); - allRelation(opt, RelationType.NAVCOMPOSED, c); - allRelation(opt, RelationType.HAS, c); - allRelation(opt, RelationType.NAVHAS, c); - allRelation(opt, RelationType.ASSOC, c); - allRelation(opt, RelationType.NAVASSOC, c); - allRelation(opt, RelationType.DEPEND, c); + Options opt = optionProvider.getOptionsFor(c); + if (hidden(c) || c.name().equals("")) // avoid phantom classes, they may pop up when the source uses annotations + return; + // Print generalization (through the Java superclass) + Type s = c.superclassType(); + ClassDoc sc = s != null && !s.qualifiedTypeName().equals(Object.class.getName()) ? s.asClassDoc() : null; + if (sc != null && !c.isEnum() && !hidden(sc)) + relation(opt, RelationType.EXTENDS, c, sc, null, null, null); + // Print generalizations (through @extends tags) + for (Tag tag : c.tags("extends")) + if (!hidden(tag.text())) + relation(opt, RelationType.EXTENDS, c, c.findClass(tag.text()), null, null, null); + // Print realizations (Java interfaces) + for (Type iface : c.interfaceTypes()) { + ClassDoc ic = iface.asClassDoc(); + if (!hidden(ic)) + relation(opt, RelationType.IMPLEMENTS, c, ic, null, null, null); + } + // Print other associations + allRelation(opt, RelationType.COMPOSED, c); + allRelation(opt, RelationType.NAVCOMPOSED, c); + allRelation(opt, RelationType.HAS, c); + allRelation(opt, RelationType.NAVHAS, c); + allRelation(opt, RelationType.ASSOC, c); + allRelation(opt, RelationType.NAVASSOC, c); + allRelation(opt, RelationType.DEPEND, c); } /** Print classes that were parts of relationships, but not parsed by javadoc */ public void printExtraClasses(RootDoc root) { - Set names = new HashSet(classnames.keySet()); - for(String className: names) { - ClassInfo info = getClassInfo(className, true); - if (info.nodePrinted) - continue; - ClassDoc c = root.classNamed(className); - if(c != null) { - printClass(c, false); - continue; - } - // Handle missing classes: - Options opt = optionProvider.getOptionsFor(className); - if(opt.matchesHideExpression(className)) - continue; - w.println(linePrefix + "// " + className); - w.print(linePrefix + info.name + "[label="); - externalTableStart(opt, className, classToUrl(className)); - innerTableStart(); - String qualifiedName = qualifiedName(opt, className); - int startTemplate = qualifiedName.indexOf('<'); - int idx = qualifiedName.lastIndexOf('.', startTemplate < 0 ? qualifiedName.length() - 1 : startTemplate); - if(opt.postfixPackage && idx > 0 && idx < (qualifiedName.length() - 1)) { - String packageName = qualifiedName.substring(0, idx); - String cn = qualifiedName.substring(idx + 1); - tableLine(Align.CENTER, Font.CLASS.wrap(opt, escape(cn))); - tableLine(Align.CENTER, Font.PACKAGE.wrap(opt, packageName)); - } else { - tableLine(Align.CENTER, Font.CLASS.wrap(opt, escape(qualifiedName))); - } - innerTableEnd(); - externalTableEnd(); - if (className == null || className.length() == 0) - w.print(",URL=\"" + classToUrl(className) + "\""); - nodeProperties(opt); - } - } - - /** - * Prints associations recovered from the fields of a class. An association is inferred only - * if another relation between the two classes is not already in the graph. - * @param classes - */ - public void printInferredRelations(ClassDoc c) { - // check if the source is excluded from inference - if (hidden(c)) - return; - - Options opt = optionProvider.getOptionsFor(c); - - for (FieldDoc field : c.fields(false)) { - if(hidden(field)) - continue; - // skip statics - if(field.isStatic()) - continue; - // skip primitives - FieldRelationInfo fri = getFieldRelationInfo(field); - if (fri == null) - continue; - // check if the destination is excluded from inference - if (hidden(fri.cd)) - continue; - - // if source and dest are not already linked, add a dependency - RelationPattern rp = getClassInfo(c, true).getRelation(fri.cd.toString()); - if (rp == null) { - String destAdornment = fri.multiple ? "*" : ""; - relation(opt, opt.inferRelationshipType, c, fri.cd, "", "", destAdornment); + Set names = new HashSet(classnames.keySet()); + for (String className : names) { + ClassInfo info = getClassInfo(className, true); + if (info.nodePrinted) + continue; + ClassDoc c = root.classNamed(className); + if (c != null) { + printClass(c, false); + continue; } - } + // Handle missing classes: + Options opt = optionProvider.getOptionsFor(className); + if (opt.matchesHideExpression(className)) + continue; + w.println(linePrefix + "// " + className); + w.print(linePrefix + info.name + "[label="); + externalTableStart(opt, className, classToUrl(className)); + innerTableStart(); + String qualifiedName = qualifiedName(opt, className); + int startTemplate = qualifiedName.indexOf('<'); + int idx = qualifiedName.lastIndexOf('.', startTemplate < 0 ? qualifiedName.length() - 1 : startTemplate); + if (opt.postfixPackage && idx > 0 && idx < (qualifiedName.length() - 1)) { + String packageName = qualifiedName.substring(0, idx); + String cn = qualifiedName.substring(idx + 1); + tableLine(Align.CENTER, Font.CLASS.wrap(opt, escape(cn))); + tableLine(Align.CENTER, Font.PACKAGE.wrap(opt, packageName)); + } else { + tableLine(Align.CENTER, Font.CLASS.wrap(opt, escape(qualifiedName))); + } + innerTableEnd(); + externalTableEnd(); + if (className == null || className.length() == 0) + w.print(",URL=\"" + classToUrl(className) + "\""); + nodeProperties(opt); + } } - /** Returns an array representing the imported classes of c. - * Disables the deprecation warning, which is output, because the - * imported classed are an implementation detail. + /** + * Prints associations recovered from the fields of a class. An association is + * inferred only if another relation between the two classes is not already in + * the graph. + * + * @param classes */ - @SuppressWarnings( "deprecation" ) + public void printInferredRelations(ClassDoc c) { + // check if the source is excluded from inference + if (hidden(c)) + return; + + Options opt = optionProvider.getOptionsFor(c); + + for (FieldDoc field : c.fields(false)) { + if (hidden(field)) + continue; + // skip statics + if (field.isStatic()) + continue; + // skip primitives + FieldRelationInfo fri = getFieldRelationInfo(field); + if (fri == null) + continue; + // check if the destination is excluded from inference + if (hidden(fri.cd)) + continue; + + // if source and dest are not already linked, add a dependency + RelationPattern rp = getClassInfo(c, true).getRelation(fri.cd.toString()); + if (rp == null) { + String destAdornment = fri.multiple ? "*" : ""; + relation(opt, opt.inferRelationshipType, c, fri.cd, "", "", destAdornment); + } + } + } + + /** + * Returns an array representing the imported classes of c. Disables the + * deprecation warning, which is output, because the imported classed are an + * implementation detail. + */ + @SuppressWarnings("deprecation") ClassDoc[] importedClasses(ClassDoc c) { return c.importedClasses(); } /** - * Prints dependencies recovered from the methods of a class. A - * dependency is inferred only if another relation between the two - * classes is not already in the graph. + * Prints dependencies recovered from the methods of a class. A dependency is + * inferred only if another relation between the two classes is not already in + * the graph. + * * @param classes - */ + */ public void printInferredDependencies(ClassDoc c) { - if (hidden(c)) - return; + if (hidden(c)) + return; - Options opt = optionProvider.getOptionsFor(c); - Set types = new HashSet(); - // harvest method return and parameter types - for (MethodDoc method : filterByVisibility(c.methods(false), opt.inferDependencyVisibility)) { - types.add(method.returnType()); - for (Parameter parameter : method.parameters()) { - types.add(parameter.type()); - } - } - // and the field types - if (!opt.inferRelationships) { - for (FieldDoc field : filterByVisibility(c.fields(false), opt.inferDependencyVisibility)) { - types.add(field.type()); - } - } - // see if there are some type parameters - if (c.asParameterizedType() != null) { - ParameterizedType pt = c.asParameterizedType(); - types.addAll(Arrays.asList(pt.typeArguments())); - } - // see if type parameters extend something - for(TypeVariable tv: c.typeParameters()) { - if(tv.bounds().length > 0 ) - types.addAll(Arrays.asList(tv.bounds())); - } + Options opt = optionProvider.getOptionsFor(c); + Set types = new HashSet(); + // harvest method return and parameter types + for (MethodDoc method : filterByVisibility(c.methods(false), opt.inferDependencyVisibility)) { + types.add(method.returnType()); + for (Parameter parameter : method.parameters()) { + types.add(parameter.type()); + } + } + // and the field types + if (!opt.inferRelationships) { + for (FieldDoc field : filterByVisibility(c.fields(false), opt.inferDependencyVisibility)) { + types.add(field.type()); + } + } + // see if there are some type parameters + if (c.asParameterizedType() != null) { + ParameterizedType pt = c.asParameterizedType(); + types.addAll(Arrays.asList(pt.typeArguments())); + } + // see if type parameters extend something + for (TypeVariable tv : c.typeParameters()) { + if (tv.bounds().length > 0) + types.addAll(Arrays.asList(tv.bounds())); + } - // and finally check for explicitly imported classes (this - // assumes there are no unused imports...) - if (opt.useImports) - types.addAll(Arrays.asList(importedClasses(c))); + // and finally check for explicitly imported classes (this + // assumes there are no unused imports...) + if (opt.useImports) + types.addAll(Arrays.asList(importedClasses(c))); - // compute dependencies - for (Type type : types) { - // skip primitives and type variables, as well as dependencies - // on the source class - if (type.isPrimitive() || type instanceof WildcardType || type instanceof TypeVariable - || c.toString().equals(type.asClassDoc().toString())) - continue; + // compute dependencies + for (Type type : types) { + // skip primitives and type variables, as well as dependencies + // on the source class + if (type.isPrimitive() || type instanceof WildcardType || type instanceof TypeVariable + || c.toString().equals(type.asClassDoc().toString())) + continue; - // check if the destination is excluded from inference - ClassDoc fc = type.asClassDoc(); - if (hidden(fc)) - continue; - - // check if source and destination are in the same package and if we are allowed - // to infer dependencies between classes in the same package - if(!opt.inferDepInPackage && c.containingPackage().equals(fc.containingPackage())) - continue; + // check if the destination is excluded from inference + ClassDoc fc = type.asClassDoc(); + if (hidden(fc)) + continue; - // if source and dest are not already linked, add a dependency - RelationPattern rp = getClassInfo(c, true).getRelation(fc.toString()); - if (rp == null || rp.matchesOne(new RelationPattern(RelationDirection.OUT))) { - relation(opt, RelationType.DEPEND, c, fc, "", "", ""); - } - - } + // check if source and destination are in the same package and if we are allowed + // to infer dependencies between classes in the same package + if (!opt.inferDepInPackage && c.containingPackage().equals(fc.containingPackage())) + continue; + + // if source and dest are not already linked, add a dependency + RelationPattern rp = getClassInfo(c, true).getRelation(fc.toString()); + if (rp == null || rp.matchesOne(new RelationPattern(RelationDirection.OUT))) { + relation(opt, RelationType.DEPEND, c, fc, "", "", ""); + } + + } } - + /** - * Returns all program element docs that have a visibility greater or - * equal than the specified level + * Returns all program element docs that have a visibility greater or equal than + * the specified level */ private List filterByVisibility(T[] docs, Visibility visibility) { - if (visibility == Visibility.PRIVATE) - return Arrays.asList(docs); + if (visibility == Visibility.PRIVATE) + return Arrays.asList(docs); - List filtered = new ArrayList(); - for (T doc : docs) { - if (Visibility.get(doc).compareTo(visibility) > 0) - filtered.add(doc); - } - return filtered; + List filtered = new ArrayList(); + for (T doc : docs) { + if (Visibility.get(doc).compareTo(visibility) > 0) + filtered.add(doc); + } + return filtered; } - - private FieldRelationInfo getFieldRelationInfo(FieldDoc field) { - Type type = field.type(); - if(type.isPrimitive() || type instanceof WildcardType || type instanceof TypeVariable) - return null; - - if (type.dimension().endsWith("[]")) { - return new FieldRelationInfo(type.asClassDoc(), true); - } - - Options opt = optionProvider.getOptionsFor(type.asClassDoc()); - if (opt.matchesCollPackageExpression(type.qualifiedTypeName())) { - Type[] argTypes = getInterfaceTypeArguments(collectionClassDoc, type); - if (argTypes != null && argTypes.length == 1 && !argTypes[0].isPrimitive()) - return new FieldRelationInfo(argTypes[0].asClassDoc(), true); + Type type = field.type(); + if (type.isPrimitive() || type instanceof WildcardType || type instanceof TypeVariable) + return null; - argTypes = getInterfaceTypeArguments(mapClassDoc, type); - if (argTypes != null && argTypes.length == 2 && !argTypes[1].isPrimitive()) - return new FieldRelationInfo(argTypes[1].asClassDoc(), true); - } + if (type.dimension().endsWith("[]")) { + return new FieldRelationInfo(type.asClassDoc(), true); + } - return new FieldRelationInfo(type.asClassDoc(), false); + Options opt = optionProvider.getOptionsFor(type.asClassDoc()); + if (opt.matchesCollPackageExpression(type.qualifiedTypeName())) { + Type[] argTypes = getInterfaceTypeArguments(collectionClassDoc, type); + if (argTypes != null && argTypes.length == 1 && !argTypes[0].isPrimitive()) + return new FieldRelationInfo(argTypes[0].asClassDoc(), true); + + argTypes = getInterfaceTypeArguments(mapClassDoc, type); + if (argTypes != null && argTypes.length == 2 && !argTypes[1].isPrimitive()) + return new FieldRelationInfo(argTypes[1].asClassDoc(), true); + } + + return new FieldRelationInfo(type.asClassDoc(), false); } - + private Type[] getInterfaceTypeArguments(ClassDoc iface, Type t) { - if (t instanceof ParameterizedType) { - ParameterizedType pt = (ParameterizedType) t; - if (iface != null && iface.equals(t.asClassDoc())) { - return pt.typeArguments(); - } else { - for (Type pti : pt.interfaceTypes()) { - Type[] result = getInterfaceTypeArguments(iface, pti); - if (result != null) - return result; - } - if (pt.superclassType() != null) - return getInterfaceTypeArguments(iface, pt.superclassType()); - } - } else if (t instanceof ClassDoc) { - ClassDoc cd = (ClassDoc) t; - for (Type pti : cd.interfaceTypes()) { - Type[] result = getInterfaceTypeArguments(iface, pti); - if (result != null) - return result; - } - if (cd.superclassType() != null) - return getInterfaceTypeArguments(iface, cd.superclassType()); - } - return null; + if (t instanceof ParameterizedType) { + ParameterizedType pt = (ParameterizedType) t; + if (iface != null && iface.equals(t.asClassDoc())) { + return pt.typeArguments(); + } else { + for (Type pti : pt.interfaceTypes()) { + Type[] result = getInterfaceTypeArguments(iface, pti); + if (result != null) + return result; + } + if (pt.superclassType() != null) + return getInterfaceTypeArguments(iface, pt.superclassType()); + } + } else if (t instanceof ClassDoc) { + ClassDoc cd = (ClassDoc) t; + for (Type pti : cd.interfaceTypes()) { + Type[] result = getInterfaceTypeArguments(iface, pti); + if (result != null) + return result; + } + if (cd.superclassType() != null) + return getInterfaceTypeArguments(iface, cd.superclassType()); + } + return null; } /** Convert the class name into a corresponding URL */ public String classToUrl(ClassDoc cd, boolean rootClass) { - // building relative path for context and package diagrams - if(contextPackageName != null && rootClass) - return buildRelativePathFromClassNames(contextPackageName, cd.containingPackage().name()) + cd.name() + ".html"; - return classToUrl(cd.qualifiedName()); + // building relative path for context and package diagrams + if (contextPackageName != null && rootClass) + return buildRelativePathFromClassNames(contextPackageName, cd.containingPackage().name()) + cd.name() + + ".html"; + return classToUrl(cd.qualifiedName()); } /** Convert the class name into a corresponding URL */ public String classToUrl(String className) { - ClassDoc classDoc = rootClassdocs.get(className); - if (classDoc != null) { - String docRoot = optionProvider.getGlobalOptions().apiDocRoot; - if (docRoot == null) - return null; - return new StringBuilder(docRoot.length() + className.length() + 10).append(docRoot) // - .append(classDoc.containingPackage().name().replace('.', '/')) // - .append('/').append(classDoc.name()).append(".html").toString(); - } - String docRoot = optionProvider.getGlobalOptions().getApiDocRoot(className); - if (docRoot == null) - return null; - int split = splitPackageClass(className); - StringBuilder buf = new StringBuilder(docRoot.length() + className.length() + 10).append(docRoot); - if (split > 0) // Avoid -1, and the extra slash then. - buf.append(className.substring(0, split).replace('.', '/')).append('/'); - return buf.append(className, Math.min(split + 1, className.length()), className.length()) // - .append(".html").toString(); + ClassDoc classDoc = rootClassdocs.get(className); + if (classDoc != null) { + String docRoot = optionProvider.getGlobalOptions().apiDocRoot; + if (docRoot == null) + return null; + return new StringBuilder(docRoot.length() + className.length() + 10).append(docRoot) // + .append(classDoc.containingPackage().name().replace('.', '/')) // + .append('/').append(classDoc.name()).append(".html").toString(); + } + String docRoot = optionProvider.getGlobalOptions().getApiDocRoot(className); + if (docRoot == null) + return null; + int split = splitPackageClass(className); + StringBuilder buf = new StringBuilder(docRoot.length() + className.length() + 10).append(docRoot); + if (split > 0) // Avoid -1, and the extra slash then. + buf.append(className.substring(0, split).replace('.', '/')).append('/'); + return buf.append(className, Math.min(split + 1, className.length()), className.length()) // + .append(".html").toString(); } - /** Dot prologue - * @throws IOException */ + /** + * Dot prologue + * + * @throws IOException + */ public void prologue() throws IOException { - Options opt = optionProvider.getGlobalOptions(); - OutputStream os; + Options opt = optionProvider.getGlobalOptions(); + OutputStream os; - if (opt.outputFileName.equals("-")) - os = System.out; - else { - // prepare output file. Use the output file name as a full path unless the output - // directory is specified - File file = new File(opt.outputDirectory, opt.outputFileName); - // make sure the output directory are there, otherwise create them - if (file.getParentFile() != null - && !file.getParentFile().exists()) - file.getParentFile().mkdirs(); - os = new FileOutputStream(file); - } + if (opt.outputFileName.equals("-")) + os = System.out; + else { + // prepare output file. Use the output file name as a full path unless the + // output + // directory is specified + File file = new File(opt.outputDirectory, opt.outputFileName); + // make sure the output directory are there, otherwise create them + if (file.getParentFile() != null && !file.getParentFile().exists()) + file.getParentFile().mkdirs(); + os = new FileOutputStream(file); + } - // print prologue - w = new PrintWriter(new OutputStreamWriter(new BufferedOutputStream(os), opt.outputEncoding)); - w.println( - "#!/usr/local/bin/dot\n" + - "#\n" + - "# Class diagram \n" + - "# Generated by UMLGraph version " + - Version.VERSION + " (http://www.spinellis.gr/umlgraph/)\n" + - "#\n\n" + - "digraph G {\n" + - linePrefix + "graph [fontnames=\"svg\"]\n" + - linePrefix + "edge [fontname=\"" + opt.edgeFontName + - "\",fontsize=" + fmt(opt.edgeFontSize) + - ",labelfontname=\"" + opt.edgeFontName + - "\",labelfontsize=" + fmt(opt.edgeFontSize) + - ",color=\"" + opt.edgeColor + "\"];\n" + - linePrefix + "node [fontname=\"" + opt.nodeFontName + - "\",fontcolor=\"" + opt.nodeFontColor + - "\",fontsize=" + fmt(opt.nodeFontSize) + - ",shape=plaintext,margin=0,width=0,height=0];" - ); + // print prologue + w = new PrintWriter(new OutputStreamWriter(new BufferedOutputStream(os), opt.outputEncoding)); + w.println("#!/usr/local/bin/dot\n" + "#\n" + "# Class diagram \n" + "# Generated by UMLGraph version " + + Version.VERSION + " (http://www.spinellis.gr/umlgraph/)\n" + "#\n\n" + "digraph G {\n" + linePrefix + + "graph [fontnames=\"svg\"]\n" + linePrefix + "edge [fontname=\"" + opt.edgeFontName + "\",fontsize=" + + fmt(opt.edgeFontSize) + ",labelfontname=\"" + opt.edgeFontName + "\",labelfontsize=" + + fmt(opt.edgeFontSize) + ",color=\"" + opt.edgeColor + "\"];\n" + linePrefix + "node [fontname=\"" + + opt.nodeFontName + "\",fontcolor=\"" + opt.nodeFontColor + "\",fontsize=" + fmt(opt.nodeFontSize) + + ",shape=plaintext,margin=0,width=0,height=0];"); - w.println(linePrefix + "nodesep=" + opt.nodeSep + ";"); - w.println(linePrefix + "ranksep=" + opt.rankSep + ";"); - if (opt.horizontal) - w.println(linePrefix + "rankdir=LR;"); - if (opt.bgColor != null) - w.println(linePrefix + "bgcolor=\"" + opt.bgColor + "\";\n"); + w.println(linePrefix + "nodesep=" + opt.nodeSep + ";"); + w.println(linePrefix + "ranksep=" + opt.rankSep + ";"); + if (opt.horizontal) + w.println(linePrefix + "rankdir=LR;"); + if (opt.bgColor != null) + w.println(linePrefix + "bgcolor=\"" + opt.bgColor + "\";\n"); } /** Dot epilogue */ public void epilogue() { - w.println("}\n"); - w.flush(); - w.close(); + w.println("}\n"); + w.flush(); + w.close(); } - + private void externalTableStart(Options opt, String name, String url) { - String bgcolor = opt.nodeFillColor == null ? "" : (" bgcolor=\"" + opt.nodeFillColor + "\""); - String href = url == null ? "" : (" href=\"" + url + "\" target=\"_parent\""); - w.print("<" + linePostfix); + String bgcolor = opt.nodeFillColor == null ? "" : (" bgcolor=\"" + opt.nodeFillColor + "\""); + String href = url == null ? "" : (" href=\"" + url + "\" target=\"_parent\""); + w.print("<
" + linePostfix); } - + private void externalTableEnd() { - w.print(linePrefix + linePrefix + "
>"); + w.print(linePrefix + linePrefix + ">"); } - + private void innerTableStart() { - w.print(linePrefix + linePrefix + "" + linePostfix); + w.print(linePrefix + linePrefix + "" + - opt.shape.extraColumn() + "" + linePostfix); + w.print(linePrefix + linePrefix + "
" + + linePostfix); } - + /** * Start the first inner table of a class. */ private void firstInnerTableStart(Options opt) { - w.print(linePrefix + linePrefix + "" + opt.shape.extraColumn() + - "" + linePostfix); } /** * End the first inner table of a class. */ private void firstInnerTableEnd(Options opt) { - w.print(linePrefix + linePrefix + "
" + linePostfix); + w.print(linePrefix + linePrefix + "" + opt.shape.extraColumn() + + "" + linePostfix); + w.print(linePrefix + linePrefix + "
" + linePostfix); } - + private void innerTableEnd() { - w.print(linePrefix + linePrefix + "
" + opt.shape.extraColumn() + "" + linePostfix); } private void tableLine(Align align, String text) { - w.print(linePrefix + linePrefix // - + " " // - + text // MAY contain markup! - + " " + linePostfix); + w.print(linePrefix + linePrefix // + + " " // + + text // MAY contain markup! + + " " + linePostfix); } private static class FieldRelationInfo { - ClassDoc cd; - boolean multiple; + ClassDoc cd; + boolean multiple; - public FieldRelationInfo(ClassDoc cd, boolean multiple) { - this.cd = cd; - this.multiple = multiple; - } + public FieldRelationInfo(ClassDoc cd, boolean multiple) { + this.cd = cd; + this.multiple = multiple; + } } } diff --git a/src/main/java/org/umlgraph/doclet/ClassInfo.java b/src/main/java/org/umlgraph/doclet/ClassInfo.java index f498210..ccb67e0 100644 --- a/src/main/java/org/umlgraph/doclet/ClassInfo.java +++ b/src/main/java/org/umlgraph/doclet/ClassInfo.java @@ -23,8 +23,9 @@ import java.util.HashMap; import java.util.Map; /** - * Class's dot-compatible alias name (for fully qualified class names) - * and printed information + * Class's dot-compatible alias name (for fully qualified class names) and + * printed information + * * @version $Revision$ * @author Diomidis Spinellis */ @@ -36,37 +37,35 @@ class ClassInfo { boolean nodePrinted; /** True if the class class node is hidden */ boolean hidden; - /** - * The list of classes that share a relation with this one. Contains - * all the classes linked with a bi-directional relation , and the ones - * referred by a directed relation + /** + * The list of classes that share a relation with this one. Contains all the + * classes linked with a bi-directional relation , and the ones referred by a + * directed relation */ Map relatedClasses = new HashMap(); ClassInfo(boolean h) { - hidden = h; - name = "c" + classNumber; - classNumber++; + hidden = h; + name = "c" + classNumber; + classNumber++; } - + public void addRelation(String dest, RelationType rt, RelationDirection d) { - RelationPattern ri = relatedClasses.get(dest); - if(ri == null) { - ri = new RelationPattern(RelationDirection.NONE); - relatedClasses.put(dest, ri); - } - ri.addRelation(rt, d); + RelationPattern ri = relatedClasses.get(dest); + if (ri == null) { + ri = new RelationPattern(RelationDirection.NONE); + relatedClasses.put(dest, ri); + } + ri.addRelation(rt, d); } - + public RelationPattern getRelation(String dest) { - return relatedClasses.get(dest); + return relatedClasses.get(dest); } /** Start numbering from zero. */ public static void reset() { - classNumber = 0; + classNumber = 0; } - } - diff --git a/src/main/java/org/umlgraph/doclet/ClassMatcher.java b/src/main/java/org/umlgraph/doclet/ClassMatcher.java index 9665376..d89df36 100644 --- a/src/main/java/org/umlgraph/doclet/ClassMatcher.java +++ b/src/main/java/org/umlgraph/doclet/ClassMatcher.java @@ -20,19 +20,19 @@ package org.umlgraph.doclet; import com.sun.javadoc.ClassDoc; /** - * A ClassMatcher is used to check if a class definition matches a - * specific condition. The nature of the condition is dependent on - * the kind of matcher + * A ClassMatcher is used to check if a class definition matches a specific + * condition. The nature of the condition is dependent on the kind of matcher + * * @author wolf */ public interface ClassMatcher { /** - * Returns the options for the specified class. + * Returns the options for the specified class. */ public boolean matches(ClassDoc cd); - + /** - * Returns the options for the specified class. + * Returns the options for the specified class. */ public boolean matches(String name); } diff --git a/src/main/java/org/umlgraph/doclet/ContextMatcher.java b/src/main/java/org/umlgraph/doclet/ContextMatcher.java index cc59d00..626fab0 100644 --- a/src/main/java/org/umlgraph/doclet/ContextMatcher.java +++ b/src/main/java/org/umlgraph/doclet/ContextMatcher.java @@ -38,6 +38,7 @@ import com.sun.javadoc.RootDoc; * This class needs to perform quite a bit of computations in order to gather * the network of class releationships, so you are allowed to reuse it should * you + * * @author wolf * * @depend - - - DevNullWriter @@ -54,25 +55,26 @@ public class ContextMatcher implements ClassMatcher { /** * Builds the context matcher - * @param root The root doc returned by JavaDoc - * @param pattern The pattern that will match the "center" of this - * context - * @param keepParentHide If true, parent option hide patterns will be - * preserved, so that classes hidden by the options won't - * be shown in the context + * + * @param root The root doc returned by JavaDoc + * @param pattern The pattern that will match the "center" of this + * context + * @param keepParentHide If true, parent option hide patterns will be preserved, + * so that classes hidden by the options won't be shown in + * the context * @throws IOException */ public ContextMatcher(RootDoc root, Pattern pattern, Options options, boolean keepParentHide) throws IOException { - this.pattern = pattern; - this.root = root; - this.keepParentHide = keepParentHide; - opt = (Options) options.clone(); - opt.setOption(new String[] { "!hide" }); - opt.setOption(new String[] { "!attributes" }); - opt.setOption(new String[] { "!operations" }); - this.cg = new ClassGraphHack(root, opt); + this.pattern = pattern; + this.root = root; + this.keepParentHide = keepParentHide; + opt = (Options) options.clone(); + opt.setOption(new String[] { "!hide" }); + opt.setOption(new String[] { "!attributes" }); + opt.setOption(new String[] { "!operations" }); + this.cg = new ClassGraphHack(root, opt); - setContextCenter(pattern); + setContextCenter(pattern); } /** @@ -80,116 +82,119 @@ public class ContextMatcher implements ClassMatcher { *

* This can be used to speed up subsequent matching with the same global * options, since the class network informations will be reused. + * * @param pattern */ public void setContextCenter(Pattern pattern) { - // build up the classgraph printing the relations for all of the - // classes that make up the "center" of this context - this.pattern = pattern; - matched = new ArrayList(); - for (ClassDoc cd : root.classes()) { - if (pattern.matcher(cd.toString()).matches()) { - matched.add(cd); - addToGraph(cd); - } - } + // build up the classgraph printing the relations for all of the + // classes that make up the "center" of this context + this.pattern = pattern; + matched = new ArrayList(); + for (ClassDoc cd : root.classes()) { + if (pattern.matcher(cd.toString()).matches()) { + matched.add(cd); + addToGraph(cd); + } + } } /** - * Adds the specified class to the internal class graph along with its - * relations and dependencies, eventually inferring them, according to the - * Options specified for this matcher + * Adds the specified class to the internal class graph along with its relations + * and dependencies, eventually inferring them, according to the Options + * specified for this matcher + * * @param cd */ private void addToGraph(ClassDoc cd) { - // avoid adding twice the same class, but don't rely on cg.getClassInfo - // since there are other ways to add a classInfor than printing the class - if (visited.contains(cd.toString())) - return; + // avoid adding twice the same class, but don't rely on cg.getClassInfo + // since there are other ways to add a classInfor than printing the class + if (visited.contains(cd.toString())) + return; - visited.add(cd.toString()); - cg.printClass(cd, false); - cg.printRelations(cd); - if (opt.inferRelationships) - cg.printInferredRelations(cd); - if (opt.inferDependencies) - cg.printInferredDependencies(cd); + visited.add(cd.toString()); + cg.printClass(cd, false); + cg.printRelations(cd); + if (opt.inferRelationships) + cg.printInferredRelations(cd); + if (opt.inferDependencies) + cg.printInferredDependencies(cd); } /** * @see org.umlgraph.doclet.ClassMatcher#matches(com.sun.javadoc.ClassDoc) */ public boolean matches(ClassDoc cd) { - if (keepParentHide && opt.matchesHideExpression(cd.toString())) - return false; + if (keepParentHide && opt.matchesHideExpression(cd.toString())) + return false; - // if the class is matched, it's in by default. - if (matched.contains(cd)) - return true; + // if the class is matched, it's in by default. + if (matched.contains(cd)) + return true; - // otherwise, add the class to the graph and see if it's associated - // with any of the matched classes using the classgraph hack - addToGraph(cd); - return matches(cd.toString()); + // otherwise, add the class to the graph and see if it's associated + // with any of the matched classes using the classgraph hack + addToGraph(cd); + return matches(cd.toString()); } /** * @see org.umlgraph.doclet.ClassMatcher#matches(java.lang.String) */ public boolean matches(String name) { - if (pattern.matcher(name).matches()) - return true; + if (pattern.matcher(name).matches()) + return true; - for (ClassDoc mcd : matched) { - RelationPattern rp = cg.getClassInfo(mcd, true).getRelation(name); - if (rp != null && opt.contextRelationPattern.matchesOne(rp)) - return true; - } - return false; + for (ClassDoc mcd : matched) { + RelationPattern rp = cg.getClassInfo(mcd, true).getRelation(name); + if (rp != null && opt.contextRelationPattern.matchesOne(rp)) + return true; + } + return false; } /** - * A quick hack to compute class dependencies reusing ClassGraph but - * without generating output. Will be removed once the ClassGraph class - * will be split into two classes for graph computation and output - * generation. + * A quick hack to compute class dependencies reusing ClassGraph but without + * generating output. Will be removed once the ClassGraph class will be split + * into two classes for graph computation and output generation. + * * @author wolf * */ private static class ClassGraphHack extends ClassGraph { - public ClassGraphHack(RootDoc root, OptionProvider optionProvider) throws IOException { - super(root, optionProvider, null); - prologue(); - } + public ClassGraphHack(RootDoc root, OptionProvider optionProvider) throws IOException { + super(root, optionProvider, null); + prologue(); + } - @Override - public void prologue() throws IOException { - w = new PrintWriter(new DevNullWriter()); - } + @Override + public void prologue() throws IOException { + w = new PrintWriter(new DevNullWriter()); + } } /** * Simple dev/null imitation + * * @author wolf */ private static class DevNullWriter extends Writer { - @Override - public void write(char[] cbuf, int off, int len) throws IOException { - // nothing to do - } + @Override + public void write(char[] cbuf, int off, int len) throws IOException { + // nothing to do + } - @Override - public void flush() throws IOException { - // nothing to do - } + @Override + public void flush() throws IOException { + // nothing to do + } - @Override - public void close() throws IOException { - // nothing to do - } + @Override + public void close() throws IOException { + // nothing to do + } } diff --git a/src/main/java/org/umlgraph/doclet/ContextView.java b/src/main/java/org/umlgraph/doclet/ContextView.java index 040725e..48e9737 100755 --- a/src/main/java/org/umlgraph/doclet/ContextView.java +++ b/src/main/java/org/umlgraph/doclet/ContextView.java @@ -14,6 +14,7 @@ import com.sun.javadoc.RootDoc; * single {@linkplain ContextMatcher}, but provides some extra configuration * such as context highlighting and output path configuration (and it is * specified in code rather than in javadoc comments). + * * @author wolf * */ @@ -28,93 +29,89 @@ public class ContextView implements OptionProvider { private Options packageOptions; private static final String[] HIDE_OPTIONS = new String[] { "hide" }; - public ContextView(String outputFolder, ClassDoc cd, RootDoc root, Options parent) - throws IOException { - this.cd = cd; - String outputPath = cd.containingPackage().name().replace('.', '/') + "/" + cd.name() - + ".dot"; + public ContextView(String outputFolder, ClassDoc cd, RootDoc root, Options parent) throws IOException { + this.cd = cd; + String outputPath = cd.containingPackage().name().replace('.', '/') + "/" + cd.name() + ".dot"; - // setup options statically, so that we won't need to change them so - // often - this.globalOptions = parent.getGlobalOptions(); - - this.packageOptions = parent.getGlobalOptions(); - this.packageOptions.showQualified = false; + // setup options statically, so that we won't need to change them so + // often + this.globalOptions = parent.getGlobalOptions(); - this.myGlobalOptions = parent.getGlobalOptions(); - this.myGlobalOptions.setOption(new String[] { "output", outputPath }); - this.myGlobalOptions.setOption(HIDE_OPTIONS); + this.packageOptions = parent.getGlobalOptions(); + this.packageOptions.showQualified = false; - this.hideOptions = parent.getGlobalOptions(); - this.hideOptions.setOption(HIDE_OPTIONS); + this.myGlobalOptions = parent.getGlobalOptions(); + this.myGlobalOptions.setOption(new String[] { "output", outputPath }); + this.myGlobalOptions.setOption(HIDE_OPTIONS); - this.centerOptions = parent.getGlobalOptions(); - this.centerOptions.nodeFillColor = "lemonChiffon"; - this.centerOptions.showQualified = false; + this.hideOptions = parent.getGlobalOptions(); + this.hideOptions.setOption(HIDE_OPTIONS); - this.matcher = new ContextMatcher(root, Pattern.compile(Pattern.quote(cd.toString())), - myGlobalOptions, true); + this.centerOptions = parent.getGlobalOptions(); + this.centerOptions.nodeFillColor = "lemonChiffon"; + this.centerOptions.showQualified = false; + + this.matcher = new ContextMatcher(root, Pattern.compile(Pattern.quote(cd.toString())), myGlobalOptions, true); } public void setContextCenter(ClassDoc contextCenter) { - this.cd = contextCenter; - String outputPath = cd.containingPackage().name().replace('.', '/') + "/" + cd.name() - + ".dot"; - this.myGlobalOptions.setOption(new String[] { "output", outputPath }); - matcher.setContextCenter(Pattern.compile(Pattern.quote(cd.toString()))); + this.cd = contextCenter; + String outputPath = cd.containingPackage().name().replace('.', '/') + "/" + cd.name() + ".dot"; + this.myGlobalOptions.setOption(new String[] { "output", outputPath }); + matcher.setContextCenter(Pattern.compile(Pattern.quote(cd.toString()))); } public String getDisplayName() { - return "Context view for class " + cd; + return "Context view for class " + cd; } public Options getGlobalOptions() { - return myGlobalOptions; + return myGlobalOptions; } public Options getOptionsFor(ClassDoc cd) { - Options opt; - if (globalOptions.matchesHideExpression(cd.qualifiedName()) - || !(matcher.matches(cd) || globalOptions.matchesIncludeExpression(cd.qualifiedName()))) { - opt = hideOptions; - } else if (cd.equals(this.cd)) { - opt = centerOptions; - } else if(cd.containingPackage().equals(this.cd.containingPackage())){ - opt = packageOptions; - } else { - opt = globalOptions; - } - Options optionClone = (Options) opt.clone(); - overrideForClass(optionClone, cd); - return optionClone; + Options opt; + if (globalOptions.matchesHideExpression(cd.qualifiedName()) + || !(matcher.matches(cd) || globalOptions.matchesIncludeExpression(cd.qualifiedName()))) { + opt = hideOptions; + } else if (cd.equals(this.cd)) { + opt = centerOptions; + } else if (cd.containingPackage().equals(this.cd.containingPackage())) { + opt = packageOptions; + } else { + opt = globalOptions; + } + Options optionClone = (Options) opt.clone(); + overrideForClass(optionClone, cd); + return optionClone; } public Options getOptionsFor(String name) { - Options opt; - if (!matcher.matches(name)) - opt = hideOptions; - else if (name.equals(cd.name())) - opt = centerOptions; - else - opt = globalOptions; - Options optionClone = (Options) opt.clone(); - overrideForClass(optionClone, name); - return optionClone; + Options opt; + if (!matcher.matches(name)) + opt = hideOptions; + else if (name.equals(cd.name())) + opt = centerOptions; + else + opt = globalOptions; + Options optionClone = (Options) opt.clone(); + overrideForClass(optionClone, name); + return optionClone; } public void overrideForClass(Options opt, ClassDoc cd) { - opt.setOptions(cd); - if (opt.matchesHideExpression(cd.qualifiedName()) - || !(matcher.matches(cd) || opt.matchesIncludeExpression(cd.qualifiedName()))) - opt.setOption(HIDE_OPTIONS); - if (cd.equals(this.cd)) - opt.nodeFillColor = "lemonChiffon"; + opt.setOptions(cd); + if (opt.matchesHideExpression(cd.qualifiedName()) + || !(matcher.matches(cd) || opt.matchesIncludeExpression(cd.qualifiedName()))) + opt.setOption(HIDE_OPTIONS); + if (cd.equals(this.cd)) + opt.nodeFillColor = "lemonChiffon"; } public void overrideForClass(Options opt, String className) { - if (!(matcher.matches(className) || opt.matchesIncludeExpression(className))) - opt.setOption(HIDE_OPTIONS); + if (!(matcher.matches(className) || opt.matchesIncludeExpression(className))) + opt.setOption(HIDE_OPTIONS); } } diff --git a/src/main/java/org/umlgraph/doclet/Font.java b/src/main/java/org/umlgraph/doclet/Font.java index 09355ea..f9bcc0d 100644 --- a/src/main/java/org/umlgraph/doclet/Font.java +++ b/src/main/java/org/umlgraph/doclet/Font.java @@ -33,12 +33,12 @@ public enum Font { // Static initialization of further values. static { - // use an appropriate font depending on the current operating system - if (System.getProperty("os.name").toLowerCase().contains("windows")) { - DEFAULT_FONT = "Arial"; - } else { - DEFAULT_FONT = "Helvetica"; // TODO: can we use just "sans"? - } + // use an appropriate font depending on the current operating system + if (System.getProperty("os.name").toLowerCase().contains("windows")) { + DEFAULT_FONT = "Arial"; + } else { + DEFAULT_FONT = "Helvetica"; // TODO: can we use just "sans"? + } } /** @@ -49,53 +49,53 @@ public enum Font { * @return Wrapped text */ public String wrap(Options opt, String text) { - if (text.isEmpty() || this == NORMAL) - return text; - String face = null; - double size = -1; - boolean italic = false; - switch (this) { - case EDGE: - case NODE: - // Not used with the wrap function. - throw new UnsupportedOperationException(); - case ABSTRACT: - italic = opt.nodeFontAbstractItalic; - case NORMAL: - break; - case CLASS_ABSTRACT: - italic = opt.nodeFontAbstractItalic; - case CLASS: - face = opt.nodeFontClassName; - size = opt.nodeFontClassSize; - break; - case PACKAGE: - face = opt.nodeFontPackageName; - size = opt.nodeFontPackageSize; - break; - case TAG: - face = opt.nodeFontTagName; - size = opt.nodeFontTagSize; - break; - } - if (face == null && size < 0 && !italic) - return text; - StringBuilder buf = new StringBuilder(text.length() + 100); - if (face != null || size > 0) { - buf.append(" 0) - buf.append(" point-size=\"").append(size).append('"'); - buf.append('>'); - } - if (italic) - buf.append(""); - buf.append(text); - if (italic) - buf.append(""); - if (face != null || size > 0) - buf.append(""); - return buf.toString(); + if (text.isEmpty() || this == NORMAL) + return text; + String face = null; + double size = -1; + boolean italic = false; + switch (this) { + case EDGE: + case NODE: + // Not used with the wrap function. + throw new UnsupportedOperationException(); + case ABSTRACT: + italic = opt.nodeFontAbstractItalic; + case NORMAL: + break; + case CLASS_ABSTRACT: + italic = opt.nodeFontAbstractItalic; + case CLASS: + face = opt.nodeFontClassName; + size = opt.nodeFontClassSize; + break; + case PACKAGE: + face = opt.nodeFontPackageName; + size = opt.nodeFontPackageSize; + break; + case TAG: + face = opt.nodeFontTagName; + size = opt.nodeFontTagSize; + break; + } + if (face == null && size < 0 && !italic) + return text; + StringBuilder buf = new StringBuilder(text.length() + 100); + if (face != null || size > 0) { + buf.append(" 0) + buf.append(" point-size=\"").append(size).append('"'); + buf.append('>'); + } + if (italic) + buf.append(""); + buf.append(text); + if (italic) + buf.append(""); + if (face != null || size > 0) + buf.append(""); + return buf.toString(); } } diff --git a/src/main/java/org/umlgraph/doclet/InterfaceMatcher.java b/src/main/java/org/umlgraph/doclet/InterfaceMatcher.java index 6c63b98..e39518d 100644 --- a/src/main/java/org/umlgraph/doclet/InterfaceMatcher.java +++ b/src/main/java/org/umlgraph/doclet/InterfaceMatcher.java @@ -6,8 +6,8 @@ import com.sun.javadoc.ClassDoc; import com.sun.javadoc.RootDoc; /** - * Matches every class that implements (directly or indirectly) an - * interfaces matched by regular expression provided. + * Matches every class that implements (directly or indirectly) an interfaces + * matched by regular expression provided. */ public class InterfaceMatcher implements ClassMatcher { @@ -15,28 +15,28 @@ public class InterfaceMatcher implements ClassMatcher { protected Pattern pattern; public InterfaceMatcher(RootDoc root, Pattern pattern) { - this.root = root; - this.pattern = pattern; + this.root = root; + this.pattern = pattern; } public boolean matches(ClassDoc cd) { - // if it's the interface we're looking for, match - if(cd.isInterface() && pattern.matcher(cd.toString()).matches()) - return true; - - // for each interface, recurse, since classes and interfaces - // are treated the same in the doclet API - for (ClassDoc iface : cd.interfaces()) - if(matches(iface)) - return true; - - // recurse on supeclass, if available - return cd.superclass() == null ? false : matches(cd.superclass()); + // if it's the interface we're looking for, match + if (cd.isInterface() && pattern.matcher(cd.toString()).matches()) + return true; + + // for each interface, recurse, since classes and interfaces + // are treated the same in the doclet API + for (ClassDoc iface : cd.interfaces()) + if (matches(iface)) + return true; + + // recurse on supeclass, if available + return cd.superclass() == null ? false : matches(cd.superclass()); } public boolean matches(String name) { - ClassDoc cd = root.classNamed(name); - return cd == null ? false : matches(cd); + ClassDoc cd = root.classNamed(name); + return cd == null ? false : matches(cd); } } diff --git a/src/main/java/org/umlgraph/doclet/OptionProvider.java b/src/main/java/org/umlgraph/doclet/OptionProvider.java index 8287780..151d2b7 100644 --- a/src/main/java/org/umlgraph/doclet/OptionProvider.java +++ b/src/main/java/org/umlgraph/doclet/OptionProvider.java @@ -20,8 +20,8 @@ package org.umlgraph.doclet; import com.sun.javadoc.ClassDoc; /** - * A factory class that builds Options object for general use or for a - * specific class + * A factory class that builds Options object for general use or for a specific + * class */ public interface OptionProvider { /** @@ -51,7 +51,8 @@ public interface OptionProvider { /** * Returns user displayable name for this option provider. - *

Will be used to provide progress feedback on the console + *

+ * Will be used to provide progress feedback on the console */ public String getDisplayName(); } diff --git a/src/main/java/org/umlgraph/doclet/Options.java b/src/main/java/org/umlgraph/doclet/Options.java index 90b7542..7018da8 100644 --- a/src/main/java/org/umlgraph/doclet/Options.java +++ b/src/main/java/org/umlgraph/doclet/Options.java @@ -44,6 +44,7 @@ import com.sun.javadoc.Tag; /** * Represent the program options + * * @version $Revision$ * @author Diomidis Spinellis */ @@ -51,7 +52,7 @@ public class Options implements Cloneable, OptionProvider { // reused often, especially in UmlGraphDoc, worth creating just once and reusing private static final Pattern allPattern = Pattern.compile(".*"); protected static final String DEFAULT_EXTERNAL_APIDOC = "http://docs.oracle.com/javase/7/docs/api/"; - + // instance fields List hidePatterns = new ArrayList(); List includePatterns = new ArrayList(); @@ -97,14 +98,13 @@ public class Options implements Cloneable, OptionProvider { double rankSep = 0.5; public String outputDirectory = null; /* - * Numeric values are preferable to symbolic here. - * Symbolic reportedly fail on MacOSX, and also are - * more difficult to verify with XML tools. + * Numeric values are preferable to symbolic here. Symbolic reportedly fail on + * MacOSX, and also are more difficult to verify with XML tools. */ /** Guillemot left (open) */ - String guilOpen = "«"; // « \u00ab + String guilOpen = "«"; // « \u00ab /** Guillemot right (close) */ - String guilClose = "»"; // » \u00bb + String guilClose = "»"; // » \u00bb boolean inferRelationships = false; boolean inferDependencies = false; boolean collapsibleDiagrams = false; @@ -119,8 +119,10 @@ public class Options implements Cloneable, OptionProvider { // internal option, used by UMLDoc to generate relative links between classes boolean relativeLinksForSourcePackages = false; // internal option, used by UMLDoc to force strict matching on the class names - // and avoid problems with packages in the template declaration making UmlGraph hide - // classes outside of them (for example, class gr.spinellis.Foo + // and avoid problems with packages in the template declaration making UmlGraph + // hide + // classes outside of them (for example, class gr.spinellis.Foo // would have been hidden by the hide pattern "java.*" // TODO: consider making this standard behaviour boolean strictMatching = false; @@ -130,555 +132,534 @@ public class Options implements Cloneable, OptionProvider { } @Override - public Object clone() { - Options clone = null; - try { - clone = (Options) super.clone(); - } catch (CloneNotSupportedException e) { - throw new RuntimeException("Cannot clone?!?", e); // Should not happen - } - // deep clone the hide and collection patterns - clone.hidePatterns = new ArrayList(hidePatterns); - clone.includePatterns = new ArrayList(includePatterns); - clone.collPackages= new ArrayList(collPackages); - clone.apiDocMap = new HashMap(apiDocMap); - return clone; + public Object clone() { + Options clone = null; + try { + clone = (Options) super.clone(); + } catch (CloneNotSupportedException e) { + throw new RuntimeException("Cannot clone?!?", e); // Should not happen + } + // deep clone the hide and collection patterns + clone.hidePatterns = new ArrayList(hidePatterns); + clone.includePatterns = new ArrayList(includePatterns); + clone.collPackages = new ArrayList(collPackages); + clone.apiDocMap = new HashMap(apiDocMap); + return clone; } /** Most complete output */ public void setAll() { - showAttributes = true; - showEnumerations = true; - showEnumConstants = true; - showOperations = true; - showConstructors = true; - showVisibility = true; - showType = true; + showAttributes = true; + showEnumerations = true; + showEnumConstants = true; + showOperations = true; + showConstructors = true; + showVisibility = true; + showType = true; } - + /** * Match strings, ignoring leading -, -!, and !. * - * @param given Given string + * @param given Given string * @param expect Expected string * @return {@code true} on success */ protected static boolean matchOption(String given, String expect) { - return matchOption(given, expect, false); + return matchOption(given, expect, false); } /** * Match strings, ignoring leading -, -!, and !. * - * @param given Given string - * @param expect Expected string + * @param given Given string + * @param expect Expected string * @param negative May be negative * @return {@code true} on success */ protected static boolean matchOption(String given, String expect, boolean negative) { - int begin = 0, end = given.length(); - if (begin < end && given.charAt(begin) == '-') - ++begin; - if (negative && begin < end && given.charAt(begin) == '!') - ++begin; - return expect.length() == end - begin && expect.regionMatches(0, given, begin, end - begin); + int begin = 0, end = given.length(); + if (begin < end && given.charAt(begin) == '-') + ++begin; + if (negative && begin < end && given.charAt(begin) == '!') + ++begin; + return expect.length() == end - begin && expect.regionMatches(0, given, begin, end - begin); } /** - * Return the number of arguments associated with the specified option. - * The return value includes the actual option. - * Will return 0 if the option is not supported. + * Return the number of arguments associated with the specified option. The + * return value includes the actual option. Will return 0 if the option is not + * supported. */ public static int optionLength(String option) { - if(matchOption(option, "qualify", true) || - matchOption(option, "qualifyGenerics", true) || - matchOption(option, "hideGenerics", true) || - matchOption(option, "horizontal", true) || - matchOption(option, "all") || - matchOption(option, "attributes", true) || - matchOption(option, "enumconstants", true) || - matchOption(option, "operations", true) || - matchOption(option, "enumerations", true) || - matchOption(option, "constructors", true) || - matchOption(option, "visibility", true) || - matchOption(option, "types", true) || - matchOption(option, "autosize", true) || - matchOption(option, "commentname", true) || - matchOption(option, "nodefontabstractitalic", true) || - matchOption(option, "postfixpackage", true) || - matchOption(option, "noguillemot", true) || - matchOption(option, "views", true) || - matchOption(option, "inferrel", true) || - matchOption(option, "useimports", true) || - matchOption(option, "collapsible", true) || - matchOption(option, "inferdep", true) || - matchOption(option, "inferdepinpackage", true) || - matchOption(option, "hideprivateinner", true) || - matchOption(option, "compact", true)) + if (matchOption(option, "qualify", true) || matchOption(option, "qualifyGenerics", true) + || matchOption(option, "hideGenerics", true) || matchOption(option, "horizontal", true) + || matchOption(option, "all") || matchOption(option, "attributes", true) + || matchOption(option, "enumconstants", true) || matchOption(option, "operations", true) + || matchOption(option, "enumerations", true) || matchOption(option, "constructors", true) + || matchOption(option, "visibility", true) || matchOption(option, "types", true) + || matchOption(option, "autosize", true) || matchOption(option, "commentname", true) + || matchOption(option, "nodefontabstractitalic", true) || matchOption(option, "postfixpackage", true) + || matchOption(option, "noguillemot", true) || matchOption(option, "views", true) + || matchOption(option, "inferrel", true) || matchOption(option, "useimports", true) + || matchOption(option, "collapsible", true) || matchOption(option, "inferdep", true) + || matchOption(option, "inferdepinpackage", true) || matchOption(option, "hideprivateinner", true) + || matchOption(option, "compact", true)) return 1; - else if(matchOption(option, "nodefillcolor") || - matchOption(option, "nodefontcolor") || - matchOption(option, "nodefontsize") || - matchOption(option, "nodefontname") || - matchOption(option, "nodefontclasssize") || - matchOption(option, "nodefontclassname") || - matchOption(option, "nodefonttagsize") || - matchOption(option, "nodefonttagname") || - matchOption(option, "nodefontpackagesize") || - matchOption(option, "nodefontpackagename") || - matchOption(option, "edgefontcolor") || - matchOption(option, "edgecolor") || - matchOption(option, "edgefontsize") || - matchOption(option, "edgefontname") || - matchOption(option, "shape") || - matchOption(option, "output") || - matchOption(option, "outputencoding") || - matchOption(option, "bgcolor") || - matchOption(option, "hide") || - matchOption(option, "include") || - matchOption(option, "apidocroot") || - matchOption(option, "apidocmap") || - matchOption(option, "d") || - matchOption(option, "view") || - matchOption(option, "inferreltype") || - matchOption(option, "inferdepvis") || - matchOption(option, "collpackages") || - matchOption(option, "nodesep") || - matchOption(option, "ranksep") || - matchOption(option, "dotexecutable") || - matchOption(option, "link")) - return 2; - else if(matchOption(option, "contextPattern") || - matchOption(option, "linkoffline")) + else if (matchOption(option, "nodefillcolor") || matchOption(option, "nodefontcolor") + || matchOption(option, "nodefontsize") || matchOption(option, "nodefontname") + || matchOption(option, "nodefontclasssize") || matchOption(option, "nodefontclassname") + || matchOption(option, "nodefonttagsize") || matchOption(option, "nodefonttagname") + || matchOption(option, "nodefontpackagesize") || matchOption(option, "nodefontpackagename") + || matchOption(option, "edgefontcolor") || matchOption(option, "edgecolor") + || matchOption(option, "edgefontsize") || matchOption(option, "edgefontname") + || matchOption(option, "shape") || matchOption(option, "output") + || matchOption(option, "outputencoding") || matchOption(option, "bgcolor") + || matchOption(option, "hide") || matchOption(option, "include") || matchOption(option, "apidocroot") + || matchOption(option, "apidocmap") || matchOption(option, "d") || matchOption(option, "view") + || matchOption(option, "inferreltype") || matchOption(option, "inferdepvis") + || matchOption(option, "collpackages") || matchOption(option, "nodesep") + || matchOption(option, "ranksep") || matchOption(option, "dotexecutable") + || matchOption(option, "link")) + return 2; + else if (matchOption(option, "contextPattern") || matchOption(option, "linkoffline")) return 3; else return 0; } - + /** Set the options based on a single option and its arguments */ void setOption(String[] opt) { - if(!matchOption(opt[0], "hide") && optionLength(opt[0]) > opt.length) { - System.err.println("Skipping option '" + opt[0] + "', missing argument"); - return; - } - boolean dash = opt[0].length() > 1 && opt[0].charAt(0) == '-'; - boolean positive = !(opt[0].length() > 1 && opt[0].charAt(dash ? 1 : 0) == '!'); - - if(matchOption(opt[0], "qualify", true)) { - showQualified = positive; - } else if(matchOption(opt[0], "qualifyGenerics", true)) { - showQualifiedGenerics = positive; - } else if(matchOption(opt[0], "hideGenerics", true)) { - hideGenerics = positive; - } else if(matchOption(opt[0], "horizontal", true)) { - horizontal = positive; - } else if(matchOption(opt[0], "attributes", true)) { - showAttributes = positive; - } else if(matchOption(opt[0], "enumconstants", true)) { - showEnumConstants = positive; - } else if(matchOption(opt[0], "operations", true)) { - showOperations = positive; - } else if(matchOption(opt[0], "enumerations", true)) { - showEnumerations = positive; - } else if(matchOption(opt[0], "constructors", true)) { - showConstructors = positive; - } else if(matchOption(opt[0], "visibility", true)) { - showVisibility = positive; - } else if(matchOption(opt[0], "types", true)) { - showType = positive; - } else if(matchOption(opt[0], "autoSize", true)) { - autoSize = positive; - } else if(matchOption(opt[0], "commentname", true)) { - showComment = positive; - } else if(matchOption(opt[0], "all")) { - setAll(); - } else if(matchOption(opt[0], "bgcolor", true)) { - bgColor = positive ? opt[1] : null; - } else if(matchOption(opt[0], "edgecolor", true)) { - edgeColor = positive ? opt[1] : "black"; - } else if(matchOption(opt[0], "edgefontcolor", true)) { - edgeFontColor = positive ? opt[1] : "black"; - } else if(matchOption(opt[0], "edgefontname", true)) { - edgeFontName = positive ? opt[1] : Font.DEFAULT_FONT; - } else if(matchOption(opt[0], "edgefontsize", true)) { - edgeFontSize = positive ? Double.parseDouble(opt[1]) : 10; - } else if(matchOption(opt[0], "nodefontcolor", true)) { - nodeFontColor = positive ? opt[1] : "black"; - } else if(matchOption(opt[0], "nodefontname", true)) { - nodeFontName = positive ? opt[1] : Font.DEFAULT_FONT; - } else if(matchOption(opt[0], "nodefontabstractitalic", true)) { - nodeFontAbstractItalic = positive; - } else if(matchOption(opt[0], "nodefontsize", true)) { - nodeFontSize = positive ? Double.parseDouble(opt[1]) : 10; - } else if(matchOption(opt[0], "nodefontclassname", true)) { - nodeFontClassName = positive ? opt[1] : null; - } else if(matchOption(opt[0], "nodefontclasssize", true)) { - nodeFontClassSize = positive ? Double.parseDouble(opt[1]) : -1; - } else if(matchOption(opt[0], "nodefonttagname", true)) { - nodeFontTagName = positive ? opt[1] : null; - } else if(matchOption(opt[0], "nodefonttagsize", true)) { - nodeFontTagSize = positive ? Double.parseDouble(opt[1]) : -1; - } else if(matchOption(opt[0], "nodefontpackagename", true)) { - nodeFontPackageName = positive ? opt[1] : null; - } else if(matchOption(opt[0], "nodefontpackagesize", true)) { - nodeFontPackageSize = positive ? Double.parseDouble(opt[1]) : -1; - } else if(matchOption(opt[0], "nodefillcolor", true)) { - nodeFillColor = positive ? opt[1] : null; - } else if(matchOption(opt[0], "shape", true)) { - shape = positive ? Shape.of(opt[1]) : Shape.CLASS; - } else if(matchOption(opt[0], "output", true)) { - outputFileName = positive ? opt[1] : "graph.dot"; - } else if(matchOption(opt[0], "outputencoding", true)) { - outputEncoding = positive ? opt[1] : "ISO-8859-1"; - } else if(matchOption(opt[0], "hide", true)) { - if (positive) { - if (opt.length == 1) { - hidePatterns.clear(); - hidePatterns.add(allPattern); - } else { - try { - hidePatterns.add(Pattern.compile(opt[1])); - } catch (PatternSyntaxException e) { - System.err.println("Skipping invalid pattern " + opt[1]); - } - } - } else - hidePatterns.clear(); - } else if(matchOption(opt[0], "include", true)) { - if (positive) { - try { - includePatterns.add(Pattern.compile(opt[1])); - } catch (PatternSyntaxException e) { - System.err.println("Skipping invalid pattern " + opt[1]); - } - } else - includePatterns.clear(); - } else if(matchOption(opt[0], "apidocroot", true)) { - apiDocRoot = positive ? fixApiDocRoot(opt[1]) : null; - } else if(matchOption(opt[0], "apidocmap", true)) { - if (positive) - setApiDocMapFile(opt[1]); - else - apiDocMap.clear(); - } else if(matchOption(opt[0], "noguillemot", true)) { - guilOpen = positive ? "<<" : "\u00ab"; - guilClose = positive ? ">>" : "\u00bb"; - } else if (matchOption(opt[0], "view", true)) { - viewName = positive ? opt[1] : null; - } else if (matchOption(opt[0], "views", true)) { - findViews = positive; - } else if (matchOption(opt[0], "d", true)) { - outputDirectory = positive ? opt[1] : null; - } else if(matchOption(opt[0], "inferrel", true)) { - inferRelationships = positive; - } else if(matchOption(opt[0], "inferreltype", true)) { - if (positive) { - try { - inferRelationshipType = RelationType.valueOf(opt[1].toUpperCase()); - } catch(IllegalArgumentException e) { - System.err.println("Unknown association type " + opt[1]); - } - } else - inferRelationshipType = RelationType.NAVASSOC; - } else if(matchOption(opt[0], "inferdepvis", true)) { - if (positive) { - try { - Visibility vis = Visibility.valueOf(opt[1].toUpperCase()); - inferDependencyVisibility = vis; - } catch(IllegalArgumentException e) { - System.err.println("Ignoring invalid visibility specification for " + - "dependency inference: " + opt[1]); - } - } else - inferDependencyVisibility = Visibility.PRIVATE; - } else if(matchOption(opt[0], "collapsible", true)) { - collapsibleDiagrams = positive; - } else if(matchOption(opt[0], "inferdep", true)) { - inferDependencies = positive; - } else if(matchOption(opt[0], "inferdepinpackage", true)) { - inferDepInPackage = positive; - } else if (matchOption(opt[0], "hideprivateinner", true)) { - hidePrivateInner = positive; - } else if(matchOption(opt[0], "useimports", true)) { - useImports = positive; - } else if (matchOption(opt[0], "collpackages", true)) { - if (positive) { - try { - collPackages.add(Pattern.compile(opt[1])); - } catch (PatternSyntaxException e) { - System.err.println("Skipping invalid pattern " + opt[1]); - } - } else - collPackages.clear(); - } else if (matchOption(opt[0], "compact", true)) { - compact = positive; - } else if (matchOption(opt[0], "postfixpackage", true)) { - postfixPackage = positive; - } else if (matchOption(opt[0], "link")) { - addApiDocRoots(opt[1]); - } else if (matchOption(opt[0], "linkoffline")) { - addApiDocRootsOffline(opt[1], opt[2]); - } else if(matchOption(opt[0], "contextPattern")) { - RelationDirection d; RelationType rt; - try { - d = RelationDirection.valueOf(opt[2].toUpperCase()); - if(opt[1].equalsIgnoreCase("all")) { - contextRelationPattern = new RelationPattern(d); - } else { - rt = RelationType.valueOf(opt[1].toUpperCase()); - contextRelationPattern.addRelation(rt, d); - } - } catch(IllegalArgumentException e) { - - } - - } else if (matchOption(opt[0], "nodesep", true)) { - try { - nodeSep = positive ? Double.parseDouble(opt[1]) : 0.25; - } catch (NumberFormatException e) { - System.err.println("Skipping invalid nodesep " + opt[1]); - } - } else if (matchOption(opt[0], "ranksep", true)) { - try { - rankSep = positive ? Double.parseDouble(opt[1]) : 0.5; - } catch (NumberFormatException e) { - System.err.println("Skipping invalid ranksep " + opt[1]); - } - } else if (matchOption(opt[0], "dotexecutable")) { - dotExecutable = opt[1]; - } else - ; // Do nothing, javadoc will handle the option or complain, if needed. + if (!matchOption(opt[0], "hide") && optionLength(opt[0]) > opt.length) { + System.err.println("Skipping option '" + opt[0] + "', missing argument"); + return; + } + boolean dash = opt[0].length() > 1 && opt[0].charAt(0) == '-'; + boolean positive = !(opt[0].length() > 1 && opt[0].charAt(dash ? 1 : 0) == '!'); + + if (matchOption(opt[0], "qualify", true)) { + showQualified = positive; + } else if (matchOption(opt[0], "qualifyGenerics", true)) { + showQualifiedGenerics = positive; + } else if (matchOption(opt[0], "hideGenerics", true)) { + hideGenerics = positive; + } else if (matchOption(opt[0], "horizontal", true)) { + horizontal = positive; + } else if (matchOption(opt[0], "attributes", true)) { + showAttributes = positive; + } else if (matchOption(opt[0], "enumconstants", true)) { + showEnumConstants = positive; + } else if (matchOption(opt[0], "operations", true)) { + showOperations = positive; + } else if (matchOption(opt[0], "enumerations", true)) { + showEnumerations = positive; + } else if (matchOption(opt[0], "constructors", true)) { + showConstructors = positive; + } else if (matchOption(opt[0], "visibility", true)) { + showVisibility = positive; + } else if (matchOption(opt[0], "types", true)) { + showType = positive; + } else if (matchOption(opt[0], "autoSize", true)) { + autoSize = positive; + } else if (matchOption(opt[0], "commentname", true)) { + showComment = positive; + } else if (matchOption(opt[0], "all")) { + setAll(); + } else if (matchOption(opt[0], "bgcolor", true)) { + bgColor = positive ? opt[1] : null; + } else if (matchOption(opt[0], "edgecolor", true)) { + edgeColor = positive ? opt[1] : "black"; + } else if (matchOption(opt[0], "edgefontcolor", true)) { + edgeFontColor = positive ? opt[1] : "black"; + } else if (matchOption(opt[0], "edgefontname", true)) { + edgeFontName = positive ? opt[1] : Font.DEFAULT_FONT; + } else if (matchOption(opt[0], "edgefontsize", true)) { + edgeFontSize = positive ? Double.parseDouble(opt[1]) : 10; + } else if (matchOption(opt[0], "nodefontcolor", true)) { + nodeFontColor = positive ? opt[1] : "black"; + } else if (matchOption(opt[0], "nodefontname", true)) { + nodeFontName = positive ? opt[1] : Font.DEFAULT_FONT; + } else if (matchOption(opt[0], "nodefontabstractitalic", true)) { + nodeFontAbstractItalic = positive; + } else if (matchOption(opt[0], "nodefontsize", true)) { + nodeFontSize = positive ? Double.parseDouble(opt[1]) : 10; + } else if (matchOption(opt[0], "nodefontclassname", true)) { + nodeFontClassName = positive ? opt[1] : null; + } else if (matchOption(opt[0], "nodefontclasssize", true)) { + nodeFontClassSize = positive ? Double.parseDouble(opt[1]) : -1; + } else if (matchOption(opt[0], "nodefonttagname", true)) { + nodeFontTagName = positive ? opt[1] : null; + } else if (matchOption(opt[0], "nodefonttagsize", true)) { + nodeFontTagSize = positive ? Double.parseDouble(opt[1]) : -1; + } else if (matchOption(opt[0], "nodefontpackagename", true)) { + nodeFontPackageName = positive ? opt[1] : null; + } else if (matchOption(opt[0], "nodefontpackagesize", true)) { + nodeFontPackageSize = positive ? Double.parseDouble(opt[1]) : -1; + } else if (matchOption(opt[0], "nodefillcolor", true)) { + nodeFillColor = positive ? opt[1] : null; + } else if (matchOption(opt[0], "shape", true)) { + shape = positive ? Shape.of(opt[1]) : Shape.CLASS; + } else if (matchOption(opt[0], "output", true)) { + outputFileName = positive ? opt[1] : "graph.dot"; + } else if (matchOption(opt[0], "outputencoding", true)) { + outputEncoding = positive ? opt[1] : "ISO-8859-1"; + } else if (matchOption(opt[0], "hide", true)) { + if (positive) { + if (opt.length == 1) { + hidePatterns.clear(); + hidePatterns.add(allPattern); + } else { + try { + hidePatterns.add(Pattern.compile(opt[1])); + } catch (PatternSyntaxException e) { + System.err.println("Skipping invalid pattern " + opt[1]); + } + } + } else + hidePatterns.clear(); + } else if (matchOption(opt[0], "include", true)) { + if (positive) { + try { + includePatterns.add(Pattern.compile(opt[1])); + } catch (PatternSyntaxException e) { + System.err.println("Skipping invalid pattern " + opt[1]); + } + } else + includePatterns.clear(); + } else if (matchOption(opt[0], "apidocroot", true)) { + apiDocRoot = positive ? fixApiDocRoot(opt[1]) : null; + } else if (matchOption(opt[0], "apidocmap", true)) { + if (positive) + setApiDocMapFile(opt[1]); + else + apiDocMap.clear(); + } else if (matchOption(opt[0], "noguillemot", true)) { + guilOpen = positive ? "<<" : "\u00ab"; + guilClose = positive ? ">>" : "\u00bb"; + } else if (matchOption(opt[0], "view", true)) { + viewName = positive ? opt[1] : null; + } else if (matchOption(opt[0], "views", true)) { + findViews = positive; + } else if (matchOption(opt[0], "d", true)) { + outputDirectory = positive ? opt[1] : null; + } else if (matchOption(opt[0], "inferrel", true)) { + inferRelationships = positive; + } else if (matchOption(opt[0], "inferreltype", true)) { + if (positive) { + try { + inferRelationshipType = RelationType.valueOf(opt[1].toUpperCase()); + } catch (IllegalArgumentException e) { + System.err.println("Unknown association type " + opt[1]); + } + } else + inferRelationshipType = RelationType.NAVASSOC; + } else if (matchOption(opt[0], "inferdepvis", true)) { + if (positive) { + try { + Visibility vis = Visibility.valueOf(opt[1].toUpperCase()); + inferDependencyVisibility = vis; + } catch (IllegalArgumentException e) { + System.err.println( + "Ignoring invalid visibility specification for " + "dependency inference: " + opt[1]); + } + } else + inferDependencyVisibility = Visibility.PRIVATE; + } else if (matchOption(opt[0], "collapsible", true)) { + collapsibleDiagrams = positive; + } else if (matchOption(opt[0], "inferdep", true)) { + inferDependencies = positive; + } else if (matchOption(opt[0], "inferdepinpackage", true)) { + inferDepInPackage = positive; + } else if (matchOption(opt[0], "hideprivateinner", true)) { + hidePrivateInner = positive; + } else if (matchOption(opt[0], "useimports", true)) { + useImports = positive; + } else if (matchOption(opt[0], "collpackages", true)) { + if (positive) { + try { + collPackages.add(Pattern.compile(opt[1])); + } catch (PatternSyntaxException e) { + System.err.println("Skipping invalid pattern " + opt[1]); + } + } else + collPackages.clear(); + } else if (matchOption(opt[0], "compact", true)) { + compact = positive; + } else if (matchOption(opt[0], "postfixpackage", true)) { + postfixPackage = positive; + } else if (matchOption(opt[0], "link")) { + addApiDocRoots(opt[1]); + } else if (matchOption(opt[0], "linkoffline")) { + addApiDocRootsOffline(opt[1], opt[2]); + } else if (matchOption(opt[0], "contextPattern")) { + RelationDirection d; + RelationType rt; + try { + d = RelationDirection.valueOf(opt[2].toUpperCase()); + if (opt[1].equalsIgnoreCase("all")) { + contextRelationPattern = new RelationPattern(d); + } else { + rt = RelationType.valueOf(opt[1].toUpperCase()); + contextRelationPattern.addRelation(rt, d); + } + } catch (IllegalArgumentException e) { + + } + + } else if (matchOption(opt[0], "nodesep", true)) { + try { + nodeSep = positive ? Double.parseDouble(opt[1]) : 0.25; + } catch (NumberFormatException e) { + System.err.println("Skipping invalid nodesep " + opt[1]); + } + } else if (matchOption(opt[0], "ranksep", true)) { + try { + rankSep = positive ? Double.parseDouble(opt[1]) : 0.5; + } catch (NumberFormatException e) { + System.err.println("Skipping invalid ranksep " + opt[1]); + } + } else if (matchOption(opt[0], "dotexecutable")) { + dotExecutable = opt[1]; + } else + ; // Do nothing, javadoc will handle the option or complain, if needed. } /** - * Adds api doc roots from a link. The folder reffered by the link should contain a package-list - * file that will be parsed in order to add api doc roots to this configuration + * Adds api doc roots from a link. The folder reffered by the link should + * contain a package-list file that will be parsed in order to add api doc roots + * to this configuration + * * @param packageListUrl */ private void addApiDocRoots(String packageListUrl) { - BufferedReader br = null; - packageListUrl = fixApiDocRoot(packageListUrl); - try { - URL url = new URL(packageListUrl + "/package-list"); - br = new BufferedReader(new InputStreamReader(url.openStream())); - String line; - while((line = br.readLine()) != null) { - line = line + "."; - Pattern pattern = Pattern.compile(line.replace(".", "\\.") + "[^\\.]*"); - apiDocMap.put(pattern, packageListUrl); - } - } catch(IOException e) { - System.err.println("Errors happened while accessing the package-list file at " - + packageListUrl); - } finally { - if(br != null) - try { - br.close(); - } catch (IOException e) {} - } - + BufferedReader br = null; + packageListUrl = fixApiDocRoot(packageListUrl); + try { + URL url = new URL(packageListUrl + "/package-list"); + br = new BufferedReader(new InputStreamReader(url.openStream())); + String line; + while ((line = br.readLine()) != null) { + line = line + "."; + Pattern pattern = Pattern.compile(line.replace(".", "\\.") + "[^\\.]*"); + apiDocMap.put(pattern, packageListUrl); + } + } catch (IOException e) { + System.err.println("Errors happened while accessing the package-list file at " + packageListUrl); + } finally { + if (br != null) + try { + br.close(); + } catch (IOException e) { + } + } + } /** - * Adds api doc roots from an offline link. - * The folder specified by packageListUrl should contain the package-list associed with the docUrl folder. - * @param docUrl folder containing the javadoc + * Adds api doc roots from an offline link. The folder specified by + * packageListUrl should contain the package-list associed with the docUrl + * folder. + * + * @param docUrl folder containing the javadoc * @param packageListUrl folder containing the package-list */ private void addApiDocRootsOffline(String docUrl, String packageListUrl) { - BufferedReader br = null; - packageListUrl = fixApiDocRoot(packageListUrl); - try { - URL url = new URL(packageListUrl + "/package-list"); - br = new BufferedReader(new InputStreamReader(url.openStream())); - String line; - while((line = br.readLine()) != null) { - line = line + "."; - Pattern pattern = Pattern.compile(line.replace(".", "\\.") + "[^\\.]*"); - apiDocMap.put(pattern, fixApiDocRoot(docUrl)); - } - } catch(IOException e) { - System.err.println("Unable to access the package-list file at " + packageListUrl); - } finally { - if (br != null) - try { - br.close(); - } catch (IOException e) {} - } + BufferedReader br = null; + packageListUrl = fixApiDocRoot(packageListUrl); + try { + URL url = new URL(packageListUrl + "/package-list"); + br = new BufferedReader(new InputStreamReader(url.openStream())); + String line; + while ((line = br.readLine()) != null) { + line = line + "."; + Pattern pattern = Pattern.compile(line.replace(".", "\\.") + "[^\\.]*"); + apiDocMap.put(pattern, fixApiDocRoot(docUrl)); + } + } catch (IOException e) { + System.err.println("Unable to access the package-list file at " + packageListUrl); + } finally { + if (br != null) + try { + br.close(); + } catch (IOException e) { + } + } } /** - * Loads the property file referred by apiDocMapFileName and fills the apiDocMap - * accordingly + * Loads the property file referred by apiDocMapFileName and fills + * the apiDocMap accordingly + * * @param apiDocMapFileName */ void setApiDocMapFile(String apiDocMapFileName) { - try { - InputStream is = new FileInputStream(apiDocMapFileName); - Properties userMap = new Properties(); - userMap.load(is); - for (Map.Entry mapEntry : userMap.entrySet()) { - try { - String thisRoot = (String) mapEntry.getValue(); - if (thisRoot != null) { - thisRoot = fixApiDocRoot(thisRoot); - apiDocMap.put(Pattern.compile((String) mapEntry.getKey()), thisRoot); - } else { - System.err.println("No URL for pattern " + mapEntry.getKey()); - } - } catch (PatternSyntaxException e) { - System.err.println("Skipping bad pattern " + mapEntry.getKey()); - } - } - } catch (FileNotFoundException e) { - System.err.println("File " + apiDocMapFileName + " was not found: " + e); - } catch (IOException e) { - System.err.println("Error reading the property api map file " + apiDocMapFileName - + ": " + e); - } + try { + InputStream is = new FileInputStream(apiDocMapFileName); + Properties userMap = new Properties(); + userMap.load(is); + for (Map.Entry mapEntry : userMap.entrySet()) { + try { + String thisRoot = (String) mapEntry.getValue(); + if (thisRoot != null) { + thisRoot = fixApiDocRoot(thisRoot); + apiDocMap.put(Pattern.compile((String) mapEntry.getKey()), thisRoot); + } else { + System.err.println("No URL for pattern " + mapEntry.getKey()); + } + } catch (PatternSyntaxException e) { + System.err.println("Skipping bad pattern " + mapEntry.getKey()); + } + } + } catch (FileNotFoundException e) { + System.err.println("File " + apiDocMapFileName + " was not found: " + e); + } catch (IOException e) { + System.err.println("Error reading the property api map file " + apiDocMapFileName + ": " + e); + } } - + /** - * Returns the appropriate URL "root" for an external class name. It will - * match the class name against the regular expressions specified in the - * apiDocMap; if a match is found, the associated URL - * will be returned. + * Returns the appropriate URL "root" for an external class name. It will match + * the class name against the regular expressions specified in the + * apiDocMap; if a match is found, the associated URL will be + * returned. *

- * NOTE: The match order of the match attempts is the one specified by the - * constructor of the api doc root, so it depends on the order of "-link" and "-apiDocMap" - * parameters. + * NOTE: The match order of the match attempts is the one specified by + * the constructor of the api doc root, so it depends on the order of "-link" + * and "-apiDocMap" parameters. */ public String getApiDocRoot(String className) { - if(apiDocMap.isEmpty()) - apiDocMap.put(Pattern.compile(".*"), DEFAULT_EXTERNAL_APIDOC); - - for (Map.Entry mapEntry : apiDocMap.entrySet()) { - if (mapEntry.getKey().matcher(className).matches()) - return mapEntry.getValue(); - } - return null; + if (apiDocMap.isEmpty()) + apiDocMap.put(Pattern.compile(".*"), DEFAULT_EXTERNAL_APIDOC); + + for (Map.Entry mapEntry : apiDocMap.entrySet()) { + if (mapEntry.getKey().matcher(className).matches()) + return mapEntry.getValue(); + } + return null; } - + /** Trim and append a file separator to the string */ private String fixApiDocRoot(String str) { - if (str == null) - return null; - String fixed = str.trim(); - if (fixed.isEmpty()) - return ""; - if (File.separatorChar != '/') - fixed = fixed.replace(File.separatorChar, '/'); - if (!fixed.endsWith("/")) - fixed = fixed + "/"; - return fixed; + if (str == null) + return null; + String fixed = str.trim(); + if (fixed.isEmpty()) + return ""; + if (File.separatorChar != '/') + fixed = fixed.replace(File.separatorChar, '/'); + if (!fixed.endsWith("/")) + fixed = fixed + "/"; + return fixed; } /** Set the options based on the command line parameters */ public void setOptions(String[][] options) { - for (String s[] : options) - setOption(s); + for (String s[] : options) + setOption(s); } - /** Set the options based on the tag elements of the ClassDoc parameter */ public void setOptions(Doc p) { - if (p == null) - return; + if (p == null) + return; - for (Tag tag : p.tags("opt")) - setOption(StringUtil.tokenize(tag.text())); + for (Tag tag : p.tags("opt")) + setOption(StringUtil.tokenize(tag.text())); } /** - * Check if the supplied string matches an entity specified - * with the -hide parameter. + * Check if the supplied string matches an entity specified with the -hide + * parameter. + * * @return true if the string matches. */ public boolean matchesHideExpression(String s) { - for (Pattern hidePattern : hidePatterns) { - // micro-optimization because the "all pattern" is heavily used in UmlGraphDoc - if(hidePattern == allPattern) - return true; - - Matcher m = hidePattern.matcher(s); - if (strictMatching ? m.matches() : m.find()) - return true; - } - return false; + for (Pattern hidePattern : hidePatterns) { + // micro-optimization because the "all pattern" is heavily used in UmlGraphDoc + if (hidePattern == allPattern) + return true; + + Matcher m = hidePattern.matcher(s); + if (strictMatching ? m.matches() : m.find()) + return true; + } + return false; } - + /** - * Check if the supplied string matches an entity specified - * with the -include parameter. + * Check if the supplied string matches an entity specified with the -include + * parameter. + * * @return true if the string matches. */ public boolean matchesIncludeExpression(String s) { - for (Pattern includePattern : includePatterns) { - Matcher m = includePattern.matcher(s); - if (strictMatching ? m.matches() : m.find()) - return true; - } - return false; + for (Pattern includePattern : includePatterns) { + Matcher m = includePattern.matcher(s); + if (strictMatching ? m.matches() : m.find()) + return true; + } + return false; } /** - * Check if the supplied string matches an entity specified - * with the -collpackages parameter. + * Check if the supplied string matches an entity specified with the + * -collpackages parameter. + * * @return true if the string matches. */ public boolean matchesCollPackageExpression(String s) { - for (Pattern collPattern : collPackages) { - Matcher m = collPattern.matcher(s); - if (strictMatching ? m.matches() : m.find()) - return true; - } - return false; + for (Pattern collPattern : collPackages) { + Matcher m = collPattern.matcher(s); + if (strictMatching ? m.matches() : m.find()) + return true; + } + return false; } - - // ---------------------------------------------------------------- + + // ---------------------------------------------------------------- // OptionProvider methods - // ---------------------------------------------------------------- - + // ---------------------------------------------------------------- + public Options getOptionsFor(ClassDoc cd) { - Options localOpt = getGlobalOptions(); - localOpt.setOptions(cd); - return localOpt; + Options localOpt = getGlobalOptions(); + localOpt.setOptions(cd); + return localOpt; } public Options getOptionsFor(String name) { - return getGlobalOptions(); + return getGlobalOptions(); } public Options getGlobalOptions() { - return (Options) clone(); + return (Options) clone(); } public void overrideForClass(Options opt, ClassDoc cd) { - // nothing to do + // nothing to do } public void overrideForClass(Options opt, String className) { - // nothing to do + // nothing to do } public String getDisplayName() { - return "general class diagram"; + return "general class diagram"; } - + public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("UMLGRAPH OPTIONS\n"); - for(Field f : this.getClass().getDeclaredFields()) { - if(!Modifier.isStatic(f.getModifiers())) { - f.setAccessible(true); - try { - sb.append(f.getName() + ":" + f.get(this) + "\n"); - } catch (Exception e) { - } - } - } - return sb.toString(); + StringBuilder sb = new StringBuilder(); + sb.append("UMLGRAPH OPTIONS\n"); + for (Field f : this.getClass().getDeclaredFields()) { + if (!Modifier.isStatic(f.getModifiers())) { + f.setAccessible(true); + try { + sb.append(f.getName() + ":" + f.get(this) + "\n"); + } catch (Exception e) { + } + } + } + return sb.toString(); } } diff --git a/src/main/java/org/umlgraph/doclet/PackageMatcher.java b/src/main/java/org/umlgraph/doclet/PackageMatcher.java index 99bd7ff..ecc3002 100644 --- a/src/main/java/org/umlgraph/doclet/PackageMatcher.java +++ b/src/main/java/org/umlgraph/doclet/PackageMatcher.java @@ -7,19 +7,19 @@ public class PackageMatcher implements ClassMatcher { protected PackageDoc packageDoc; public PackageMatcher(PackageDoc packageDoc) { - super(); - this.packageDoc = packageDoc; + super(); + this.packageDoc = packageDoc; } public boolean matches(ClassDoc cd) { - return cd.containingPackage().equals(packageDoc); + return cd.containingPackage().equals(packageDoc); } public boolean matches(String name) { - for (ClassDoc cd : packageDoc.allClasses()) - if (cd.qualifiedName().equals(name)) - return true; - return false; + for (ClassDoc cd : packageDoc.allClasses()) + if (cd.qualifiedName().equals(name)) + return true; + return false; } } diff --git a/src/main/java/org/umlgraph/doclet/PackageView.java b/src/main/java/org/umlgraph/doclet/PackageView.java index c66bf6d..83af937 100755 --- a/src/main/java/org/umlgraph/doclet/PackageView.java +++ b/src/main/java/org/umlgraph/doclet/PackageView.java @@ -12,6 +12,7 @@ import com.sun.javadoc.RootDoc; * single {@linkplain ClassMatcher}, and provides some extra configuration such * as output path configuration (and it is specified in code rather than in * javadoc comments). + * * @author wolf * */ @@ -25,57 +26,57 @@ public class PackageView implements OptionProvider { private Options opt; public PackageView(String outputFolder, PackageDoc pd, RootDoc root, OptionProvider parent) { - this.parent = parent; - this.pd = pd; - this.matcher = new PackageMatcher(pd); - this.opt = parent.getGlobalOptions(); - this.opt.setOptions(pd); - this.outputPath = pd.name().replace('.', '/') + "/" + pd.name() + ".dot"; + this.parent = parent; + this.pd = pd; + this.matcher = new PackageMatcher(pd); + this.opt = parent.getGlobalOptions(); + this.opt.setOptions(pd); + this.outputPath = pd.name().replace('.', '/') + "/" + pd.name() + ".dot"; } public String getDisplayName() { - return "Package view for package " + pd; + return "Package view for package " + pd; } public Options getGlobalOptions() { - Options go = parent.getGlobalOptions(); + Options go = parent.getGlobalOptions(); - go.setOption(new String[] { "output", outputPath }); - go.setOption(HIDE); + go.setOption(new String[] { "output", outputPath }); + go.setOption(HIDE); - return go; + return go; } public Options getOptionsFor(ClassDoc cd) { - Options go = parent.getGlobalOptions(); - overrideForClass(go, cd); - return go; + Options go = parent.getGlobalOptions(); + overrideForClass(go, cd); + return go; } public Options getOptionsFor(String name) { - Options go = parent.getGlobalOptions(); - overrideForClass(go, name); - return go; + Options go = parent.getGlobalOptions(); + overrideForClass(go, name); + return go; } public void overrideForClass(Options opt, ClassDoc cd) { - opt.setOptions(cd); - boolean inPackage = matcher.matches(cd); - if (inPackage) - opt.showQualified = false; - boolean included = inPackage || this.opt.matchesIncludeExpression(cd.qualifiedName()); - if (!included || this.opt.matchesHideExpression(cd.qualifiedName())) - opt.setOption(HIDE); + opt.setOptions(cd); + boolean inPackage = matcher.matches(cd); + if (inPackage) + opt.showQualified = false; + boolean included = inPackage || this.opt.matchesIncludeExpression(cd.qualifiedName()); + if (!included || this.opt.matchesHideExpression(cd.qualifiedName())) + opt.setOption(HIDE); } public void overrideForClass(Options opt, String className) { - opt.showQualified = false; - boolean inPackage = matcher.matches(className); - if (inPackage) - opt.showQualified = false; - boolean included = inPackage || this.opt.matchesIncludeExpression(className); - if (!included || this.opt.matchesHideExpression(className)) - opt.setOption(HIDE); + opt.showQualified = false; + boolean inPackage = matcher.matches(className); + if (inPackage) + opt.showQualified = false; + boolean included = inPackage || this.opt.matchesIncludeExpression(className); + if (!included || this.opt.matchesHideExpression(className)) + opt.setOption(HIDE); } } diff --git a/src/main/java/org/umlgraph/doclet/PatternMatcher.java b/src/main/java/org/umlgraph/doclet/PatternMatcher.java index 78a9135..a809db6 100644 --- a/src/main/java/org/umlgraph/doclet/PatternMatcher.java +++ b/src/main/java/org/umlgraph/doclet/PatternMatcher.java @@ -23,21 +23,22 @@ import com.sun.javadoc.ClassDoc; /** * Matches classes performing a regular expression match on the qualified class * name + * * @author wolf */ public class PatternMatcher implements ClassMatcher { Pattern pattern; public PatternMatcher(Pattern pattern) { - this.pattern = pattern; + this.pattern = pattern; } public boolean matches(ClassDoc cd) { - return matches(cd.toString()); + return matches(cd.toString()); } public boolean matches(String name) { - return pattern.matcher(name).matches(); + return pattern.matcher(name).matches(); } } diff --git a/src/main/java/org/umlgraph/doclet/RelationDirection.java b/src/main/java/org/umlgraph/doclet/RelationDirection.java index 4d3595c..dca8b4b 100644 --- a/src/main/java/org/umlgraph/doclet/RelationDirection.java +++ b/src/main/java/org/umlgraph/doclet/RelationDirection.java @@ -9,32 +9,35 @@ public enum RelationDirection { /** * Adds the current direction + * * @param d * @return */ public RelationDirection sum(RelationDirection d) { - // Handle same and nones first: - return (this == d || d == NONE) ? this : // - this == NONE ? d : BOTH; // They are different and not none. + // Handle same and nones first: + return (this == d || d == NONE) ? this : // + this == NONE ? d : BOTH; // They are different and not none. } /** - * Returns true if this direction "contains" the specified one, that is, - * either it's equal to it, or this direction is {@link #BOTH} + * Returns true if this direction "contains" the specified one, that is, either + * it's equal to it, or this direction is {@link #BOTH} + * * @param d * @return */ public boolean contains(RelationDirection d) { - return this == BOTH ? true : (d == this); + return this == BOTH ? true : (d == this); } /** - * Inverts the direction of the relation. Turns IN into OUT and vice-versa, NONE and BOTH - * are not changed + * Inverts the direction of the relation. Turns IN into OUT and vice-versa, NONE + * and BOTH are not changed + * * @return */ public RelationDirection inverse() { - return this == IN ? OUT : this == OUT ? IN : this; + return this == IN ? OUT : this == OUT ? IN : this; } }; diff --git a/src/main/java/org/umlgraph/doclet/RelationPattern.java b/src/main/java/org/umlgraph/doclet/RelationPattern.java index 4fa994e..db9b31e 100644 --- a/src/main/java/org/umlgraph/doclet/RelationPattern.java +++ b/src/main/java/org/umlgraph/doclet/RelationPattern.java @@ -2,6 +2,7 @@ package org.umlgraph.doclet; /** * A map from relation types to directions + * * @author wolf * */ @@ -13,38 +14,41 @@ public class RelationPattern { /** * Creates a new pattern using the same direction for every relation kind + * * @param defaultDirection The direction used to initialize this pattern */ public RelationPattern(RelationDirection defaultDirection) { - directions = new RelationDirection[RelationType.values().length]; - for (int i = 0; i < directions.length; i++) { - directions[i] = defaultDirection; - } + directions = new RelationDirection[RelationType.values().length]; + for (int i = 0; i < directions.length; i++) { + directions[i] = defaultDirection; + } } /** * Adds, eventually merging, a direction for the specified relation type + * * @param relationType * @param direction */ public void addRelation(RelationType relationType, RelationDirection direction) { - int idx = relationType.ordinal(); - directions[idx] = directions[idx].sum(direction); + int idx = relationType.ordinal(); + directions[idx] = directions[idx].sum(direction); } /** - * Returns true if this patterns matches at least the direction of one - * of the relations in the other relation patterns. Matching is defined - * by {@linkplain RelationDirection#contains(RelationDirection)} + * Returns true if this patterns matches at least the direction of one of the + * relations in the other relation patterns. Matching is defined by + * {@linkplain RelationDirection#contains(RelationDirection)} + * * @param relationPattern * @return */ public boolean matchesOne(RelationPattern relationPattern) { - for (int i = 0; i < directions.length; i++) { - if (directions[i].contains(relationPattern.directions[i])) - return true; - } - return false; + for (int i = 0; i < directions.length; i++) { + if (directions[i].contains(relationPattern.directions[i])) + return true; + } + return false; } } diff --git a/src/main/java/org/umlgraph/doclet/RelationType.java b/src/main/java/org/umlgraph/doclet/RelationType.java index 09f33a1..33b645d 100644 --- a/src/main/java/org/umlgraph/doclet/RelationType.java +++ b/src/main/java/org/umlgraph/doclet/RelationType.java @@ -27,8 +27,8 @@ public enum RelationType { /** Enum constructors must be private */ private RelationType(String style, boolean backorder) { - this.lower = toString().toLowerCase(); - this.style = style; - this.backorder = backorder; + this.lower = toString().toLowerCase(); + this.style = style; + this.backorder = backorder; } } diff --git a/src/main/java/org/umlgraph/doclet/Shape.java b/src/main/java/org/umlgraph/doclet/Shape.java index 54a8cdd..31df88c 100644 --- a/src/main/java/org/umlgraph/doclet/Shape.java +++ b/src/main/java/org/umlgraph/doclet/Shape.java @@ -45,10 +45,10 @@ public enum Shape { /** Initialize the lookup index */ static { - for (Shape s : Shape.values()) { - index.put(s.name(), s); - index.put(s.name().toLowerCase(Locale.ROOT), s); - } + for (Shape s : Shape.values()) { + index.put(s.name(), s); + index.put(s.name().toLowerCase(Locale.ROOT), s); + } } /** @@ -59,25 +59,25 @@ public enum Shape { * @return Shape */ public static Shape of(String s) { - Shape shp = index.get(s); - if (shp != null) - return shp; - System.err.println("Ignoring invalid shape: " + s); - return CLASS; + Shape shp = index.get(s); + if (shp != null) + return shp; + System.err.println("Ignoring invalid shape: " + s); + return CLASS; } /** Enum constructor, must be private! */ private Shape(String style) { - this.style = style; + this.style = style; } /** Return the table border required for the shape */ public String extraColumn() { - return this == Shape.ACTIVECLASS ? ("") : ""; + return this == Shape.ACTIVECLASS ? ("") : ""; } /** Return the cell border required for the shape */ public String cellBorder() { - return this == CLASS || this == ACTIVECLASS ? "1" : "0"; + return this == CLASS || this == ACTIVECLASS ? "1" : "0"; } } diff --git a/src/main/java/org/umlgraph/doclet/StringUtil.java b/src/main/java/org/umlgraph/doclet/StringUtil.java index e122e0b..1aee85b 100644 --- a/src/main/java/org/umlgraph/doclet/StringUtil.java +++ b/src/main/java/org/umlgraph/doclet/StringUtil.java @@ -31,37 +31,37 @@ import java.util.regex.Pattern; class StringUtil { /** Tokenize string s into an array */ public static String[] tokenize(String s) { - ArrayList r = new ArrayList(); - String remain = s; - int n = 0, pos; + ArrayList r = new ArrayList(); + String remain = s; + int n = 0, pos; - remain = remain.trim(); - while (remain.length() > 0) { - if (remain.startsWith("\"")) { - // Field in quotes - pos = remain.indexOf('"', 1); - if (pos == -1) - break; - r.add(remain.substring(1, pos)); - if (pos + 1 < remain.length()) - pos++; - } else { - // Space-separated field - pos = remain.indexOf(' ', 0); - if (pos == -1) { - r.add(remain); - remain = ""; - } else - r.add(remain.substring(0, pos)); - } - remain = remain.substring(pos + 1); - remain = remain.trim(); - // - is used as a placeholder for empy fields - if (r.get(n).equals("-")) - r.set(n, ""); - n++; - } - return r.toArray(new String[0]); + remain = remain.trim(); + while (remain.length() > 0) { + if (remain.startsWith("\"")) { + // Field in quotes + pos = remain.indexOf('"', 1); + if (pos == -1) + break; + r.add(remain.substring(1, pos)); + if (pos + 1 < remain.length()) + pos++; + } else { + // Space-separated field + pos = remain.indexOf(' ', 0); + if (pos == -1) { + r.add(remain); + remain = ""; + } else + r.add(remain.substring(0, pos)); + } + remain = remain.substring(pos + 1); + remain = remain.trim(); + // - is used as a placeholder for empy fields + if (r.get(n).equals("-")) + r.set(n, ""); + n++; + } + return r.toArray(new String[0]); } private final static Pattern ESCAPE_BASIC_XML = Pattern.compile("[&<>]"); @@ -71,47 +71,47 @@ class StringUtil { * HTML entity code. */ public static String escape(String s) { - if (ESCAPE_BASIC_XML.matcher(s).find()) { - StringBuilder sb = new StringBuilder(s); - for (int i = 0; i < sb.length();) { - switch (sb.charAt(i)) { - case '&': - sb.replace(i, i + 1, "&"); - i += "&".length(); - break; - case '<': - sb.replace(i, i + 1, "<"); - i += "<".length(); - break; - case '>': - sb.replace(i, i + 1, ">"); - i += ">".length(); - break; - default: - i++; - } - } - return sb.toString(); - } else - return s; + if (ESCAPE_BASIC_XML.matcher(s).find()) { + StringBuilder sb = new StringBuilder(s); + for (int i = 0; i < sb.length();) { + switch (sb.charAt(i)) { + case '&': + sb.replace(i, i + 1, "&"); + i += "&".length(); + break; + case '<': + sb.replace(i, i + 1, "<"); + i += "<".length(); + break; + case '>': + sb.replace(i, i + 1, ">"); + i += ">".length(); + break; + default: + i++; + } + } + return sb.toString(); + } else + return s; } /** * Convert embedded newlines into HTML line breaks */ public static String htmlNewline(String s) { - if (s.indexOf('\n') == -1) - return s; + if (s.indexOf('\n') == -1) + return s; - StringBuilder sb = new StringBuilder(s); - for (int i = 0; i < sb.length();) { - if (sb.charAt(i) == '\n') { - sb.replace(i, i + 1, "
"); - i += "
".length(); - } else - i++; - } - return sb.toString(); + StringBuilder sb = new StringBuilder(s); + for (int i = 0; i < sb.length();) { + if (sb.charAt(i) == '\n') { + sb.replace(i, i + 1, "
"); + i += "
".length(); + } else + i++; + } + return sb.toString(); } /** @@ -119,22 +119,22 @@ class StringUtil { * characters. */ public static String guillemize(Options opt, String s) { - StringBuilder r = new StringBuilder(s); - for (int i = 0; i < r.length();) - switch (r.charAt(i)) { - case '<': - r.replace(i, i + 1, opt.guilOpen); - i += opt.guilOpen.length(); - break; - case '>': - r.replace(i, i + 1, opt.guilClose); - i += opt.guilClose.length(); - break; - default: - i++; - break; - } - return r.toString(); + StringBuilder r = new StringBuilder(s); + for (int i = 0; i < r.length();) + switch (r.charAt(i)) { + case '<': + r.replace(i, i + 1, opt.guilOpen); + i += opt.guilOpen.length(); + break; + case '>': + r.replace(i, i + 1, opt.guilClose); + i += opt.guilClose.length(); + break; + default: + i++; + break; + } + return r.toString(); } /** @@ -144,45 +144,45 @@ class StringUtil { * @return the wrapped String. */ public static String guilWrap(Options opt, String str) { - return opt.guilOpen + str + opt.guilClose; + return opt.guilOpen + str + opt.guilClose; } /** Removes the template specs from a class name. */ public static String removeTemplate(String name) { - int openIdx = name.indexOf('<'); - if (openIdx == -1) - return name; - StringBuilder buf = new StringBuilder(name.length()); - for (int i = 0, depth = 0; i < name.length(); i++) { - char c = name.charAt(i); - if (c == '<') - depth++; - else if (c == '>') - depth--; - else if (depth == 0) - buf.append(c); - } - return buf.toString(); + int openIdx = name.indexOf('<'); + if (openIdx == -1) + return name; + StringBuilder buf = new StringBuilder(name.length()); + for (int i = 0, depth = 0; i < name.length(); i++) { + char c = name.charAt(i); + if (c == '<') + depth++; + else if (c == '>') + depth--; + else if (depth == 0) + buf.append(c); + } + return buf.toString(); } public static String buildRelativePathFromClassNames(String contextPackageName, String classPackageName) { - // path, relative to the root, of the destination class - String[] contextClassPath = contextPackageName.split("\\."); - String[] currClassPath = classPackageName.split("\\."); + // path, relative to the root, of the destination class + String[] contextClassPath = contextPackageName.split("\\."); + String[] currClassPath = classPackageName.split("\\."); - // compute relative path between the context and the destination - // ... first, compute common part - int i = 0, e = Math.min(contextClassPath.length, currClassPath.length); - while (i < e && contextClassPath[i].equals(currClassPath[i])) - i++; - // ... go up with ".." to reach the common root - StringBuilder buf = new StringBuilder(classPackageName.length()); - for (int j = i; j < contextClassPath.length; j++) - buf.append("../"); - // ... go down from the common root to the destination - for (int j = i; j < currClassPath.length; j++) - buf.append(currClassPath[j]).append('/'); // Always use HTML seperators - return buf.toString(); + // compute relative path between the context and the destination + // ... first, compute common part + int i = 0, e = Math.min(contextClassPath.length, currClassPath.length); + while (i < e && contextClassPath[i].equals(currClassPath[i])) + i++; + // ... go up with ".." to reach the common root + StringBuilder buf = new StringBuilder(classPackageName.length()); + for (int j = i; j < contextClassPath.length; j++) + buf.append("../"); + // ... go down from the common root to the destination + for (int j = i; j < currClassPath.length; j++) + buf.append(currClassPath[j]).append('/'); // Always use HTML seperators + return buf.toString(); } /** @@ -199,24 +199,24 @@ class StringUtil { * @return Splitting point (Either referring to a dot, or -1) */ public static int splitPackageClass(String className) { - int gen = className.indexOf('<'); // Begin before generics. - int end = gen >= 0 ? gen : className.length(); - int start = className.lastIndexOf('.', end); - // No package name special cases: - if (start < 0) - return gen >= 0 || className.isEmpty() ? -1 // - : Character.isLowerCase(className.charAt(0)) ? end : -1; - int split = end; - while (true) { - if (Character.isLowerCase(className.charAt(start + 1))) - return split; - split = start; // Continue, this looks like a class name. - if (start < 0) - return -1; - start = className.lastIndexOf('.', start - 1); - } + int gen = className.indexOf('<'); // Begin before generics. + int end = gen >= 0 ? gen : className.length(); + int start = className.lastIndexOf('.', end); + // No package name special cases: + if (start < 0) + return gen >= 0 || className.isEmpty() ? -1 // + : Character.isLowerCase(className.charAt(0)) ? end : -1; + int split = end; + while (true) { + if (Character.isLowerCase(className.charAt(start + 1))) + return split; + split = start; // Continue, this looks like a class name. + if (start < 0) + return -1; + start = className.lastIndexOf('.', start - 1); + } } - + /** * Format a double to a string. *

@@ -226,6 +226,6 @@ class StringUtil { * @return Formatted value */ public static String fmt(double val) { - return val == Math.round(val) ? Long.toString((long) val) : Double.toString(val); + return val == Math.round(val) ? Long.toString((long) val) : Double.toString(val); } } diff --git a/src/main/java/org/umlgraph/doclet/SubclassMatcher.java b/src/main/java/org/umlgraph/doclet/SubclassMatcher.java index 999b823..f9282c6 100644 --- a/src/main/java/org/umlgraph/doclet/SubclassMatcher.java +++ b/src/main/java/org/umlgraph/doclet/SubclassMatcher.java @@ -6,8 +6,8 @@ import com.sun.javadoc.ClassDoc; import com.sun.javadoc.RootDoc; /** - * Matches every class that extends (directly or indirectly) a class - * matched by the regular expression provided. + * Matches every class that extends (directly or indirectly) a class matched by + * the regular expression provided. */ public class SubclassMatcher implements ClassMatcher { @@ -15,22 +15,22 @@ public class SubclassMatcher implements ClassMatcher { protected Pattern pattern; public SubclassMatcher(RootDoc root, Pattern pattern) { - this.root = root; - this.pattern = pattern; + this.root = root; + this.pattern = pattern; } public boolean matches(ClassDoc cd) { - // if it's the class we're looking for return - if(pattern.matcher(cd.toString()).matches()) - return true; - - // recurse on supeclass, if available - return cd.superclass() == null ? false : matches(cd.superclass()); + // if it's the class we're looking for return + if (pattern.matcher(cd.toString()).matches()) + return true; + + // recurse on supeclass, if available + return cd.superclass() == null ? false : matches(cd.superclass()); } public boolean matches(String name) { - ClassDoc cd = root.classNamed(name); - return cd == null ? false : matches(cd); + ClassDoc cd = root.classNamed(name); + return cd == null ? false : matches(cd); } } diff --git a/src/main/java/org/umlgraph/doclet/UMLOptions.java b/src/main/java/org/umlgraph/doclet/UMLOptions.java index b707110..a221134 100644 --- a/src/main/java/org/umlgraph/doclet/UMLOptions.java +++ b/src/main/java/org/umlgraph/doclet/UMLOptions.java @@ -2,8 +2,10 @@ package org.umlgraph.doclet; /** * Options for UMLGraph class diagram generation + * * @opt operations * @opt visibility * @hidden */ -public class UMLOptions {} \ No newline at end of file +public class UMLOptions { +} \ No newline at end of file diff --git a/src/main/java/org/umlgraph/doclet/UmlGraph.java b/src/main/java/org/umlgraph/doclet/UmlGraph.java index edd3825..5bc08a0 100644 --- a/src/main/java/org/umlgraph/doclet/UmlGraph.java +++ b/src/main/java/org/umlgraph/doclet/UmlGraph.java @@ -31,6 +31,7 @@ import com.sun.javadoc.RootDoc; /** * Doclet API implementation + * * @depend - - - OptionProvider * @depend - - - Options * @depend - - - View @@ -50,139 +51,138 @@ public class UmlGraph { /** Entry point through javadoc */ public static boolean start(RootDoc root) throws IOException { - Options opt = buildOptions(root); - root.printNotice("UMLGraph doclet version " + Version.VERSION + " started"); + Options opt = buildOptions(root); + root.printNotice("UMLGraph doclet version " + Version.VERSION + " started"); - View[] views = buildViews(opt, root, root); - if(views == null) - return false; - if (views.length == 0) - buildGraph(root, opt, null); - else - for (int i = 0; i < views.length; i++) - buildGraph(root, views[i], null); - return true; + View[] views = buildViews(opt, root, root); + if (views == null) + return false; + if (views.length == 0) + buildGraph(root, opt, null); + else + for (int i = 0; i < views.length; i++) + buildGraph(root, views[i], null); + return true; } public static void main(String args[]) { - PrintWriter err = new PrintWriter(System.err); - com.sun.tools.javadoc.Main.execute(programName, - err, err, err, docletName, args); + PrintWriter err = new PrintWriter(System.err); + com.sun.tools.javadoc.Main.execute(programName, err, err, err, docletName, args); } public static Options getCommentOptions() { - return commentOptions; + return commentOptions; } /** - * Creates the base Options object. - * This contains both the options specified on the command - * line and the ones specified in the UMLOptions class, if available. - * Also create the globally accessible commentOptions object. + * Creates the base Options object. This contains both the options specified on + * the command line and the ones specified in the UMLOptions class, if + * available. Also create the globally accessible commentOptions object. */ public static Options buildOptions(RootDoc root) { - commentOptions = new Options(); - commentOptions.setOptions(root.options()); - commentOptions.setOptions(findClass(root, "UMLNoteOptions")); - commentOptions.shape = Shape.NOTE; + commentOptions = new Options(); + commentOptions.setOptions(root.options()); + commentOptions.setOptions(findClass(root, "UMLNoteOptions")); + commentOptions.shape = Shape.NOTE; - Options opt = new Options(); - opt.setOptions(root.options()); - opt.setOptions(findClass(root, "UMLOptions")); - return opt; + Options opt = new Options(); + opt.setOptions(root.options()); + opt.setOptions(findClass(root, "UMLOptions")); + return opt; } /** Return the ClassDoc for the specified class; null if not found. */ private static ClassDoc findClass(RootDoc root, String name) { - ClassDoc[] classes = root.classes(); - for (ClassDoc cd : classes) - if(cd.name().equals(name)) - return cd; - return null; + ClassDoc[] classes = root.classes(); + for (ClassDoc cd : classes) + if (cd.name().equals(name)) + return cd; + return null; } /** * Builds and outputs a single graph according to the view overrides */ public static void buildGraph(RootDoc root, OptionProvider op, Doc contextDoc) throws IOException { - if(getCommentOptions() == null) - buildOptions(root); - Options opt = op.getGlobalOptions(); - root.printNotice("Building " + op.getDisplayName()); - ClassDoc[] classes = root.classes(); + if (getCommentOptions() == null) + buildOptions(root); + Options opt = op.getGlobalOptions(); + root.printNotice("Building " + op.getDisplayName()); + ClassDoc[] classes = root.classes(); - ClassGraph c = new ClassGraph(root, op, contextDoc); - c.prologue(); - for (ClassDoc cd : classes) - c.printClass(cd, true); - for (ClassDoc cd : classes) - c.printRelations(cd); - if(opt.inferRelationships) - for (ClassDoc cd : classes) - c.printInferredRelations(cd); - if(opt.inferDependencies) - for (ClassDoc cd : classes) - c.printInferredDependencies(cd); + ClassGraph c = new ClassGraph(root, op, contextDoc); + c.prologue(); + for (ClassDoc cd : classes) + c.printClass(cd, true); + for (ClassDoc cd : classes) + c.printRelations(cd); + if (opt.inferRelationships) + for (ClassDoc cd : classes) + c.printInferredRelations(cd); + if (opt.inferDependencies) + for (ClassDoc cd : classes) + c.printInferredDependencies(cd); - c.printExtraClasses(root); - c.epilogue(); + c.printExtraClasses(root); + c.epilogue(); } /** * Builds the views according to the parameters on the command line - * @param opt The options - * @param srcRootDoc The RootDoc for the source classes - * @param viewRootDoc The RootDoc for the view classes (may be - * different, or may be the same as the srcRootDoc) + * + * @param opt The options + * @param srcRootDoc The RootDoc for the source classes + * @param viewRootDoc The RootDoc for the view classes (may be different, or may + * be the same as the srcRootDoc) */ public static View[] buildViews(Options opt, RootDoc srcRootDoc, RootDoc viewRootDoc) { - if (opt.viewName != null) { - ClassDoc viewClass = viewRootDoc.classNamed(opt.viewName); - if(viewClass == null) { - System.out.println("View " + opt.viewName + " not found! Exiting without generating any output."); - return null; - } - if(viewClass.tags("view").length == 0) { - System.out.println(viewClass + " is not a view!"); - return null; - } - if(viewClass.isAbstract()) { - System.out.println(viewClass + " is an abstract view, no output will be generated!"); - return null; - } - return new View[] { buildView(srcRootDoc, viewClass, opt) }; - } else if (opt.findViews) { - List views = new ArrayList(); - ClassDoc[] classes = viewRootDoc.classes(); + if (opt.viewName != null) { + ClassDoc viewClass = viewRootDoc.classNamed(opt.viewName); + if (viewClass == null) { + System.out.println("View " + opt.viewName + " not found! Exiting without generating any output."); + return null; + } + if (viewClass.tags("view").length == 0) { + System.out.println(viewClass + " is not a view!"); + return null; + } + if (viewClass.isAbstract()) { + System.out.println(viewClass + " is an abstract view, no output will be generated!"); + return null; + } + return new View[] { buildView(srcRootDoc, viewClass, opt) }; + } else if (opt.findViews) { + List views = new ArrayList(); + ClassDoc[] classes = viewRootDoc.classes(); - // find view classes - for (int i = 0; i < classes.length; i++) - if (classes[i].tags("view").length > 0 && !classes[i].isAbstract()) - views.add(buildView(srcRootDoc, classes[i], opt)); + // find view classes + for (int i = 0; i < classes.length; i++) + if (classes[i].tags("view").length > 0 && !classes[i].isAbstract()) + views.add(buildView(srcRootDoc, classes[i], opt)); - return views.toArray(new View[views.size()]); - } else - return new View[0]; + return views.toArray(new View[views.size()]); + } else + return new View[0]; } /** * Builds a view along with its parent views, recursively */ private static View buildView(RootDoc root, ClassDoc viewClass, OptionProvider provider) { - ClassDoc superClass = viewClass.superclass(); - if(superClass == null || superClass.tags("view").length == 0) - return new View(root, viewClass, provider); + ClassDoc superClass = viewClass.superclass(); + if (superClass == null || superClass.tags("view").length == 0) + return new View(root, viewClass, provider); - return new View(root, viewClass, buildView(root, superClass, provider)); + return new View(root, viewClass, buildView(root, superClass, provider)); } /** Option checking */ public static int optionLength(String option) { - return Options.optionLength(option); + return Options.optionLength(option); } /** Indicate the language version we support */ public static LanguageVersion languageVersion() { - return LanguageVersion.JAVA_1_5; + return LanguageVersion.JAVA_1_5; } } diff --git a/src/main/java/org/umlgraph/doclet/UmlGraphDoc.java b/src/main/java/org/umlgraph/doclet/UmlGraphDoc.java index dca406f..a22c021 100644 --- a/src/main/java/org/umlgraph/doclet/UmlGraphDoc.java +++ b/src/main/java/org/umlgraph/doclet/UmlGraphDoc.java @@ -23,6 +23,7 @@ import com.sun.tools.doclets.standard.Standard; /** * Chaining doclet that runs the standart Javadoc doclet first, and on success, * runs the generation of dot files by UMLGraph + * * @author wolf * * @depend - - - WrappedClassDoc @@ -30,81 +31,81 @@ import com.sun.tools.doclets.standard.Standard; */ public class UmlGraphDoc { /** - * Option check, forwards options to the standard doclet, if that one refuses them, - * they are sent to UmlGraph + * Option check, forwards options to the standard doclet, if that one refuses + * them, they are sent to UmlGraph */ public static int optionLength(String option) { - int result = Standard.optionLength(option); - if (result != 0) - return result; - else - return UmlGraph.optionLength(option); + int result = Standard.optionLength(option); + if (result != 0) + return result; + else + return UmlGraph.optionLength(option); } /** * Standard doclet entry point + * * @param root * @return */ public static boolean start(RootDoc root) { - root.printNotice("UmlGraphDoc version " + Version.VERSION + ", running the standard doclet"); - Standard.start(root); - root.printNotice("UmlGraphDoc version " + Version.VERSION + ", altering javadocs"); - try { - String outputFolder = findOutputPath(root.options()); + root.printNotice("UmlGraphDoc version " + Version.VERSION + ", running the standard doclet"); + Standard.start(root); + root.printNotice("UmlGraphDoc version " + Version.VERSION + ", altering javadocs"); + try { + String outputFolder = findOutputPath(root.options()); - Options opt = UmlGraph.buildOptions(root); - opt.setOptions(root.options()); - // in javadoc enumerations are always printed - opt.showEnumerations = true; - opt.relativeLinksForSourcePackages = true; - // enable strict matching for hide expressions - opt.strictMatching = true; + Options opt = UmlGraph.buildOptions(root); + opt.setOptions(root.options()); + // in javadoc enumerations are always printed + opt.showEnumerations = true; + opt.relativeLinksForSourcePackages = true; + // enable strict matching for hide expressions + opt.strictMatching = true; // root.printNotice(opt.toString()); - generatePackageDiagrams(root, opt, outputFolder); - generateContextDiagrams(root, opt, outputFolder); - } catch(Throwable t) { - root.printWarning("Error: " + t.toString()); - t.printStackTrace(); - return false; - } - return true; + generatePackageDiagrams(root, opt, outputFolder); + generateContextDiagrams(root, opt, outputFolder); + } catch (Throwable t) { + root.printWarning("Error: " + t.toString()); + t.printStackTrace(); + return false; + } + return true; } /** * Standand doclet entry + * * @return */ public static LanguageVersion languageVersion() { - return Standard.languageVersion(); + return Standard.languageVersion(); } /** - * Generates the package diagrams for all of the packages that contain classes among those - * returned by RootDoc.class() + * Generates the package diagrams for all of the packages that contain classes + * among those returned by RootDoc.class() */ - private static void generatePackageDiagrams(RootDoc root, Options opt, String outputFolder) - throws IOException { - Set packages = new HashSet(); - for (ClassDoc classDoc : root.classes()) { - PackageDoc packageDoc = classDoc.containingPackage(); - if(!packages.contains(packageDoc.name())) { - packages.add(packageDoc.name()); - OptionProvider view = new PackageView(outputFolder, packageDoc, root, opt); - UmlGraph.buildGraph(root, view, packageDoc); - runGraphviz(opt.dotExecutable, outputFolder, packageDoc.name(), packageDoc.name(), root); - alterHtmlDocs(opt, outputFolder, packageDoc.name(), packageDoc.name(), - "package-summary.html", Pattern.compile("()|(

packages = new HashSet(); + for (ClassDoc classDoc : root.classes()) { + PackageDoc packageDoc = classDoc.containingPackage(); + if (!packages.contains(packageDoc.name())) { + packages.add(packageDoc.name()); + OptionProvider view = new PackageView(outputFolder, packageDoc, root, opt); + UmlGraph.buildGraph(root, view, packageDoc); + runGraphviz(opt.dotExecutable, outputFolder, packageDoc.name(), packageDoc.name(), root); + alterHtmlDocs(opt, outputFolder, packageDoc.name(), packageDoc.name(), "package-summary.html", + Pattern.compile("()|(

classDocs = new TreeSet(new Comparator() { public int compare(ClassDoc cd1, ClassDoc cd2) { return cd1.name().compareTo(cd2.name()); @@ -113,158 +114,143 @@ public class UmlGraphDoc { for (ClassDoc classDoc : root.classes()) classDocs.add(classDoc); - ContextView view = null; - for (ClassDoc classDoc : classDocs) { - try { - if(view == null) - view = new ContextView(outputFolder, classDoc, root, opt); - else - view.setContextCenter(classDoc); - UmlGraph.buildGraph(root, view, classDoc); - runGraphviz(opt.dotExecutable, outputFolder, classDoc.containingPackage().name(), classDoc.name(), root); - alterHtmlDocs(opt, outputFolder, classDoc.containingPackage().name(), classDoc.name(), - classDoc.name() + ".html", Pattern.compile(".*(Class|Interface|Enum) " + classDoc.name() + ".*") , root); - } catch (Exception e) { - throw new RuntimeException("Error generating " + classDoc.name(), e); - } - } + ContextView view = null; + for (ClassDoc classDoc : classDocs) { + try { + if (view == null) + view = new ContextView(outputFolder, classDoc, root, opt); + else + view.setContextCenter(classDoc); + UmlGraph.buildGraph(root, view, classDoc); + runGraphviz(opt.dotExecutable, outputFolder, classDoc.containingPackage().name(), classDoc.name(), + root); + alterHtmlDocs(opt, outputFolder, classDoc.containingPackage().name(), classDoc.name(), + classDoc.name() + ".html", + Pattern.compile(".*(Class|Interface|Enum) " + classDoc.name() + ".*"), root); + } catch (Exception e) { + throw new RuntimeException("Error generating " + classDoc.name(), e); + } + } } /** - * Runs Graphviz dot building both a diagram (in png format) and a client side map for it. + * Runs Graphviz dot building both a diagram (in png format) and a client side + * map for it. */ - private static void runGraphviz(String dotExecutable, String outputFolder, String packageName, String name, RootDoc root) { - if (dotExecutable == null) { - dotExecutable = "dot"; - } - File dotFile = new File(outputFolder, packageName.replace(".", "/") + "/" + name + ".dot"); - File svgFile = new File(outputFolder, packageName.replace(".", "/") + "/" + name + ".svg"); + private static void runGraphviz(String dotExecutable, String outputFolder, String packageName, String name, + RootDoc root) { + if (dotExecutable == null) { + dotExecutable = "dot"; + } + File dotFile = new File(outputFolder, packageName.replace(".", "/") + "/" + name + ".dot"); + File svgFile = new File(outputFolder, packageName.replace(".", "/") + "/" + name + ".svg"); - try { - Process p = Runtime.getRuntime().exec(new String [] { - dotExecutable, - "-Tsvg", - "-o", - svgFile.getAbsolutePath(), - dotFile.getAbsolutePath() - }); - BufferedReader reader = new BufferedReader(new InputStreamReader(p.getErrorStream())); - String line; - while((line = reader.readLine()) != null) - root.printWarning(line); - int result = p.waitFor(); - if (result != 0) - root.printWarning("Errors running Graphviz on " + dotFile); - } catch (Exception e) { - e.printStackTrace(); - System.err.println("Ensure that dot is in your path and that its path does not contain spaces"); - } + try { + Process p = Runtime.getRuntime().exec(new String[] { dotExecutable, "-Tsvg", "-o", + svgFile.getAbsolutePath(), dotFile.getAbsolutePath() }); + BufferedReader reader = new BufferedReader(new InputStreamReader(p.getErrorStream())); + String line; + while ((line = reader.readLine()) != null) + root.printWarning(line); + int result = p.waitFor(); + if (result != 0) + root.printWarning("Errors running Graphviz on " + dotFile); + } catch (Exception e) { + e.printStackTrace(); + System.err.println("Ensure that dot is in your path and that its path does not contain spaces"); + } } - //Format string for the uml image div tag. - private static final String UML_DIV_TAG = - "
" + - "" + - "
"; - - private static final String UML_AUTO_SIZED_DIV_TAG = - "
" + - "" + - "
"; - + // Format string for the uml image div tag. + private static final String UML_DIV_TAG = "
" + + "" + + "
"; + + private static final String UML_AUTO_SIZED_DIV_TAG = "
" + + "" + + "
"; + private static final String EXPANDABLE_UML_STYLE = "font-family: Arial,Helvetica,sans-serif;font-size: 1.5em; display: block; width: 250px; height: 20px; background: #009933; padding: 5px; text-align: center; border-radius: 8px; color: white; font-weight: bold;"; - //Format string for the java script tag. - private static final String EXPANDABLE_UML = - "\n" + - "
\n" + - " \n" + - " %2$s \n" + - "
"; - + // Format string for the java script tag. + private static final String EXPANDABLE_UML = "\n" + "
\n" + + " \n" + " %2$s \n" + "
"; + /** - * Takes an HTML file, looks for the first instance of the specified insertion point, and - * inserts the diagram image reference and a client side map in that point. + * Takes an HTML file, looks for the first instance of the specified insertion + * point, and inserts the diagram image reference and a client side map in that + * point. */ private static void alterHtmlDocs(Options opt, String outputFolder, String packageName, String className, - String htmlFileName, Pattern insertPointPattern, RootDoc root) throws IOException { - // setup files - File output = new File(outputFolder, packageName.replace(".", "/")); - File htmlFile = new File(output, htmlFileName); - File alteredFile = new File(htmlFile.getAbsolutePath() + ".uml"); - if (!htmlFile.exists()) { - System.err.println("Expected file not found: " + htmlFile.getAbsolutePath()); - return; - } + String htmlFileName, Pattern insertPointPattern, RootDoc root) throws IOException { + // setup files + File output = new File(outputFolder, packageName.replace(".", "/")); + File htmlFile = new File(output, htmlFileName); + File alteredFile = new File(htmlFile.getAbsolutePath() + ".uml"); + if (!htmlFile.exists()) { + System.err.println("Expected file not found: " + htmlFile.getAbsolutePath()); + return; + } - // parse & rewrite - BufferedWriter writer = null; - BufferedReader reader = null; - boolean matched = false; - try { - writer = new BufferedWriter(new OutputStreamWriter(new - FileOutputStream(alteredFile), opt.outputEncoding)); - reader = new BufferedReader(new InputStreamReader(new - FileInputStream(htmlFile), opt.outputEncoding)); + // parse & rewrite + BufferedWriter writer = null; + BufferedReader reader = null; + boolean matched = false; + try { + writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(alteredFile), opt.outputEncoding)); + reader = new BufferedReader(new InputStreamReader(new FileInputStream(htmlFile), opt.outputEncoding)); - String line; - while ((line = reader.readLine()) != null) { - writer.write(line); - writer.newLine(); - if (!matched && insertPointPattern.matcher(line).matches()) { - matched = true; - - String tag; - if (opt.autoSize) - tag = String.format(UML_AUTO_SIZED_DIV_TAG, className); - else - tag = String.format(UML_DIV_TAG, className); - if (opt.collapsibleDiagrams) - tag = String.format(EXPANDABLE_UML, tag, "Show UML class diagram", "Hide UML class diagram"); - writer.write(""); - writer.newLine(); - writer.write(tag); - writer.newLine(); - } - } - } finally { - if (writer != null) - writer.close(); - if (reader != null) - reader.close(); - } + String line; + while ((line = reader.readLine()) != null) { + writer.write(line); + writer.newLine(); + if (!matched && insertPointPattern.matcher(line).matches()) { + matched = true; - // if altered, delete old file and rename new one to the old file name - if (matched) { - htmlFile.delete(); - alteredFile.renameTo(htmlFile); - } else { - root.printNotice("Warning, could not find a line that matches the pattern '" + insertPointPattern.pattern() - + "'.\n Class diagram reference not inserted"); - alteredFile.delete(); - } + String tag; + if (opt.autoSize) + tag = String.format(UML_AUTO_SIZED_DIV_TAG, className); + else + tag = String.format(UML_DIV_TAG, className); + if (opt.collapsibleDiagrams) + tag = String.format(EXPANDABLE_UML, tag, "Show UML class diagram", "Hide UML class diagram"); + writer.write(""); + writer.newLine(); + writer.write(tag); + writer.newLine(); + } + } + } finally { + if (writer != null) + writer.close(); + if (reader != null) + reader.close(); + } + + // if altered, delete old file and rename new one to the old file name + if (matched) { + htmlFile.delete(); + alteredFile.renameTo(htmlFile); + } else { + root.printNotice("Warning, could not find a line that matches the pattern '" + + insertPointPattern.pattern() + "'.\n Class diagram reference not inserted"); + alteredFile.delete(); + } } /** * Returns the output path specified on the javadoc options */ private static String findOutputPath(String[][] options) { - for (int i = 0; i < options.length; i++) { - if (options[i][0].equals("-d")) - return options[i][1]; - } - return "."; + for (int i = 0; i < options.length; i++) { + if (options[i][0].equals("-d")) + return options[i][1]; + } + return "."; } } diff --git a/src/main/java/org/umlgraph/doclet/Version.java b/src/main/java/org/umlgraph/doclet/Version.java index 03f857d..36dab1a 100644 --- a/src/main/java/org/umlgraph/doclet/Version.java +++ b/src/main/java/org/umlgraph/doclet/Version.java @@ -1,4 +1,6 @@ /* Automatically generated file */ package org.umlgraph.doclet; -class Version { public static String VERSION = "R5_7_2-60-g0e99a6";} - \ No newline at end of file + +class Version { + public static String VERSION = "R5_7_2-60-g0e99a6"; +} diff --git a/src/main/java/org/umlgraph/doclet/View.java b/src/main/java/org/umlgraph/doclet/View.java index 8659a1c..f3b2dd4 100644 --- a/src/main/java/org/umlgraph/doclet/View.java +++ b/src/main/java/org/umlgraph/doclet/View.java @@ -32,6 +32,7 @@ import com.sun.javadoc.Tag; * will lead to the creation of a UML class diagram. Multiple views can be * defined on the same source tree, effectively allowing to create multiple * class diagram out of it. + * * @author wolf * * @depend - - - Options @@ -53,121 +54,116 @@ public class View implements OptionProvider { * Builds a view given the class that contains its definition */ public View(RootDoc root, ClassDoc c, OptionProvider provider) { - this.viewDoc = c; - this.provider = provider; - this.root = root; - Tag[] tags = c.tags(); - ClassMatcher currMatcher = null; - // parse options, get the global ones, and build a map of the - // pattern matched overrides - globalOptions = new ArrayList(); - for (int i = 0; i < tags.length; i++) { - if (tags[i].name().equals("@match")) { - currMatcher = buildMatcher(tags[i].text()); - if(currMatcher != null) { - optionOverrides.put(currMatcher, new ArrayList()); - } - } else if (tags[i].name().equals("@opt")) { - String[] opts = StringUtil.tokenize(tags[i].text()); - opts[0] = "-" + opts[0]; - if (currMatcher == null) { - globalOptions.add(opts); - } else { - optionOverrides.get(currMatcher).add(opts); - } - } - } + this.viewDoc = c; + this.provider = provider; + this.root = root; + Tag[] tags = c.tags(); + ClassMatcher currMatcher = null; + // parse options, get the global ones, and build a map of the + // pattern matched overrides + globalOptions = new ArrayList(); + for (int i = 0; i < tags.length; i++) { + if (tags[i].name().equals("@match")) { + currMatcher = buildMatcher(tags[i].text()); + if (currMatcher != null) { + optionOverrides.put(currMatcher, new ArrayList()); + } + } else if (tags[i].name().equals("@opt")) { + String[] opts = StringUtil.tokenize(tags[i].text()); + opts[0] = "-" + opts[0]; + if (currMatcher == null) { + globalOptions.add(opts); + } else { + optionOverrides.get(currMatcher).add(opts); + } + } + } } - + /** * Factory method that builds the appropriate matcher for @match tags */ private ClassMatcher buildMatcher(String tagText) { - // check there are at least @match and a parameter - String[] strings = StringUtil.tokenize(tagText); - if (strings.length < 2) { - System.err.println("Skipping uncomplete @match tag, type missing: " + tagText + " in view " + viewDoc); - return null; - } - - try { - if (strings[0].equals("class")) { - return new PatternMatcher(Pattern.compile(strings[1])); - } else if (strings[0].equals("context")) { - return new ContextMatcher(root, Pattern.compile(strings[1]), getGlobalOptions(), - false); - } else if (strings[0].equals("outgoingContext")) { - return new ContextMatcher(root, Pattern.compile(strings[1]), getGlobalOptions(), - false); - } else if (strings[0].equals("interface")) { - return new InterfaceMatcher(root, Pattern.compile(strings[1])); - } else if (strings[0].equals("subclass")) { - return new SubclassMatcher(root, Pattern.compile(strings[1])); - } else { - System.err.println("Skipping @match tag, unknown match type, in view " + viewDoc); - } - } catch (PatternSyntaxException pse) { - System.err.println("Skipping @match tag due to invalid regular expression '" + tagText - + "'" + " in view " + viewDoc); - } catch (Exception e) { - System.err.println("Skipping @match tag due to an internal error '" + tagText - + "'" + " in view " + viewDoc); - e.printStackTrace(); - } - return null; - } - + // check there are at least @match and a parameter + String[] strings = StringUtil.tokenize(tagText); + if (strings.length < 2) { + System.err.println("Skipping uncomplete @match tag, type missing: " + tagText + " in view " + viewDoc); + return null; + } - // ---------------------------------------------------------------- + try { + if (strings[0].equals("class")) { + return new PatternMatcher(Pattern.compile(strings[1])); + } else if (strings[0].equals("context")) { + return new ContextMatcher(root, Pattern.compile(strings[1]), getGlobalOptions(), false); + } else if (strings[0].equals("outgoingContext")) { + return new ContextMatcher(root, Pattern.compile(strings[1]), getGlobalOptions(), false); + } else if (strings[0].equals("interface")) { + return new InterfaceMatcher(root, Pattern.compile(strings[1])); + } else if (strings[0].equals("subclass")) { + return new SubclassMatcher(root, Pattern.compile(strings[1])); + } else { + System.err.println("Skipping @match tag, unknown match type, in view " + viewDoc); + } + } catch (PatternSyntaxException pse) { + System.err.println("Skipping @match tag due to invalid regular expression '" + tagText + "'" + " in view " + viewDoc); + } catch (Exception e) { + System.err.println("Skipping @match tag due to an internal error '" + tagText + "'" + " in view " + viewDoc); + e.printStackTrace(); + } + return null; + } + + // ---------------------------------------------------------------- // OptionProvider methods - // ---------------------------------------------------------------- + // ---------------------------------------------------------------- public Options getOptionsFor(ClassDoc cd) { - Options localOpt = getGlobalOptions(); - overrideForClass(localOpt, cd); - localOpt.setOptions(cd); - return localOpt; + Options localOpt = getGlobalOptions(); + overrideForClass(localOpt, cd); + localOpt.setOptions(cd); + return localOpt; } public Options getOptionsFor(String name) { - Options localOpt = getGlobalOptions(); - overrideForClass(localOpt, name); - return localOpt; + Options localOpt = getGlobalOptions(); + overrideForClass(localOpt, name); + return localOpt; } public Options getGlobalOptions() { - Options go = provider.getGlobalOptions(); - - boolean outputSet = false; - for (String[] opts : globalOptions) { - if (Options.matchOption(opts[0], "output")) - outputSet = true; - go.setOption(opts); - } - if (!outputSet) - go.setOption(new String[] { "output", viewDoc.name() + ".dot" }); - - return go; + Options go = provider.getGlobalOptions(); + + boolean outputSet = false; + for (String[] opts : globalOptions) { + if (Options.matchOption(opts[0], "output")) + outputSet = true; + go.setOption(opts); + } + if (!outputSet) + go.setOption(new String[] { "output", viewDoc.name() + ".dot" }); + + return go; } public void overrideForClass(Options opt, ClassDoc cd) { - provider.overrideForClass(opt, cd); - for (ClassMatcher cm : optionOverrides.keySet()) - if(cm.matches(cd)) - for (String[] override : optionOverrides.get(cm)) - opt.setOption(override); + provider.overrideForClass(opt, cd); + for (ClassMatcher cm : optionOverrides.keySet()) + if (cm.matches(cd)) + for (String[] override : optionOverrides.get(cm)) + opt.setOption(override); } public void overrideForClass(Options opt, String className) { - provider.overrideForClass(opt, className); - for (ClassMatcher cm : optionOverrides.keySet()) - if(cm.matches(className)) - for (String[] override : optionOverrides.get(cm)) - opt.setOption(override); + provider.overrideForClass(opt, className); + for (ClassMatcher cm : optionOverrides.keySet()) + if (cm.matches(className)) + for (String[] override : optionOverrides.get(cm)) + opt.setOption(override); } public String getDisplayName() { - return "view " + viewDoc.name(); + return "view " + viewDoc.name(); } } diff --git a/src/main/java/org/umlgraph/doclet/Visibility.java b/src/main/java/org/umlgraph/doclet/Visibility.java index 408a551..831d64b 100644 --- a/src/main/java/org/umlgraph/doclet/Visibility.java +++ b/src/main/java/org/umlgraph/doclet/Visibility.java @@ -23,6 +23,7 @@ import com.sun.javadoc.ProgramElementDoc; /** * Enumerates the possible visibilities in a Java program. For brevity, package * private visibility is referred as PACKAGE. + * * @author wolf */ public enum Visibility { @@ -31,17 +32,17 @@ public enum Visibility { final public String symbol; private Visibility(String symbol) { - this.symbol = symbol; + this.symbol = symbol; } public static Visibility get(ProgramElementDoc doc) { - if (doc.isPrivate()) - return PRIVATE; - else if (doc.isPackagePrivate()) - return PACKAGE; - else if (doc.isProtected()) - return PROTECTED; - else - return PUBLIC; + if (doc.isPrivate()) + return PRIVATE; + else if (doc.isPackagePrivate()) + return PACKAGE; + else if (doc.isProtected()) + return PROTECTED; + else + return PUBLIC; } }