From 14b80c0eabd1fc7a10dc4ceee3bb359d04f15d5f Mon Sep 17 00:00:00 2001 From: Andrea Aime Date: Sun, 2 Jul 2006 16:23:39 +0000 Subject: [PATCH] Introduced explicit enums for relation types and relation directions, added an option to specify the direction and type of relations included in the context (basically, a tool to build a map from relation type to direction), fixed a test that still contained the old -inferassoc intestead of -inferrel --- .../spinellis/umlgraph/doclet/ClassInfo.java | 20 +++++--- .../umlgraph/doclet/ContextMatcher.java | 33 ++++++------ src/gr/spinellis/umlgraph/doclet/Options.java | 51 +++++++++++++------ .../umlgraph/doclet/RelationDirection.java | 51 +++++++++++++++++++ .../umlgraph/doclet/RelationPattern.java | 50 ++++++++++++++++++ .../umlgraph/doclet/RelationType.java | 10 ++++ src/gr/spinellis/umlgraph/doclet/View.java | 3 ++ .../spinellis/umlgraph/doclet/Visibility.java | 16 +----- src/org/umlgraph/doclet/ClassInfo.java | 20 +++++--- src/org/umlgraph/doclet/ContextMatcher.java | 33 ++++++------ src/org/umlgraph/doclet/Options.java | 51 +++++++++++++------ .../umlgraph/doclet/RelationDirection.java | 51 +++++++++++++++++++ src/org/umlgraph/doclet/RelationPattern.java | 50 ++++++++++++++++++ src/org/umlgraph/doclet/RelationType.java | 10 ++++ src/org/umlgraph/doclet/View.java | 3 ++ src/org/umlgraph/doclet/Visibility.java | 16 +----- testdata/dot-ref/Inference.dot | 40 ++++++++------- testdata/java/Inference.java | 4 +- 18 files changed, 385 insertions(+), 127 deletions(-) create mode 100644 src/gr/spinellis/umlgraph/doclet/RelationDirection.java create mode 100644 src/gr/spinellis/umlgraph/doclet/RelationPattern.java create mode 100644 src/gr/spinellis/umlgraph/doclet/RelationType.java create mode 100644 src/org/umlgraph/doclet/RelationDirection.java create mode 100644 src/org/umlgraph/doclet/RelationPattern.java create mode 100644 src/org/umlgraph/doclet/RelationType.java diff --git a/src/gr/spinellis/umlgraph/doclet/ClassInfo.java b/src/gr/spinellis/umlgraph/doclet/ClassInfo.java index 500a7c2..045194c 100644 --- a/src/gr/spinellis/umlgraph/doclet/ClassInfo.java +++ b/src/gr/spinellis/umlgraph/doclet/ClassInfo.java @@ -20,8 +20,9 @@ package gr.spinellis.umlgraph.doclet; -import java.util.HashSet; -import java.util.Set; +import java.util.HashMap; +import java.util.List; +import java.util.Map; /** * Class's dot-comaptible alias name (for fully qualified class names) @@ -42,7 +43,7 @@ class ClassInfo { * all the classes linked with a bi-directional relation , and the ones * referred by a directed relation */ - Set relatedClasses = new HashSet(); + Map relatedClasses = new HashMap(); ClassInfo(boolean p, boolean h) { nodePrinted = p; @@ -51,12 +52,17 @@ class ClassInfo { classNumber++; } - public void addRelation(String dest) { - relatedClasses.add(dest); + 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); } - public boolean isRelated(String dest) { - return relatedClasses.contains(dest); + public RelationPattern getRelation(String dest) { + return relatedClasses.get(dest); } /** Start numbering from zero. */ diff --git a/src/gr/spinellis/umlgraph/doclet/ContextMatcher.java b/src/gr/spinellis/umlgraph/doclet/ContextMatcher.java index 53d212e..d0569d2 100644 --- a/src/gr/spinellis/umlgraph/doclet/ContextMatcher.java +++ b/src/gr/spinellis/umlgraph/doclet/ContextMatcher.java @@ -32,13 +32,13 @@ import com.sun.javadoc.RootDoc; /** * Matches classes that are directly connected to one of the classes matched by - * the regual expression specified. The context center is computed by regex lookup. - * Depending on the specified Options, inferred relations and dependencies will - * be used as well. + * the regual expression specified. The context center is computed by regex + * lookup. Depending on the specified Options, inferred relations and + * dependencies will be used as well. *

* 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 + * you * @author wolf * * @depend - - - DevNullWriter @@ -61,6 +61,10 @@ public class ContextMatcher implements ClassMatcher { * @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 fullContext If true, all the classes related to the context + * center will be included, otherwise it will match only + * the classes referred with an outgoing relation from + * the context center * @throws IOException */ public ContextMatcher(RootDoc root, Pattern pattern, Options options, boolean keepParentHide) throws IOException { @@ -68,14 +72,14 @@ public class ContextMatcher implements ClassMatcher { 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"}); + opt.setOption(new String[] { "-!hide" }); + opt.setOption(new String[] { "-!attributes" }); + opt.setOption(new String[] { "-!operations" }); this.cg = new ClassGraphHack(root, opt); setContextCenter(pattern); } - + /** * Can be used to setup a different pattern for this context matcher. *

@@ -103,11 +107,12 @@ public class ContextMatcher implements ClassMatcher { * @param cd */ private void addToGraph(ClassDoc cd) { - // avoid adding twice the same class, but don't rely on cg.getClassInfo since there + // 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())) + if (visited.contains(cd.toString())) return; - + visited.add(cd.toString()); cg.printClass(cd, false); cg.printRelations(cd); @@ -146,10 +151,8 @@ public class ContextMatcher implements ClassMatcher { for (ClassDoc mcd : matched) { String mcName = mcd.toString(); ClassInfo ciMatched = cg.getClassInfo(mcName); - if (ciMatched != null && ciMatched.isRelated(name)) - return true; - ClassInfo ci = cg.getClassInfo(name); - if (ci != null && ci.isRelated(mcName)) + RelationPattern rp = ciMatched.getRelation(name); + if (ciMatched != null && rp != null && opt.contextRelationPattern.matchesOne(rp)) return true; } return false; diff --git a/src/gr/spinellis/umlgraph/doclet/Options.java b/src/gr/spinellis/umlgraph/doclet/Options.java index ff855e4..29feec8 100644 --- a/src/gr/spinellis/umlgraph/doclet/Options.java +++ b/src/gr/spinellis/umlgraph/doclet/Options.java @@ -109,11 +109,12 @@ public class Options implements Cloneable, OptionProvider { String guilClose = "»"; // "\u00bb"; boolean inferRelationships; boolean inferDependencies; + RelationPattern contextRelationPattern; boolean useImports; Visibility inferDendencyVisibility; boolean inferDepInPackage; boolean verbose2; - String inferRelationshipType; + RelationType inferRelationshipType; private Vector collPackages; boolean compact; // internal option, used by UMLDoc to generate relative links between classes @@ -161,12 +162,13 @@ public class Options implements Cloneable, OptionProvider { useGuillemot = true; findViews = false; viewName = null; + contextRelationPattern = new RelationPattern(RelationDirection.BOTH); inferRelationships = false; inferDependencies = false; inferDendencyVisibility = Visibility.PRIVATE; inferDepInPackage = false; useImports = false; - inferRelationshipType = "navassoc"; + inferRelationshipType = RelationType.NAVASSOC; collPackages = new Vector(); compact = false; relativeLinksForSourcePackages = false; @@ -220,6 +222,7 @@ public class Options implements Cloneable, OptionProvider { option.equals("-useimports") || option.equals("-inferdep") || option.equals("-inferdepinpackage") || + option.equals("-fullContext") || option.equals("-verbose2") || option.equals("-compact")) @@ -251,9 +254,10 @@ public class Options implements Cloneable, OptionProvider { option.equals("-inferreltype") || option.equals("-inferdepvis") || option.equals("-collpackages") || - option.equals("-link") - ) + option.equals("-link")) return 2; + else if(option.equals("-contextPattern")) + return 3; else return 0; } @@ -423,22 +427,23 @@ public class Options implements Cloneable, OptionProvider { } else if(opt[0].equals("-!inferrel")) { inferRelationships = false; } else if(opt[0].equals("-inferreltype")) { - if(ClassGraph.associationMap.containsKey(opt[1])) { - inferRelationshipType = opt[1]; - } else { - System.err.println("Unknown association type " + opt[1]); - } + try { + inferRelationshipType = RelationType.valueOf(opt[1].toUpperCase()); + } catch(IllegalArgumentException e) { + System.err.println("Unknown association type " + opt[1]); + } } else if(opt[0].equals("-!inferreltype")) { - inferRelationshipType = "navassoc"; + inferRelationshipType = RelationType.NAVASSOC; } else if(opt[0].equals("-inferdepvis")) { - Visibility vis = Visibility.parseVisibility(opt[1]); - if(vis == null) - System.err.println("Ignoring invalid visibility specification for dependency inference" + vis); - inferDendencyVisibility = Visibility.PRIVATE; + try { + Visibility vis = Visibility.valueOf(opt[1].toUpperCase()); + inferDendencyVisibility = vis; + } catch(IllegalArgumentException e) { + System.err.println("Ignoring invalid visibility specification for " + + "dependency inference: " + opt[1]); + } } else if(opt[0].equals("-!inferdepvis")) { inferDendencyVisibility = Visibility.PRIVATE; - } else if(opt[0].equals("-!inferreltype")) { - inferRelationshipType = "navassoc"; } else if(opt[0].equals("-inferdep")) { inferDependencies = true; } else if(opt[0].equals("-!inferdep")) { @@ -469,6 +474,20 @@ public class Options implements Cloneable, OptionProvider { postfixPackage = false; } else if (opt[0].equals("-link")) { addApiDocRoots(opt[1]); + } else if(opt[0].equals("-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 ; // Do nothing, javadoc will handle the option or complain, if // needed. diff --git a/src/gr/spinellis/umlgraph/doclet/RelationDirection.java b/src/gr/spinellis/umlgraph/doclet/RelationDirection.java new file mode 100644 index 0000000..5cd86a1 --- /dev/null +++ b/src/gr/spinellis/umlgraph/doclet/RelationDirection.java @@ -0,0 +1,51 @@ +package gr.spinellis.umlgraph.doclet; + +/** + * The possibile directions of a relation given a reference class (used in + * context diagrams) + */ +public enum RelationDirection { + NONE, IN, OUT, BOTH; + + /** + * Adds the current direction + * @param d + * @return + */ + public RelationDirection sum(RelationDirection d) { + if (this == NONE) + return d; + + if ((this == IN && d == OUT) || (this == OUT && d == IN) || this == BOTH || d == BOTH) + return BOTH; + return this; + } + + /** + * 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) { + if (this == BOTH) + return true; + else + return d == this; + } + + /** + * Inverts the direction of the relation. Turns IN into OUT and vice-versa, NONE and BOTH + * are not changed + * @return + */ + public RelationDirection inverse() { + if (this == IN) + return OUT; + else if (this == OUT) + return IN; + else + return this; + } + +}; diff --git a/src/gr/spinellis/umlgraph/doclet/RelationPattern.java b/src/gr/spinellis/umlgraph/doclet/RelationPattern.java new file mode 100644 index 0000000..62afa49 --- /dev/null +++ b/src/gr/spinellis/umlgraph/doclet/RelationPattern.java @@ -0,0 +1,50 @@ +package gr.spinellis.umlgraph.doclet; + +/** + * A map from relation types to directions + * @author wolf + * + */ +public class RelationPattern { + /** + * A map from RelationType (indexes) to Direction objects + */ + RelationDirection[] directions; + + /** + * 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; + } + } + + /** + * 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); + } + + /** + * 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; + } + +} diff --git a/src/gr/spinellis/umlgraph/doclet/RelationType.java b/src/gr/spinellis/umlgraph/doclet/RelationType.java new file mode 100644 index 0000000..23577ba --- /dev/null +++ b/src/gr/spinellis/umlgraph/doclet/RelationType.java @@ -0,0 +1,10 @@ +package gr.spinellis.umlgraph.doclet; + +/** + * The type of relation that links two entities + * @author wolf + * + */ +public enum RelationType { + ASSOC, NAVASSOC, HAS, COMPOSED, DEPEND, EXTENDS, IMPLEMENTS; +} diff --git a/src/gr/spinellis/umlgraph/doclet/View.java b/src/gr/spinellis/umlgraph/doclet/View.java index b792393..20fb4e7 100644 --- a/src/gr/spinellis/umlgraph/doclet/View.java +++ b/src/gr/spinellis/umlgraph/doclet/View.java @@ -97,6 +97,9 @@ public class View implements OptionProvider { } 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")) { diff --git a/src/gr/spinellis/umlgraph/doclet/Visibility.java b/src/gr/spinellis/umlgraph/doclet/Visibility.java index 25ed4e7..36da653 100644 --- a/src/gr/spinellis/umlgraph/doclet/Visibility.java +++ b/src/gr/spinellis/umlgraph/doclet/Visibility.java @@ -28,13 +28,7 @@ import com.sun.javadoc.ProgramElementDoc; * */ public enum Visibility { - PRIVATE("private"), PACKAGE("package"), PROTECTED("protected"), PUBLIC("public"); - - private String name; - - private Visibility(String name) { - this.name = name; - } + PRIVATE, PACKAGE, PROTECTED, PUBLIC; public static Visibility get(ProgramElementDoc doc) { if (doc.isPrivate()) @@ -47,12 +41,4 @@ public enum Visibility { return PUBLIC; } - - public static Visibility parseVisibility(String vis) { - for (Visibility v : Visibility.values()) { - if (v.name.equalsIgnoreCase(vis)) - return v; - } - return null; - } } \ No newline at end of file diff --git a/src/org/umlgraph/doclet/ClassInfo.java b/src/org/umlgraph/doclet/ClassInfo.java index 500a7c2..045194c 100644 --- a/src/org/umlgraph/doclet/ClassInfo.java +++ b/src/org/umlgraph/doclet/ClassInfo.java @@ -20,8 +20,9 @@ package gr.spinellis.umlgraph.doclet; -import java.util.HashSet; -import java.util.Set; +import java.util.HashMap; +import java.util.List; +import java.util.Map; /** * Class's dot-comaptible alias name (for fully qualified class names) @@ -42,7 +43,7 @@ class ClassInfo { * all the classes linked with a bi-directional relation , and the ones * referred by a directed relation */ - Set relatedClasses = new HashSet(); + Map relatedClasses = new HashMap(); ClassInfo(boolean p, boolean h) { nodePrinted = p; @@ -51,12 +52,17 @@ class ClassInfo { classNumber++; } - public void addRelation(String dest) { - relatedClasses.add(dest); + 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); } - public boolean isRelated(String dest) { - return relatedClasses.contains(dest); + public RelationPattern getRelation(String dest) { + return relatedClasses.get(dest); } /** Start numbering from zero. */ diff --git a/src/org/umlgraph/doclet/ContextMatcher.java b/src/org/umlgraph/doclet/ContextMatcher.java index 53d212e..d0569d2 100644 --- a/src/org/umlgraph/doclet/ContextMatcher.java +++ b/src/org/umlgraph/doclet/ContextMatcher.java @@ -32,13 +32,13 @@ import com.sun.javadoc.RootDoc; /** * Matches classes that are directly connected to one of the classes matched by - * the regual expression specified. The context center is computed by regex lookup. - * Depending on the specified Options, inferred relations and dependencies will - * be used as well. + * the regual expression specified. The context center is computed by regex + * lookup. Depending on the specified Options, inferred relations and + * dependencies will be used as well. *

* 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 + * you * @author wolf * * @depend - - - DevNullWriter @@ -61,6 +61,10 @@ public class ContextMatcher implements ClassMatcher { * @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 fullContext If true, all the classes related to the context + * center will be included, otherwise it will match only + * the classes referred with an outgoing relation from + * the context center * @throws IOException */ public ContextMatcher(RootDoc root, Pattern pattern, Options options, boolean keepParentHide) throws IOException { @@ -68,14 +72,14 @@ public class ContextMatcher implements ClassMatcher { 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"}); + opt.setOption(new String[] { "-!hide" }); + opt.setOption(new String[] { "-!attributes" }); + opt.setOption(new String[] { "-!operations" }); this.cg = new ClassGraphHack(root, opt); setContextCenter(pattern); } - + /** * Can be used to setup a different pattern for this context matcher. *

@@ -103,11 +107,12 @@ public class ContextMatcher implements ClassMatcher { * @param cd */ private void addToGraph(ClassDoc cd) { - // avoid adding twice the same class, but don't rely on cg.getClassInfo since there + // 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())) + if (visited.contains(cd.toString())) return; - + visited.add(cd.toString()); cg.printClass(cd, false); cg.printRelations(cd); @@ -146,10 +151,8 @@ public class ContextMatcher implements ClassMatcher { for (ClassDoc mcd : matched) { String mcName = mcd.toString(); ClassInfo ciMatched = cg.getClassInfo(mcName); - if (ciMatched != null && ciMatched.isRelated(name)) - return true; - ClassInfo ci = cg.getClassInfo(name); - if (ci != null && ci.isRelated(mcName)) + RelationPattern rp = ciMatched.getRelation(name); + if (ciMatched != null && rp != null && opt.contextRelationPattern.matchesOne(rp)) return true; } return false; diff --git a/src/org/umlgraph/doclet/Options.java b/src/org/umlgraph/doclet/Options.java index ff855e4..29feec8 100644 --- a/src/org/umlgraph/doclet/Options.java +++ b/src/org/umlgraph/doclet/Options.java @@ -109,11 +109,12 @@ public class Options implements Cloneable, OptionProvider { String guilClose = "»"; // "\u00bb"; boolean inferRelationships; boolean inferDependencies; + RelationPattern contextRelationPattern; boolean useImports; Visibility inferDendencyVisibility; boolean inferDepInPackage; boolean verbose2; - String inferRelationshipType; + RelationType inferRelationshipType; private Vector collPackages; boolean compact; // internal option, used by UMLDoc to generate relative links between classes @@ -161,12 +162,13 @@ public class Options implements Cloneable, OptionProvider { useGuillemot = true; findViews = false; viewName = null; + contextRelationPattern = new RelationPattern(RelationDirection.BOTH); inferRelationships = false; inferDependencies = false; inferDendencyVisibility = Visibility.PRIVATE; inferDepInPackage = false; useImports = false; - inferRelationshipType = "navassoc"; + inferRelationshipType = RelationType.NAVASSOC; collPackages = new Vector(); compact = false; relativeLinksForSourcePackages = false; @@ -220,6 +222,7 @@ public class Options implements Cloneable, OptionProvider { option.equals("-useimports") || option.equals("-inferdep") || option.equals("-inferdepinpackage") || + option.equals("-fullContext") || option.equals("-verbose2") || option.equals("-compact")) @@ -251,9 +254,10 @@ public class Options implements Cloneable, OptionProvider { option.equals("-inferreltype") || option.equals("-inferdepvis") || option.equals("-collpackages") || - option.equals("-link") - ) + option.equals("-link")) return 2; + else if(option.equals("-contextPattern")) + return 3; else return 0; } @@ -423,22 +427,23 @@ public class Options implements Cloneable, OptionProvider { } else if(opt[0].equals("-!inferrel")) { inferRelationships = false; } else if(opt[0].equals("-inferreltype")) { - if(ClassGraph.associationMap.containsKey(opt[1])) { - inferRelationshipType = opt[1]; - } else { - System.err.println("Unknown association type " + opt[1]); - } + try { + inferRelationshipType = RelationType.valueOf(opt[1].toUpperCase()); + } catch(IllegalArgumentException e) { + System.err.println("Unknown association type " + opt[1]); + } } else if(opt[0].equals("-!inferreltype")) { - inferRelationshipType = "navassoc"; + inferRelationshipType = RelationType.NAVASSOC; } else if(opt[0].equals("-inferdepvis")) { - Visibility vis = Visibility.parseVisibility(opt[1]); - if(vis == null) - System.err.println("Ignoring invalid visibility specification for dependency inference" + vis); - inferDendencyVisibility = Visibility.PRIVATE; + try { + Visibility vis = Visibility.valueOf(opt[1].toUpperCase()); + inferDendencyVisibility = vis; + } catch(IllegalArgumentException e) { + System.err.println("Ignoring invalid visibility specification for " + + "dependency inference: " + opt[1]); + } } else if(opt[0].equals("-!inferdepvis")) { inferDendencyVisibility = Visibility.PRIVATE; - } else if(opt[0].equals("-!inferreltype")) { - inferRelationshipType = "navassoc"; } else if(opt[0].equals("-inferdep")) { inferDependencies = true; } else if(opt[0].equals("-!inferdep")) { @@ -469,6 +474,20 @@ public class Options implements Cloneable, OptionProvider { postfixPackage = false; } else if (opt[0].equals("-link")) { addApiDocRoots(opt[1]); + } else if(opt[0].equals("-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 ; // Do nothing, javadoc will handle the option or complain, if // needed. diff --git a/src/org/umlgraph/doclet/RelationDirection.java b/src/org/umlgraph/doclet/RelationDirection.java new file mode 100644 index 0000000..5cd86a1 --- /dev/null +++ b/src/org/umlgraph/doclet/RelationDirection.java @@ -0,0 +1,51 @@ +package gr.spinellis.umlgraph.doclet; + +/** + * The possibile directions of a relation given a reference class (used in + * context diagrams) + */ +public enum RelationDirection { + NONE, IN, OUT, BOTH; + + /** + * Adds the current direction + * @param d + * @return + */ + public RelationDirection sum(RelationDirection d) { + if (this == NONE) + return d; + + if ((this == IN && d == OUT) || (this == OUT && d == IN) || this == BOTH || d == BOTH) + return BOTH; + return this; + } + + /** + * 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) { + if (this == BOTH) + return true; + else + return d == this; + } + + /** + * Inverts the direction of the relation. Turns IN into OUT and vice-versa, NONE and BOTH + * are not changed + * @return + */ + public RelationDirection inverse() { + if (this == IN) + return OUT; + else if (this == OUT) + return IN; + else + return this; + } + +}; diff --git a/src/org/umlgraph/doclet/RelationPattern.java b/src/org/umlgraph/doclet/RelationPattern.java new file mode 100644 index 0000000..62afa49 --- /dev/null +++ b/src/org/umlgraph/doclet/RelationPattern.java @@ -0,0 +1,50 @@ +package gr.spinellis.umlgraph.doclet; + +/** + * A map from relation types to directions + * @author wolf + * + */ +public class RelationPattern { + /** + * A map from RelationType (indexes) to Direction objects + */ + RelationDirection[] directions; + + /** + * 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; + } + } + + /** + * 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); + } + + /** + * 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; + } + +} diff --git a/src/org/umlgraph/doclet/RelationType.java b/src/org/umlgraph/doclet/RelationType.java new file mode 100644 index 0000000..23577ba --- /dev/null +++ b/src/org/umlgraph/doclet/RelationType.java @@ -0,0 +1,10 @@ +package gr.spinellis.umlgraph.doclet; + +/** + * The type of relation that links two entities + * @author wolf + * + */ +public enum RelationType { + ASSOC, NAVASSOC, HAS, COMPOSED, DEPEND, EXTENDS, IMPLEMENTS; +} diff --git a/src/org/umlgraph/doclet/View.java b/src/org/umlgraph/doclet/View.java index b792393..20fb4e7 100644 --- a/src/org/umlgraph/doclet/View.java +++ b/src/org/umlgraph/doclet/View.java @@ -97,6 +97,9 @@ public class View implements OptionProvider { } 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")) { diff --git a/src/org/umlgraph/doclet/Visibility.java b/src/org/umlgraph/doclet/Visibility.java index 25ed4e7..36da653 100644 --- a/src/org/umlgraph/doclet/Visibility.java +++ b/src/org/umlgraph/doclet/Visibility.java @@ -28,13 +28,7 @@ import com.sun.javadoc.ProgramElementDoc; * */ public enum Visibility { - PRIVATE("private"), PACKAGE("package"), PROTECTED("protected"), PUBLIC("public"); - - private String name; - - private Visibility(String name) { - this.name = name; - } + PRIVATE, PACKAGE, PROTECTED, PUBLIC; public static Visibility get(ProgramElementDoc doc) { if (doc.isPrivate()) @@ -47,12 +41,4 @@ public enum Visibility { return PUBLIC; } - - public static Visibility parseVisibility(String vis) { - for (Visibility v : Visibility.values()) { - if (v.name.equalsIgnoreCase(vis)) - return v; - } - return null; - } } \ No newline at end of file diff --git a/testdata/dot-ref/Inference.dot b/testdata/dot-ref/Inference.dot index ac780ed..531bd25 100644 --- a/testdata/dot-ref/Inference.dot +++ b/testdata/dot-ref/Inference.dot @@ -1,7 +1,7 @@ #!/usr/local/bin/dot # # Class diagram -# Generated by UmlGraph version 4.1 (http://www.spinellis.gr/sw/umlgraph) +# Generated by UmlGraph version 4.4 (http://www.spinellis.gr/sw/umlgraph) # digraph G { @@ -23,27 +23,29 @@ digraph G { c72:p -> c69:p [dir=back,arrowtail=empty]; //MyList extends MyFunnyList c69:p -> c70:p [dir=back,arrowtail=empty]; - // A depend C - c66:p -> c68:p [taillabel="", label="", headlabel="", fontname="Helvetica", fontcolor="black", fontsize=10.0, color="black", arrowhead=open, style=dashed]; - // A depend B - c66:p -> c67:p [taillabel="", label="", headlabel="", fontname="Helvetica", fontcolor="black", fontsize=10.0, color="black", arrowhead=open, style=dashed]; - // B depend C - c67:p -> c68:p [taillabel="", label="", headlabel="", fontname="Helvetica", fontcolor="black", fontsize=10.0, color="black", arrowhead=open, style=dashed]; - // B depend A + // A HAS B + c66:p -> c67:p [taillabel="", label="", headlabel="", fontname="Helvetica", fontcolor="black", fontsize=10.0, color="black", arrowhead=none, arrowtail=ediamond]; + // A HAS B + c66:p -> c67:p [taillabel="", label="", headlabel="", fontname="Helvetica", fontcolor="black", fontsize=10.0, color="black", arrowhead=none, arrowtail=ediamond]; + // A HAS C + c66:p -> c68:p [taillabel="", label="", headlabel="", fontname="Helvetica", fontcolor="black", fontsize=10.0, color="black", arrowhead=none, arrowtail=ediamond]; + // C NAVASSOC A + c68:p -> c66:p [taillabel="", label="", headlabel="*", fontname="Helvetica", fontcolor="black", fontsize=10.0, color="black", arrowhead=open]; + // C NAVASSOC B + c68:p -> c67:p [taillabel="", label="", headlabel="*", fontname="Helvetica", fontcolor="black", fontsize=10.0, color="black", arrowhead=open]; + // C NAVASSOC D + c68:p -> c71:p [taillabel="", label="", headlabel="*", fontname="Helvetica", fontcolor="black", fontsize=10.0, color="black", arrowhead=open]; + // C NAVASSOC C + c68:p -> c68:p [taillabel="", label="", headlabel="*", fontname="Helvetica", fontcolor="black", fontsize=10.0, color="black", arrowhead=open]; + // C NAVASSOC java.util.List + c68:p -> c73:p [taillabel="", label="", headlabel="", fontname="Helvetica", fontcolor="black", fontsize=10.0, color="black", arrowhead=open]; + // D NAVASSOC MyList + c71:p -> c70:p [taillabel="", label="", headlabel="", fontname="Helvetica", fontcolor="black", fontsize=10.0, color="black", arrowhead=open]; + // B DEPEND A c67:p -> c66:p [taillabel="", label="", headlabel="", fontname="Helvetica", fontcolor="black", fontsize=10.0, color="black", arrowhead=open, style=dashed]; - // C depend java.util.Map - c68:p -> c73:p [taillabel="", label="", headlabel="", fontname="Helvetica", fontcolor="black", fontsize=10.0, color="black", arrowhead=open, style=dashed]; - // C depend java.util.List - c68:p -> c74:p [taillabel="", label="", headlabel="", fontname="Helvetica", fontcolor="black", fontsize=10.0, color="black", arrowhead=open, style=dashed]; - // C depend java.util.ArrayList - c68:p -> c72:p [taillabel="", label="", headlabel="", fontname="Helvetica", fontcolor="black", fontsize=10.0, color="black", arrowhead=open, style=dashed]; - // D depend MyList - c71:p -> c70:p [taillabel="", label="", headlabel="", fontname="Helvetica", fontcolor="black", fontsize=10.0, color="black", arrowhead=open, style=dashed]; - // java.util.Map - c73 [label=<
«interface»
Map<K, V>
size() : int
isEmpty() : boolean
containsKey(arg0 : Object) : boolean
containsValue(arg0 : Object) : boolean
get(arg0 : Object) : V
put(arg0 : K, arg1 : V) : V
remove(arg0 : Object) : V
putAll(arg0 : Map<?, ?>)
clear()
keySet() : Set<K>
values() : Collection<V>
entrySet() : Set<Map.Entry<K, V>>
equals(arg0 : Object) : boolean
hashCode() : int
>, fontname="Helvetica", fontcolor="black", fontsize=10.0]; // java.util.ArrayList c72 [label=<
ArrayList<E>
serialVersionUID : long
elementData : E[]
size : int
trimToSize()
ensureCapacity(arg0 : int)
size() : int
isEmpty() : boolean
contains(arg0 : Object) : boolean
indexOf(arg0 : Object) : int
lastIndexOf(arg0 : Object) : int
clone() : Object
toArray() : Object[]
toArray(arg0 : T[]) : T[]
get(arg0 : int) : E
set(arg0 : int, arg1 : E) : E
add(arg0 : E) : boolean
add(arg0 : int, arg1 : E)
remove(arg0 : int) : E
remove(arg0 : Object) : boolean
fastRemove(arg0 : int)
clear()
addAll(arg0 : Collection<?>) : boolean
addAll(arg0 : int, arg1 : Collection<?>) : boolean
removeRange(arg0 : int, arg1 : int)
RangeCheck(arg0 : int)
writeObject(arg0 : ObjectOutputStream)
readObject(arg0 : ObjectInputStream)
>, fontname="Helvetica", fontcolor="black", fontsize=10.0]; // java.util.List - c74 [label=<
«interface»
List<E>
size() : int
isEmpty() : boolean
contains(arg0 : Object) : boolean
iterator() : Iterator<E>
toArray() : Object[]
toArray(arg0 : T[]) : T[]
add(arg0 : E) : boolean
remove(arg0 : Object) : boolean
containsAll(arg0 : Collection<?>) : boolean
addAll(arg0 : Collection<?>) : boolean
addAll(arg0 : int, arg1 : Collection<?>) : boolean
removeAll(arg0 : Collection<?>) : boolean
retainAll(arg0 : Collection<?>) : boolean
clear()
equals(arg0 : Object) : boolean
hashCode() : int
get(arg0 : int) : E
set(arg0 : int, arg1 : E) : E
add(arg0 : int, arg1 : E)
remove(arg0 : int) : E
indexOf(arg0 : Object) : int
lastIndexOf(arg0 : Object) : int
listIterator() : ListIterator<E>
listIterator(arg0 : int) : ListIterator<E>
subList(arg0 : int, arg1 : int) : List<E>
>, fontname="Helvetica", fontcolor="black", fontsize=10.0]; + c73 [label=<
«interface»
List<E>
size() : int
isEmpty() : boolean
contains(arg0 : Object) : boolean
iterator() : Iterator<E>
toArray() : Object[]
toArray(arg0 : T[]) : T[]
add(arg0 : E) : boolean
remove(arg0 : Object) : boolean
containsAll(arg0 : Collection<?>) : boolean
addAll(arg0 : Collection<?>) : boolean
addAll(arg0 : int, arg1 : Collection<?>) : boolean
removeAll(arg0 : Collection<?>) : boolean
retainAll(arg0 : Collection<?>) : boolean
clear()
equals(arg0 : Object) : boolean
hashCode() : int
get(arg0 : int) : E
set(arg0 : int, arg1 : E) : E
add(arg0 : int, arg1 : E)
remove(arg0 : int) : E
indexOf(arg0 : Object) : int
lastIndexOf(arg0 : Object) : int
listIterator() : ListIterator<E>
listIterator(arg0 : int) : ListIterator<E>
subList(arg0 : int, arg1 : int) : List<E>
>, fontname="Helvetica", fontcolor="black", fontsize=10.0]; } diff --git a/testdata/java/Inference.java b/testdata/java/Inference.java index 21cf0d9..2d76faf 100644 --- a/testdata/java/Inference.java +++ b/testdata/java/Inference.java @@ -5,7 +5,7 @@ import java.util.ArrayList; import java.util.Map; /** - * @opt inferassoc + * @opt inferrel * @opt inferdep * @opt inferdepinpackage * @opt attributes @@ -17,7 +17,7 @@ import java.util.Map; class UMLOptions {} /** - * @opt inferassoctype has + * @opt inferreltype has */ class A { B first;