View support code

This commit is contained in:
Andrea Aime 2005-12-26 21:14:36 +00:00
parent 7fe982d20e
commit 956673ffb7
6 changed files with 514 additions and 34 deletions

View File

@ -60,6 +60,9 @@ class Options implements Cloneable {
String apiDocMapFileName;
String apiDocRoot;
boolean useGuillemot;
boolean findViews;
String viewName;
String outputDirectory;
/** Guillemot left (open) */
String guilOpen = "\u00ab";
/** Guillemot right (close) */
@ -90,6 +93,8 @@ class Options implements Cloneable {
apiDocMapFileName = null;
apiDocRoot = null;
useGuillemot = true;
findViews = false;
viewName = null;
}
public Object clone() {
@ -127,7 +132,10 @@ class Options implements Cloneable {
option.equals("-visibility") ||
option.equals("-types") ||
option.equals("-all") ||
option.equals("-noguillemot"))
option.equals("-noguillemot") ||
option.equals("-hideall") ||
option.equals("-views"))
return 1;
else if(option.equals("-nodefillcolor") ||
option.equals("-nodefontcolor") ||
@ -143,14 +151,82 @@ class Options implements Cloneable {
option.equals("-bgcolor") ||
option.equals("-hide") ||
option.equals("-apidocroot") ||
option.equals("-apidocmap"))
option.equals("-apidocmap") ||
option.equals("-d") ||
option.equals("-view"))
return 2;
else
return 0;
}
/** Resets the specified option to its default value */
void resetOption(String[] opt) {
if (opt[0].equals("-qualify")) {
showQualified = false;
} else if (opt[0].equals("-horizontal")) {
horizontal = false;
} else if (opt[0].equals("-attributes")) {
showAttributes = false;
} else if (opt[0].equals("-enumconstants")) {
showEnumConstants = false;
} else if (opt[0].equals("-operations")) {
showOperations = false;
} else if (opt[0].equals("-enumerations")) {
showEnumerations = false;
} else if (opt[0].equals("-constructors")) {
showConstructors = false;
} else if (opt[0].equals("-visibility")) {
showVisibility = false;
} else if (opt[0].equals("-types")) {
showType = false;
} else if (opt[0].equals("-bgcolor")) {
bgColor = null;
} else if (opt[0].equals("-edgecolor")) {
edgeColor = "black";
} else if (opt[0].equals("-edgefontcolor")) {
edgeFontColor = "black";
} else if (opt[0].equals("-edgefontname")) {
edgeFontName = "Helvetica";
} else if (opt[0].equals("-edgefontsize")) {
edgeFontSize = 10;
} else if (opt[0].equals("-nodefontcolor")) {
nodeFontColor = "black";
} else if (opt[0].equals("-nodefontname")) {
nodeFontName = "Helvetica";
} else if (opt[0].equals("-nodefontabstractname")) {
nodeFontAbstractName = "Helvetica-Oblique";
} else if (opt[0].equals("-nodefontsize")) {
nodeFontSize = 10;
} else if (opt[0].equals("-nodefillcolor")) {
nodeFillColor = null;
} else if (opt[0].equals("-output")) {
outputFileName = "graph.dot";
} else if (opt[0].equals("-outputencoding")) {
outputEncoding = "ISO-8859-1";
} else if (opt[0].equals("-hide")) {
new Vector<Pattern>();
} else if (opt[0].equals("-apidocroot")) {
apiDocRoot = null;
} else if (opt[0].equals("-apidocmap")) {
apiDocMapFileName = null;
} else if (opt[0].equals("-noguillemot")) {
guilOpen = "\u00ab";
guilClose = "\u00bb";
} else if (opt[0].equals("-view")) {
viewName = null;
} else if (opt[0].equals("-views")) {
findViews = false;
} else if (opt[0].equals("-d")) {
outputDirectory = null;
} else if (opt[0].equals("-hideall")) {
hidePatterns.clear();
} else
; // Do nothing, javadoc will handle the option or complain, if
// needed.
}
/** Set the options based on a lingle option and its arguments */
private void setOption(String[] opt) {
void setOption(String[] opt) {
if(opt[0].equals("-qualify")) {
showQualified = true;
} else if(opt[0].equals("-horizontal")) {
@ -195,6 +271,8 @@ class Options implements Cloneable {
outputFileName = opt[1];
} else if(opt[0].equals("-outputencoding")) {
outputEncoding = opt[1];
} else if(opt[0].equals("-hideall")) {
hidePatterns.add(Pattern.compile(".*"));
} else if(opt[0].equals("-hide")) {
try {
hidePatterns.add(Pattern.compile(opt[1]));
@ -208,6 +286,12 @@ class Options implements Cloneable {
} else if(opt[0].equals("-noguillemot")) {
guilOpen = "\\<\\<";
guilClose = "\\>\\>";
} else if (opt[0].equals("-view")) {
viewName = opt[1];
} else if (opt[0].equals("-views")) {
findViews = true;
} else if (opt[0].equals("-d")) {
outputDirectory = opt[1];
} else
; // Do nothing, javadoc will handle the option or complain, if needed.
}
@ -235,6 +319,11 @@ class Options implements Cloneable {
FileOutputStream fos = new FileOutputStream(outputFileName);
w = new PrintWriter(new BufferedWriter(new OutputStreamWriter(fos, outputEncoding)));
}
public void closeFile() {
w.close();
}
/**
* Check if the supplied string matches an entity specified

View File

@ -20,9 +20,13 @@
package gr.spinellis.umlgraph.doclet;
import com.sun.javadoc.*;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.io.*;
import com.sun.javadoc.ClassDoc;
import com.sun.javadoc.LanguageVersion;
import com.sun.javadoc.RootDoc;
/**
* Doclet API implementation
@ -37,34 +41,80 @@ public class UmlGraph {
/** Entry point */
public static boolean start(RootDoc root) throws IOException {
Options opt = new Options();
ClassInfo.reset();
opt.setOptions(root.options());
opt.openFile();
opt.setOptions(root.classNamed("UMLOptions"));
View[] views = buildViews(opt, root);
if (views.length == 0) {
buildGraph(root, null, opt);
} else {
for (int i = 0; i < views.length; i++) {
buildGraph(root, views[i], (Options) opt.clone());
}
}
return true;
}
/**
* Builds and outputs a single graph according to the view overrides
*/
private static void buildGraph(RootDoc root, View view, Options opt) throws IOException {
if (view != null)
view.applyOverrides(opt);
opt.openFile();
prologue(opt);
ClassDoc[] classes = root.classes();
ClassGraph c = new ClassGraph(root.specifiedPackages(),
opt.apiDocRoot, opt.apiDocMapFileName);
for (ClassDoc cd : classes) {
ClassGraph c = new ClassGraph(root.specifiedPackages(), opt.apiDocRoot,
opt.apiDocMapFileName);
for (int i = 0; i < classes.length; i++) {
// Process class-local options (through @opt tags)
Options localOpt = (Options) opt.clone();
localOpt.setOptions(cd);
c.printClass(localOpt, cd);
localOpt.setOptions(classes[i]);
if (view != null)
view.applyOverrides(localOpt, classes[i]);
c.printClass(localOpt, classes[i]);
}
for (ClassDoc cd : classes) {
for (int i = 0; i < classes.length; i++) {
// Process class-local options (through @opt tags)
Options localOpt = (Options) opt.clone();
localOpt.setOptions(cd);
c.printRelations(localOpt, cd);
localOpt.setOptions(classes[i]);
if (view != null)
view.applyOverrides(localOpt, classes[i]);
c.printRelations(localOpt, classes[i]);
}
c.printExtraClasses(opt, root);
epilogue(opt);
return true;
opt.closeFile();
}
/**
* Builds the views according to the parameters on the command line
*/
private static View[] buildViews(Options opt, RootDoc root) {
if (opt.findViews) {
List<View> views = new ArrayList<View>();
ClassDoc[] classes = root.classes();
for (int i = 0; i < classes.length; i++) {
if (classes[i].tags("view").length > 0) {
views.add(new View(classes[i]));
}
}
return views.toArray(new View[views.size()]);
} else if (opt.viewName != null) {
ClassDoc viewClass = root.classNamed(opt.viewName);
return new View[] { new View(viewClass) };
} else {
return new View[0];
}
}
/** Option checking */
public static int optionLength(String option) {
return Options.optionLength(option);

View File

@ -0,0 +1,101 @@
/*
* Contibuted by Andrea Aime
* (C) Copyright 2005 Diomidis Spinellis
*
* Permission to use, copy, and distribute this software and its
* documentation for any purpose and without fee is hereby granted,
* provided that the above copyright notice appear in all copies and that
* both that copyright notice and this permission notice appear in
* supporting documentation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
* $Id$
*
*/
package gr.spinellis.umlgraph.doclet;
import java.io.File;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
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;
/**
* Contains the definition of a View. A View is a set of option overrides
* that 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
*
*/
class View {
Map<Pattern, String[]> optionOverrides = new LinkedHashMap<Pattern, String[]>();
ClassDoc viewDoc;
public View(ClassDoc c) {
this.viewDoc = c;
Tag[] tags = c.tags("opt_override");
for (int i = 0; i < tags.length; i++) {
String[] opts = StringUtil.tokenize(tags[i].text());
try {
optionOverrides.put(Pattern.compile(opts[0]), opts);
} catch (PatternSyntaxException e) {
System.err.println("Skipping invalid pattern " + opts[0] + " in view "
+ c.toString());
}
}
}
/**
* Applies global view overrides
*/
public void applyOverrides(Options o) {
o.setOptions(viewDoc);
File dotFile = new File(o.outputDirectory, viewDoc.name() + ".dot");
o.setOption(new String[] {"-output", dotFile.getPath()});
}
/**
* Applies local view overrides
*/
public void applyOverrides(Options o, ClassDoc c) {
String className = c.toString();
for (Iterator<Map.Entry<Pattern, String[]>> iter = optionOverrides.entrySet().iterator(); iter
.hasNext();) {
Map.Entry<Pattern, String[]> mapEntry = iter.next();
Pattern regex = mapEntry.getKey();
Matcher matcher = regex.matcher(className);
if (matcher.matches()) {
String[] overrides = mapEntry.getValue(); // the first element is in fact the pattern
for (int i = 1; i < overrides.length; i++) {
String[] option = null;
boolean reset = false;
if (overrides[i].contains("=")) {
option = overrides[i].split("=");
} else {
option = new String[] { overrides[i] };
}
if (option[0].charAt(0) == '!') {
reset = true;
option[0] = option[0].substring(1);
}
option[0] = "-" + option[0];
if (reset) {
o.resetOption(option);
} else {
o.setOption(option);
}
}
}
}
}
}

View File

@ -60,6 +60,9 @@ class Options implements Cloneable {
String apiDocMapFileName;
String apiDocRoot;
boolean useGuillemot;
boolean findViews;
String viewName;
String outputDirectory;
/** Guillemot left (open) */
String guilOpen = "\u00ab";
/** Guillemot right (close) */
@ -90,6 +93,8 @@ class Options implements Cloneable {
apiDocMapFileName = null;
apiDocRoot = null;
useGuillemot = true;
findViews = false;
viewName = null;
}
public Object clone() {
@ -127,7 +132,10 @@ class Options implements Cloneable {
option.equals("-visibility") ||
option.equals("-types") ||
option.equals("-all") ||
option.equals("-noguillemot"))
option.equals("-noguillemot") ||
option.equals("-hideall") ||
option.equals("-views"))
return 1;
else if(option.equals("-nodefillcolor") ||
option.equals("-nodefontcolor") ||
@ -143,14 +151,82 @@ class Options implements Cloneable {
option.equals("-bgcolor") ||
option.equals("-hide") ||
option.equals("-apidocroot") ||
option.equals("-apidocmap"))
option.equals("-apidocmap") ||
option.equals("-d") ||
option.equals("-view"))
return 2;
else
return 0;
}
/** Resets the specified option to its default value */
void resetOption(String[] opt) {
if (opt[0].equals("-qualify")) {
showQualified = false;
} else if (opt[0].equals("-horizontal")) {
horizontal = false;
} else if (opt[0].equals("-attributes")) {
showAttributes = false;
} else if (opt[0].equals("-enumconstants")) {
showEnumConstants = false;
} else if (opt[0].equals("-operations")) {
showOperations = false;
} else if (opt[0].equals("-enumerations")) {
showEnumerations = false;
} else if (opt[0].equals("-constructors")) {
showConstructors = false;
} else if (opt[0].equals("-visibility")) {
showVisibility = false;
} else if (opt[0].equals("-types")) {
showType = false;
} else if (opt[0].equals("-bgcolor")) {
bgColor = null;
} else if (opt[0].equals("-edgecolor")) {
edgeColor = "black";
} else if (opt[0].equals("-edgefontcolor")) {
edgeFontColor = "black";
} else if (opt[0].equals("-edgefontname")) {
edgeFontName = "Helvetica";
} else if (opt[0].equals("-edgefontsize")) {
edgeFontSize = 10;
} else if (opt[0].equals("-nodefontcolor")) {
nodeFontColor = "black";
} else if (opt[0].equals("-nodefontname")) {
nodeFontName = "Helvetica";
} else if (opt[0].equals("-nodefontabstractname")) {
nodeFontAbstractName = "Helvetica-Oblique";
} else if (opt[0].equals("-nodefontsize")) {
nodeFontSize = 10;
} else if (opt[0].equals("-nodefillcolor")) {
nodeFillColor = null;
} else if (opt[0].equals("-output")) {
outputFileName = "graph.dot";
} else if (opt[0].equals("-outputencoding")) {
outputEncoding = "ISO-8859-1";
} else if (opt[0].equals("-hide")) {
new Vector<Pattern>();
} else if (opt[0].equals("-apidocroot")) {
apiDocRoot = null;
} else if (opt[0].equals("-apidocmap")) {
apiDocMapFileName = null;
} else if (opt[0].equals("-noguillemot")) {
guilOpen = "\u00ab";
guilClose = "\u00bb";
} else if (opt[0].equals("-view")) {
viewName = null;
} else if (opt[0].equals("-views")) {
findViews = false;
} else if (opt[0].equals("-d")) {
outputDirectory = null;
} else if (opt[0].equals("-hideall")) {
hidePatterns.clear();
} else
; // Do nothing, javadoc will handle the option or complain, if
// needed.
}
/** Set the options based on a lingle option and its arguments */
private void setOption(String[] opt) {
void setOption(String[] opt) {
if(opt[0].equals("-qualify")) {
showQualified = true;
} else if(opt[0].equals("-horizontal")) {
@ -195,6 +271,8 @@ class Options implements Cloneable {
outputFileName = opt[1];
} else if(opt[0].equals("-outputencoding")) {
outputEncoding = opt[1];
} else if(opt[0].equals("-hideall")) {
hidePatterns.add(Pattern.compile(".*"));
} else if(opt[0].equals("-hide")) {
try {
hidePatterns.add(Pattern.compile(opt[1]));
@ -208,6 +286,12 @@ class Options implements Cloneable {
} else if(opt[0].equals("-noguillemot")) {
guilOpen = "\\<\\<";
guilClose = "\\>\\>";
} else if (opt[0].equals("-view")) {
viewName = opt[1];
} else if (opt[0].equals("-views")) {
findViews = true;
} else if (opt[0].equals("-d")) {
outputDirectory = opt[1];
} else
; // Do nothing, javadoc will handle the option or complain, if needed.
}
@ -235,6 +319,11 @@ class Options implements Cloneable {
FileOutputStream fos = new FileOutputStream(outputFileName);
w = new PrintWriter(new BufferedWriter(new OutputStreamWriter(fos, outputEncoding)));
}
public void closeFile() {
w.close();
}
/**
* Check if the supplied string matches an entity specified

View File

@ -20,9 +20,13 @@
package gr.spinellis.umlgraph.doclet;
import com.sun.javadoc.*;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.io.*;
import com.sun.javadoc.ClassDoc;
import com.sun.javadoc.LanguageVersion;
import com.sun.javadoc.RootDoc;
/**
* Doclet API implementation
@ -37,34 +41,80 @@ public class UmlGraph {
/** Entry point */
public static boolean start(RootDoc root) throws IOException {
Options opt = new Options();
ClassInfo.reset();
opt.setOptions(root.options());
opt.openFile();
opt.setOptions(root.classNamed("UMLOptions"));
View[] views = buildViews(opt, root);
if (views.length == 0) {
buildGraph(root, null, opt);
} else {
for (int i = 0; i < views.length; i++) {
buildGraph(root, views[i], (Options) opt.clone());
}
}
return true;
}
/**
* Builds and outputs a single graph according to the view overrides
*/
private static void buildGraph(RootDoc root, View view, Options opt) throws IOException {
if (view != null)
view.applyOverrides(opt);
opt.openFile();
prologue(opt);
ClassDoc[] classes = root.classes();
ClassGraph c = new ClassGraph(root.specifiedPackages(),
opt.apiDocRoot, opt.apiDocMapFileName);
for (ClassDoc cd : classes) {
ClassGraph c = new ClassGraph(root.specifiedPackages(), opt.apiDocRoot,
opt.apiDocMapFileName);
for (int i = 0; i < classes.length; i++) {
// Process class-local options (through @opt tags)
Options localOpt = (Options) opt.clone();
localOpt.setOptions(cd);
c.printClass(localOpt, cd);
localOpt.setOptions(classes[i]);
if (view != null)
view.applyOverrides(localOpt, classes[i]);
c.printClass(localOpt, classes[i]);
}
for (ClassDoc cd : classes) {
for (int i = 0; i < classes.length; i++) {
// Process class-local options (through @opt tags)
Options localOpt = (Options) opt.clone();
localOpt.setOptions(cd);
c.printRelations(localOpt, cd);
localOpt.setOptions(classes[i]);
if (view != null)
view.applyOverrides(localOpt, classes[i]);
c.printRelations(localOpt, classes[i]);
}
c.printExtraClasses(opt, root);
epilogue(opt);
return true;
opt.closeFile();
}
/**
* Builds the views according to the parameters on the command line
*/
private static View[] buildViews(Options opt, RootDoc root) {
if (opt.findViews) {
List<View> views = new ArrayList<View>();
ClassDoc[] classes = root.classes();
for (int i = 0; i < classes.length; i++) {
if (classes[i].tags("view").length > 0) {
views.add(new View(classes[i]));
}
}
return views.toArray(new View[views.size()]);
} else if (opt.viewName != null) {
ClassDoc viewClass = root.classNamed(opt.viewName);
return new View[] { new View(viewClass) };
} else {
return new View[0];
}
}
/** Option checking */
public static int optionLength(String option) {
return Options.optionLength(option);

View File

@ -0,0 +1,101 @@
/*
* Contibuted by Andrea Aime
* (C) Copyright 2005 Diomidis Spinellis
*
* Permission to use, copy, and distribute this software and its
* documentation for any purpose and without fee is hereby granted,
* provided that the above copyright notice appear in all copies and that
* both that copyright notice and this permission notice appear in
* supporting documentation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
* $Id$
*
*/
package gr.spinellis.umlgraph.doclet;
import java.io.File;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
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;
/**
* Contains the definition of a View. A View is a set of option overrides
* that 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
*
*/
class View {
Map<Pattern, String[]> optionOverrides = new LinkedHashMap<Pattern, String[]>();
ClassDoc viewDoc;
public View(ClassDoc c) {
this.viewDoc = c;
Tag[] tags = c.tags("opt_override");
for (int i = 0; i < tags.length; i++) {
String[] opts = StringUtil.tokenize(tags[i].text());
try {
optionOverrides.put(Pattern.compile(opts[0]), opts);
} catch (PatternSyntaxException e) {
System.err.println("Skipping invalid pattern " + opts[0] + " in view "
+ c.toString());
}
}
}
/**
* Applies global view overrides
*/
public void applyOverrides(Options o) {
o.setOptions(viewDoc);
File dotFile = new File(o.outputDirectory, viewDoc.name() + ".dot");
o.setOption(new String[] {"-output", dotFile.getPath()});
}
/**
* Applies local view overrides
*/
public void applyOverrides(Options o, ClassDoc c) {
String className = c.toString();
for (Iterator<Map.Entry<Pattern, String[]>> iter = optionOverrides.entrySet().iterator(); iter
.hasNext();) {
Map.Entry<Pattern, String[]> mapEntry = iter.next();
Pattern regex = mapEntry.getKey();
Matcher matcher = regex.matcher(className);
if (matcher.matches()) {
String[] overrides = mapEntry.getValue(); // the first element is in fact the pattern
for (int i = 1; i < overrides.length; i++) {
String[] option = null;
boolean reset = false;
if (overrides[i].contains("=")) {
option = overrides[i].split("=");
} else {
option = new String[] { overrides[i] };
}
if (option[0].charAt(0) == '!') {
reset = true;
option[0] = option[0].substring(1);
}
option[0] = "-" + option[0];
if (reset) {
o.resetOption(option);
} else {
o.setOption(option);
}
}
}
}
}
}