diff --git a/src/gr/spinellis/umlgraph/doclet/ClassGraph.java b/src/gr/spinellis/umlgraph/doclet/ClassGraph.java index c836b0b..b9121b1 100644 --- a/src/gr/spinellis/umlgraph/doclet/ClassGraph.java +++ b/src/gr/spinellis/umlgraph/doclet/ClassGraph.java @@ -22,21 +22,15 @@ package gr.spinellis.umlgraph.doclet; import java.io.BufferedOutputStream; import java.io.File; -import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; -import java.io.InputStream; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.Map; -import java.util.Properties; import java.util.Set; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import java.util.regex.PatternSyntaxException; import com.sun.javadoc.ClassDoc; import com.sun.javadoc.ConstructorDoc; @@ -64,7 +58,6 @@ import com.sun.javadoc.WildcardType; * @author Diomidis Spinellis */ class ClassGraph { - protected static final String DEFAULT_EXTERNAL_APIDOC = "http://java.sun.com/j2se/1.4.2/docs/api/"; protected static final char FILE_SEPARATOR = '/'; enum Font { NORMAL, ABSTRACT, CLASS, CLASS_ABSTRACT, TAG, PACKAGE @@ -81,9 +74,7 @@ class ClassGraph { associationMap.put("depend", "arrowhead=open, style=dashed"); } protected Map classnames = new HashMap(); - protected String apiDocRoot; - protected Map apiDocMap = new HashMap(); - protected Set specifiedPackages; + protected Set rootClasses; protected OptionProvider optionProvider; protected PrintWriter w; protected ClassDoc collectionClassDoc; @@ -105,15 +96,18 @@ class ClassGraph { * @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) throws IOException { + 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"); this.contextDoc = contextDoc; - specifiedPackages = new HashSet(); - for (PackageDoc p : root.specifiedPackages()) - specifiedPackages.add(p.name()); + // 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()); Options opt = optionProvider.getGlobalOptions(); if (opt.compact) { @@ -123,45 +117,9 @@ class ClassGraph { linePrefix = "\t"; linePostfix = "\n"; } - - apiDocRoot = fixApiDocRoot(opt.apiDocRoot); - String mapFileName = opt.apiDocMapFileName; - if (mapFileName != null) { - InputStream is = new FileInputStream(mapFileName); - Properties userMap = new Properties(); - userMap.load(is); - for (Map.Entry mapEntry : userMap.entrySet()) { - try { - Pattern regex = Pattern.compile((String)mapEntry.getKey()); - String thisRoot = (String)mapEntry.getValue(); - if (thisRoot != null) { - thisRoot = fixApiDocRoot(thisRoot); - apiDocMap.put(regex, thisRoot); - } else { - System.err.println("No URL for pattern " + mapEntry.getKey()); - } - } catch (PatternSyntaxException e) { - System.err.println("Skipping bad pattern " + mapEntry.getKey()); - } - } - } else - apiDocMap.put(Pattern.compile(".*"), DEFAULT_EXTERNAL_APIDOC); } - /** Trim and append a file separator to the string */ - private String fixApiDocRoot(String str) { - String fixed = null; - if (str != null) { - fixed = str.trim(); - if (fixed.length() > 0) { - if (!File.separator.equals("/")) - fixed = fixed.replace(File.separator.charAt(0), '/'); - if (!fixed.endsWith("/")) - fixed = fixed + "/"; - } - } - return fixed; - } + /** Return the class's name, possibly by stripping the leading path */ private String qualifiedName(Options opt, String r) { @@ -732,10 +690,10 @@ class ClassGraph { continue; // check if the destination is excluded from inference - String dest = fri.cd.toString(); if (hidden(fri.cd)) continue; + String dest = fri.cd.toString(); String destAdornment = fri.multiple ? "*" : ""; relation(opt, opt.inferRelationshipType, sourceName, getNodeName(c), dest, getNodeName(dest), "", "", destAdornment); @@ -879,22 +837,6 @@ class ClassGraph { return name.substring(0, openIdx); } - /** - * Return true if the class name has been specified in the command line. - * Use this only if the ClassDoc is not available, since this implementation won't handle - * properly inner classes (confuses the containing class as a package) - */ - public boolean isSpecifiedPackage(String className) { - int idx = className.lastIndexOf("."); - String packageName = idx > 0 ? className.substring(0, idx) : className; - return specifiedPackages.contains(packageName); - } - - /** Return true if the class name has been specified in the command line */ - public boolean isSpecifiedPackage(ClassDoc cd) { - return specifiedPackages.contains(cd.containingPackage().name()); - } - /** Convert the class name into a corresponding URL */ public String classToUrl(ClassDoc cd, boolean rootClass) { // building relative path for context and package diagrams @@ -957,34 +899,17 @@ class ClassGraph { * the final diagram to the associated JavaDoc page. */ private String mapApiDocRoot(String className) { - String root = null; /* If no packages are specified, we use apiDocRoot for all of them. */ - if (specifiedPackages.isEmpty() || isSpecifiedPackage(className)) - root = apiDocRoot; - else - root = getExternalApiDocRoot(className); + if (rootClasses.contains(className)) { + root = optionProvider.getGlobalOptions().apiDocRoot; + } else { + Options globalOptions = optionProvider.getGlobalOptions(); + root = globalOptions.getApiDocRoot(className); + } return root; } - /** - * Returns the appropriate URL "root" for an external class name. It will - * match the class name against the regular expressions specified in the - * apiDocMapFileName file; if a match is found, the associated URL - * will be returned. - * - * NOTE: Currently the order of the match attempts is not specified, - * so if more then one regular expression matches the result is undetermined. - */ - public String getExternalApiDocRoot(String className) { - for (Map.Entry mapEntry : apiDocMap.entrySet()) { - Pattern regex = mapEntry.getKey(); - Matcher matcher = regex.matcher(className); - if (matcher.matches()) - return mapEntry.getValue(); - } - return null; - } /** Dot prologue * @throws IOException */ @@ -993,10 +918,13 @@ class ClassGraph { // prepare output file. Use the output file name as a full path unless the output // directory is specified File file = null; - if(opt.outputDirectory != null) + if (opt.outputDirectory != null) file = new File(opt.outputDirectory, opt.outputFileName); else - file = new File(opt.outputFileName); + file = new File(".", opt.outputFileName); + // make sure the output directory are there, otherwise create them + if(!file.getParentFile().exists()) + file.getParentFile().mkdirs(); FileOutputStream fos = new FileOutputStream(file); // print plologue diff --git a/src/org/umlgraph/doclet/ClassGraph.java b/src/org/umlgraph/doclet/ClassGraph.java index c836b0b..b9121b1 100644 --- a/src/org/umlgraph/doclet/ClassGraph.java +++ b/src/org/umlgraph/doclet/ClassGraph.java @@ -22,21 +22,15 @@ package gr.spinellis.umlgraph.doclet; import java.io.BufferedOutputStream; import java.io.File; -import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; -import java.io.InputStream; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.Map; -import java.util.Properties; import java.util.Set; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import java.util.regex.PatternSyntaxException; import com.sun.javadoc.ClassDoc; import com.sun.javadoc.ConstructorDoc; @@ -64,7 +58,6 @@ import com.sun.javadoc.WildcardType; * @author Diomidis Spinellis */ class ClassGraph { - protected static final String DEFAULT_EXTERNAL_APIDOC = "http://java.sun.com/j2se/1.4.2/docs/api/"; protected static final char FILE_SEPARATOR = '/'; enum Font { NORMAL, ABSTRACT, CLASS, CLASS_ABSTRACT, TAG, PACKAGE @@ -81,9 +74,7 @@ class ClassGraph { associationMap.put("depend", "arrowhead=open, style=dashed"); } protected Map classnames = new HashMap(); - protected String apiDocRoot; - protected Map apiDocMap = new HashMap(); - protected Set specifiedPackages; + protected Set rootClasses; protected OptionProvider optionProvider; protected PrintWriter w; protected ClassDoc collectionClassDoc; @@ -105,15 +96,18 @@ class ClassGraph { * @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) throws IOException { + 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"); this.contextDoc = contextDoc; - specifiedPackages = new HashSet(); - for (PackageDoc p : root.specifiedPackages()) - specifiedPackages.add(p.name()); + // 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()); Options opt = optionProvider.getGlobalOptions(); if (opt.compact) { @@ -123,45 +117,9 @@ class ClassGraph { linePrefix = "\t"; linePostfix = "\n"; } - - apiDocRoot = fixApiDocRoot(opt.apiDocRoot); - String mapFileName = opt.apiDocMapFileName; - if (mapFileName != null) { - InputStream is = new FileInputStream(mapFileName); - Properties userMap = new Properties(); - userMap.load(is); - for (Map.Entry mapEntry : userMap.entrySet()) { - try { - Pattern regex = Pattern.compile((String)mapEntry.getKey()); - String thisRoot = (String)mapEntry.getValue(); - if (thisRoot != null) { - thisRoot = fixApiDocRoot(thisRoot); - apiDocMap.put(regex, thisRoot); - } else { - System.err.println("No URL for pattern " + mapEntry.getKey()); - } - } catch (PatternSyntaxException e) { - System.err.println("Skipping bad pattern " + mapEntry.getKey()); - } - } - } else - apiDocMap.put(Pattern.compile(".*"), DEFAULT_EXTERNAL_APIDOC); } - /** Trim and append a file separator to the string */ - private String fixApiDocRoot(String str) { - String fixed = null; - if (str != null) { - fixed = str.trim(); - if (fixed.length() > 0) { - if (!File.separator.equals("/")) - fixed = fixed.replace(File.separator.charAt(0), '/'); - if (!fixed.endsWith("/")) - fixed = fixed + "/"; - } - } - return fixed; - } + /** Return the class's name, possibly by stripping the leading path */ private String qualifiedName(Options opt, String r) { @@ -732,10 +690,10 @@ class ClassGraph { continue; // check if the destination is excluded from inference - String dest = fri.cd.toString(); if (hidden(fri.cd)) continue; + String dest = fri.cd.toString(); String destAdornment = fri.multiple ? "*" : ""; relation(opt, opt.inferRelationshipType, sourceName, getNodeName(c), dest, getNodeName(dest), "", "", destAdornment); @@ -879,22 +837,6 @@ class ClassGraph { return name.substring(0, openIdx); } - /** - * Return true if the class name has been specified in the command line. - * Use this only if the ClassDoc is not available, since this implementation won't handle - * properly inner classes (confuses the containing class as a package) - */ - public boolean isSpecifiedPackage(String className) { - int idx = className.lastIndexOf("."); - String packageName = idx > 0 ? className.substring(0, idx) : className; - return specifiedPackages.contains(packageName); - } - - /** Return true if the class name has been specified in the command line */ - public boolean isSpecifiedPackage(ClassDoc cd) { - return specifiedPackages.contains(cd.containingPackage().name()); - } - /** Convert the class name into a corresponding URL */ public String classToUrl(ClassDoc cd, boolean rootClass) { // building relative path for context and package diagrams @@ -957,34 +899,17 @@ class ClassGraph { * the final diagram to the associated JavaDoc page. */ private String mapApiDocRoot(String className) { - String root = null; /* If no packages are specified, we use apiDocRoot for all of them. */ - if (specifiedPackages.isEmpty() || isSpecifiedPackage(className)) - root = apiDocRoot; - else - root = getExternalApiDocRoot(className); + if (rootClasses.contains(className)) { + root = optionProvider.getGlobalOptions().apiDocRoot; + } else { + Options globalOptions = optionProvider.getGlobalOptions(); + root = globalOptions.getApiDocRoot(className); + } return root; } - /** - * Returns the appropriate URL "root" for an external class name. It will - * match the class name against the regular expressions specified in the - * apiDocMapFileName file; if a match is found, the associated URL - * will be returned. - * - * NOTE: Currently the order of the match attempts is not specified, - * so if more then one regular expression matches the result is undetermined. - */ - public String getExternalApiDocRoot(String className) { - for (Map.Entry mapEntry : apiDocMap.entrySet()) { - Pattern regex = mapEntry.getKey(); - Matcher matcher = regex.matcher(className); - if (matcher.matches()) - return mapEntry.getValue(); - } - return null; - } /** Dot prologue * @throws IOException */ @@ -993,10 +918,13 @@ class ClassGraph { // prepare output file. Use the output file name as a full path unless the output // directory is specified File file = null; - if(opt.outputDirectory != null) + if (opt.outputDirectory != null) file = new File(opt.outputDirectory, opt.outputFileName); else - file = new File(opt.outputFileName); + file = new File(".", opt.outputFileName); + // make sure the output directory are there, otherwise create them + if(!file.getParentFile().exists()) + file.getParentFile().mkdirs(); FileOutputStream fos = new FileOutputStream(file); // print plologue