From 20070fafaf62d51c5604953c3820bcec3e10ff95 Mon Sep 17 00:00:00 2001 From: Andrea Aime Date: Sun, 4 Jun 2006 08:27:03 +0000 Subject: [PATCH] Moved handling of api doc map to Options, and made options react to -link parameters the same way as the standard doclet does: by downloading and parsing the package-list file to populate the api doc map. --- src/gr/spinellis/umlgraph/doclet/Options.java | 140 ++++++++++++++++-- src/org/umlgraph/doclet/Options.java | 140 ++++++++++++++++-- 2 files changed, 258 insertions(+), 22 deletions(-) diff --git a/src/gr/spinellis/umlgraph/doclet/Options.java b/src/gr/spinellis/umlgraph/doclet/Options.java index c1f228d..fde451b 100644 --- a/src/gr/spinellis/umlgraph/doclet/Options.java +++ b/src/gr/spinellis/umlgraph/doclet/Options.java @@ -20,14 +20,27 @@ package gr.spinellis.umlgraph.doclet; -import com.sun.javadoc.*; - -import java.lang.reflect.*; -import java.util.*; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.net.URL; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; +import java.util.Vector; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; +import com.sun.javadoc.ClassDoc; +import com.sun.javadoc.Tag; + /** * Represent the program options * @version $Revision$ @@ -38,7 +51,8 @@ public class Options implements Cloneable, OptionProvider { private static String defaultFont; private static String defaultItalicFont; // reused often, especially in UmlDoc, worth creating just once and reusing - private static Pattern allPattern = Pattern.compile(".*"); + private static final Pattern allPattern = Pattern.compile(".*"); + protected static final String DEFAULT_EXTERNAL_APIDOC = "http://java.sun.com/j2se/1.4.2/docs/api/"; static { // use an appropriate font depending on the current operating system @@ -82,7 +96,7 @@ public class Options implements Cloneable, OptionProvider { String bgColor; public String outputFileName; String outputEncoding; - String apiDocMapFileName; + Map apiDocMap; String apiDocRoot; boolean postfixPackage; boolean useGuillemot; @@ -139,7 +153,7 @@ public class Options implements Cloneable, OptionProvider { outputDirectory= null; outputEncoding = "ISO-8859-1"; hidePatterns = new Vector(); - apiDocMapFileName = null; + apiDocMap = new HashMap(); apiDocRoot = null; postfixPackage = false; useGuillemot = true; @@ -165,6 +179,7 @@ public class Options implements Cloneable, OptionProvider { // deep clone the hide and collection patterns clone.hidePatterns = new Vector(hidePatterns); clone.collPackages= new Vector(collPackages); + clone.apiDocMap = new HashMap(apiDocMap); return clone; } @@ -230,7 +245,8 @@ public class Options implements Cloneable, OptionProvider { option.equals("-d") || option.equals("-view") || option.equals("-inferreltype") || - option.equals("-collpackages") + option.equals("-collpackages") || + option.equals("-link") ) return 2; else @@ -372,13 +388,13 @@ public class Options implements Cloneable, OptionProvider { } else if (opt[0].equals("-!hide")) { hidePatterns.clear(); } else if(opt[0].equals("-apidocroot")) { - apiDocRoot = opt[1]; + apiDocRoot = fixApiDocRoot(opt[1]); } else if (opt[0].equals("-!apidocroot")) { apiDocRoot = null; } else if(opt[0].equals("-apidocmap")) { - apiDocMapFileName = opt[1]; + setApiDocMapFile(opt[1]); } else if (opt[0].equals("-!apidocmap")) { - apiDocMapFileName = null; + apiDocMap.clear(); } else if(opt[0].equals("-noguillemot")) { guilOpen = "\\<\\<"; guilClose = "\\>\\>"; @@ -435,11 +451,112 @@ public class Options implements Cloneable, OptionProvider { postfixPackage = true; } else if (opt[0].equals("-!postfixpackage")) { postfixPackage = false; + } else if (opt[0].equals("-link")) { + addApiDocRoots(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 + * @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 = null; + 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) {} + } + + } + + /** + * 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 { + 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()); + } + } + } 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. + * + * 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()) { + Pattern regex = mapEntry.getKey(); + Matcher matcher = regex.matcher(className); + if (matcher.matches()) + return mapEntry.getValue(); + } + return null; + } + + /** 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; + } + /** Set the options based on the command line parameters */ public void setOptions(String[][] options) { for (String s[] : options) @@ -545,5 +662,6 @@ public class Options implements Cloneable, OptionProvider { } return sb.toString(); } + } diff --git a/src/org/umlgraph/doclet/Options.java b/src/org/umlgraph/doclet/Options.java index c1f228d..fde451b 100644 --- a/src/org/umlgraph/doclet/Options.java +++ b/src/org/umlgraph/doclet/Options.java @@ -20,14 +20,27 @@ package gr.spinellis.umlgraph.doclet; -import com.sun.javadoc.*; - -import java.lang.reflect.*; -import java.util.*; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.net.URL; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; +import java.util.Vector; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; +import com.sun.javadoc.ClassDoc; +import com.sun.javadoc.Tag; + /** * Represent the program options * @version $Revision$ @@ -38,7 +51,8 @@ public class Options implements Cloneable, OptionProvider { private static String defaultFont; private static String defaultItalicFont; // reused often, especially in UmlDoc, worth creating just once and reusing - private static Pattern allPattern = Pattern.compile(".*"); + private static final Pattern allPattern = Pattern.compile(".*"); + protected static final String DEFAULT_EXTERNAL_APIDOC = "http://java.sun.com/j2se/1.4.2/docs/api/"; static { // use an appropriate font depending on the current operating system @@ -82,7 +96,7 @@ public class Options implements Cloneable, OptionProvider { String bgColor; public String outputFileName; String outputEncoding; - String apiDocMapFileName; + Map apiDocMap; String apiDocRoot; boolean postfixPackage; boolean useGuillemot; @@ -139,7 +153,7 @@ public class Options implements Cloneable, OptionProvider { outputDirectory= null; outputEncoding = "ISO-8859-1"; hidePatterns = new Vector(); - apiDocMapFileName = null; + apiDocMap = new HashMap(); apiDocRoot = null; postfixPackage = false; useGuillemot = true; @@ -165,6 +179,7 @@ public class Options implements Cloneable, OptionProvider { // deep clone the hide and collection patterns clone.hidePatterns = new Vector(hidePatterns); clone.collPackages= new Vector(collPackages); + clone.apiDocMap = new HashMap(apiDocMap); return clone; } @@ -230,7 +245,8 @@ public class Options implements Cloneable, OptionProvider { option.equals("-d") || option.equals("-view") || option.equals("-inferreltype") || - option.equals("-collpackages") + option.equals("-collpackages") || + option.equals("-link") ) return 2; else @@ -372,13 +388,13 @@ public class Options implements Cloneable, OptionProvider { } else if (opt[0].equals("-!hide")) { hidePatterns.clear(); } else if(opt[0].equals("-apidocroot")) { - apiDocRoot = opt[1]; + apiDocRoot = fixApiDocRoot(opt[1]); } else if (opt[0].equals("-!apidocroot")) { apiDocRoot = null; } else if(opt[0].equals("-apidocmap")) { - apiDocMapFileName = opt[1]; + setApiDocMapFile(opt[1]); } else if (opt[0].equals("-!apidocmap")) { - apiDocMapFileName = null; + apiDocMap.clear(); } else if(opt[0].equals("-noguillemot")) { guilOpen = "\\<\\<"; guilClose = "\\>\\>"; @@ -435,11 +451,112 @@ public class Options implements Cloneable, OptionProvider { postfixPackage = true; } else if (opt[0].equals("-!postfixpackage")) { postfixPackage = false; + } else if (opt[0].equals("-link")) { + addApiDocRoots(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 + * @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 = null; + 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) {} + } + + } + + /** + * 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 { + 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()); + } + } + } 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. + * + * 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()) { + Pattern regex = mapEntry.getKey(); + Matcher matcher = regex.matcher(className); + if (matcher.matches()) + return mapEntry.getValue(); + } + return null; + } + + /** 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; + } + /** Set the options based on the command line parameters */ public void setOptions(String[][] options) { for (String s[] : options) @@ -545,5 +662,6 @@ public class Options implements Cloneable, OptionProvider { } return sb.toString(); } + }