mirror of https://github.com/dspinellis/UMLGraph
First stab at UmlDoc implementation. It's an "improved" javadoc that outputs docs along with class diagrams.
Diomidis, can you have a look at the output (UmlGraph javadoc are built with UmlDoc now) and review the code? I know I still have to write the docs, and I will have to try out UmlDoc on something other than UmlGraph itself (was thinking of the java sources themselves, or Hibernate, Spring, ... whatever is big enough).
This commit is contained in:
parent
23fbf7ff19
commit
72f918b68c
|
|
@ -67,7 +67,11 @@ class Version { public static String VERSION = "${VERSION}";}
|
|||
</target>
|
||||
|
||||
<target name="javadocs" depends="compile">
|
||||
<javadoc sourcepath="${src}" packagenames="gr.spinellis.umlgraph.doclet.*" destdir="${javadoc}" package="true"/>
|
||||
<javadoc sourcepath="${src}" packagenames="gr.spinellis.umlgraph.doclet.*" destdir="${javadoc}" package="true">
|
||||
<doclet name="gr.spinellis.umlgraph.doclet.UmlDoc" path="${lib}/UMLGraph.jar">
|
||||
</doclet>
|
||||
</javadoc>
|
||||
|
||||
<property name="outFolder" location="${javadoc}/gr/spinellis/umlgraph/doclet"/>
|
||||
<property name="dotName" value="umlgraph.dot"/>
|
||||
<property name="dotFile" location="${outFolder}/${dotName}"/>
|
||||
|
|
|
|||
|
|
@ -56,6 +56,7 @@ import com.sun.javadoc.WildcardType;
|
|||
/**
|
||||
* Class graph generation engine
|
||||
* @depend - - - StringUtil
|
||||
* @depend - - - Options
|
||||
* @composed - - * ClassInfo
|
||||
* @has - - - OptionProvider
|
||||
*
|
||||
|
|
@ -89,16 +90,26 @@ class ClassGraph {
|
|||
protected ClassDoc mapClassDoc;
|
||||
protected String linePostfix;
|
||||
protected String linePrefix;
|
||||
|
||||
|
||||
// used only when generating context class diagrams in UMLDoc, to generate the proper
|
||||
// relative links to other classes in the image map
|
||||
protected Doc contextDoc;
|
||||
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* Create a new ClassGraph. <p>The packages passed as an
|
||||
* argument are the ones specified on the command line.</p>
|
||||
* <p>Local URLs will be generated for these packages.</p>
|
||||
* @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)
|
||||
*/
|
||||
public ClassGraph(RootDoc root, OptionProvider optionProvider) throws IOException {
|
||||
public ClassGraph(RootDoc root, OptionProvider optionProvider, Doc contextDoc) throws IOException {
|
||||
this.optionProvider = optionProvider;
|
||||
this.collectionClassDoc = root.classNamed("java.util.Collection");
|
||||
this.mapClassDoc = root.classNamed("java.util.Map");
|
||||
this.contextDoc = contextDoc;
|
||||
|
||||
specifiedPackages = new HashSet<String>();
|
||||
for (PackageDoc p : root.specifiedPackages())
|
||||
|
|
@ -447,7 +458,7 @@ class ClassGraph {
|
|||
w.println("\t// " + r);
|
||||
// Create label
|
||||
w.print("\t" + ci.name + " [label=");
|
||||
externalTableStart(opt, c.qualifiedName());
|
||||
externalTableStart(opt, c.qualifiedName(), classToUrl(c));
|
||||
innerTableStart();
|
||||
if (c.isInterface())
|
||||
tableLine(Align.CENTER, guilWrap(opt, "interface"));
|
||||
|
|
@ -656,7 +667,7 @@ class ClassGraph {
|
|||
continue;
|
||||
w.println("\t// " + className);
|
||||
w.print("\t" + info.name + "[label=");
|
||||
externalTableStart(opt, className);
|
||||
externalTableStart(opt, className, classToUrl(className));
|
||||
innerTableStart();
|
||||
int idx = className.lastIndexOf(".");
|
||||
if(opt.postfixPackage && idx > 0 && idx < (className.length() - 1)) {
|
||||
|
|
@ -847,24 +858,76 @@ class ClassGraph {
|
|||
return name.substring(0, openIdx);
|
||||
}
|
||||
|
||||
/** Return true if the class name has been specified in the command line */
|
||||
/**
|
||||
* 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) {
|
||||
// building relative path for context and package diagrams
|
||||
if(contextDoc != null && isSpecifiedPackage(cd)) {
|
||||
// determine the context path, relative to the root
|
||||
String[] contextClassPath = null;
|
||||
if(contextDoc instanceof ClassDoc) {
|
||||
contextClassPath = ((ClassDoc) contextDoc).containingPackage().name().split("\\.");
|
||||
} else if(contextDoc instanceof PackageDoc) {
|
||||
contextClassPath = ((PackageDoc) contextDoc).name().split("\\.");
|
||||
} else {
|
||||
return classToUrl(cd.qualifiedName());
|
||||
}
|
||||
|
||||
// path, relative to the root, of the destination class
|
||||
String[] currClassPath = cd.containingPackage().name().split("\\.");
|
||||
|
||||
// compute relative path between the context and the destination
|
||||
// ... first, compute common part
|
||||
int i = 0;
|
||||
while(i < contextClassPath.length && i < currClassPath.length
|
||||
&& contextClassPath[i].equals(currClassPath[i]))
|
||||
i++;
|
||||
// ... go up with ".." to reach the common root
|
||||
StringBuffer buf = new StringBuffer();
|
||||
if(i == contextClassPath.length) {
|
||||
buf.append(".").append(FILE_SEPARATOR);
|
||||
} else {
|
||||
for (int j = i; j < currClassPath.length; j++) {
|
||||
buf.append("..").append(FILE_SEPARATOR);
|
||||
}
|
||||
}
|
||||
// ... go down from the common root to the destination
|
||||
for (int j = i; j < currClassPath.length; j++) {
|
||||
buf.append(currClassPath[j]).append(FILE_SEPARATOR);
|
||||
}
|
||||
buf.append(cd.name()).append(".html");
|
||||
return buf.toString();
|
||||
} else {
|
||||
return classToUrl(cd.qualifiedName());
|
||||
}
|
||||
}
|
||||
|
||||
/** Convert the class name into a corresponding URL */
|
||||
public String classToUrl(String className) {
|
||||
String result = null;
|
||||
String docRoot = mapApiDocRoot(className);
|
||||
if (docRoot != null) {
|
||||
StringBuffer buf = new StringBuffer(docRoot);
|
||||
buf.append(className.replace('.', FILE_SEPARATOR));
|
||||
buf.append(".html");
|
||||
result = buf.toString();
|
||||
}
|
||||
return result;
|
||||
String docRoot = mapApiDocRoot(className);
|
||||
if (docRoot != null) {
|
||||
StringBuffer buf = new StringBuffer(docRoot);
|
||||
buf.append(className.replace('.', FILE_SEPARATOR));
|
||||
buf.append(".html");
|
||||
return buf.toString();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -944,12 +1007,11 @@ class ClassGraph {
|
|||
w.close();
|
||||
}
|
||||
|
||||
private void externalTableStart(Options opt, String name) {
|
||||
private void externalTableStart(Options opt, String name, String url) {
|
||||
String bgcolor = "";
|
||||
if (opt.nodeFillColor != null)
|
||||
bgcolor = " bgcolor=\""+ opt.nodeFillColor + "\"";
|
||||
String href = "";
|
||||
String url = classToUrl(name);
|
||||
if (url != null)
|
||||
href = " href=\"" + url + "\"";
|
||||
w.print("<<table border=\"0\" cellborder=\"1\" cellspacing=\"0\" "
|
||||
|
|
|
|||
|
|
@ -128,7 +128,7 @@ public class ContextMatcher implements ClassMatcher {
|
|||
private static class ClassGraphHack extends ClassGraph {
|
||||
|
||||
public ClassGraphHack(RootDoc root, OptionProvider optionProvider) throws IOException {
|
||||
super(root, optionProvider);
|
||||
super(root, optionProvider, null);
|
||||
prologue();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,74 @@
|
|||
package gr.spinellis.umlgraph.doclet;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import com.sun.javadoc.ClassDoc;
|
||||
import com.sun.javadoc.RootDoc;
|
||||
|
||||
/**
|
||||
* A view designed for UMLDoc, filters out everything that it's not directly
|
||||
* connected to the center class of the context.
|
||||
* <p>
|
||||
* As such, can be viewed as a simplified version of a {@linkplain View} using a
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
public class ContextView implements OptionProvider {
|
||||
|
||||
private ClassDoc cd;
|
||||
private OptionProvider parent;
|
||||
private ContextMatcher matcher;
|
||||
private String outputPath;
|
||||
|
||||
public ContextView(String outputFolder, ClassDoc cd, RootDoc root, OptionProvider parent)
|
||||
throws IOException {
|
||||
this.parent = parent;
|
||||
this.cd = cd;
|
||||
this.matcher = new ContextMatcher(root, Pattern.compile(cd.qualifiedName()),
|
||||
getGlobalOptions());
|
||||
this.outputPath = cd.containingPackage().name().replace('.', '/') + "/" + cd.name()
|
||||
+ ".dot";
|
||||
}
|
||||
|
||||
public String getDisplayName() {
|
||||
return "Context view for class " + cd;
|
||||
}
|
||||
|
||||
public Options getGlobalOptions() {
|
||||
Options go = parent.getGlobalOptions();
|
||||
|
||||
go.setOption(new String[] { "-output", outputPath });
|
||||
go.setOption(new String[] { "-hide" });
|
||||
|
||||
return go;
|
||||
}
|
||||
|
||||
public Options getOptionsFor(ClassDoc cd) {
|
||||
Options go = parent.getGlobalOptions();
|
||||
overrideForClass(go, cd);
|
||||
return go;
|
||||
}
|
||||
|
||||
public Options getOptionsFor(String name) {
|
||||
Options go = parent.getGlobalOptions();
|
||||
overrideForClass(go, name);
|
||||
return go;
|
||||
}
|
||||
|
||||
public void overrideForClass(Options opt, ClassDoc cd) {
|
||||
if (parent.getGlobalOptions().matchesHideExpression(cd.name()) || !matcher.matches(cd))
|
||||
opt.setOption(new String[] { "-hide" });
|
||||
if (cd.equals(this.cd))
|
||||
opt.nodeFillColor = "lemonChiffon";
|
||||
}
|
||||
|
||||
public void overrideForClass(Options opt, String className) {
|
||||
if (!matcher.matches(className))
|
||||
opt.setOption(new String[] { "-hide" });
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -97,6 +97,8 @@ class Options implements Cloneable, OptionProvider {
|
|||
String inferRelationshipType;
|
||||
private Vector<Pattern> collPackages;
|
||||
public boolean compact;
|
||||
// internal option, used by UMLDoc to generate relative links between classes
|
||||
boolean relativeLinksForSourcePackages;
|
||||
|
||||
Options() {
|
||||
showQualified = false;
|
||||
|
|
@ -141,6 +143,7 @@ class Options implements Cloneable, OptionProvider {
|
|||
inferRelationshipType = "navassoc";
|
||||
collPackages = new Vector<Pattern>();
|
||||
compact = false;
|
||||
relativeLinksForSourcePackages = false;
|
||||
}
|
||||
|
||||
public Object clone() {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,26 @@
|
|||
package gr.spinellis.umlgraph.doclet;
|
||||
|
||||
import com.sun.javadoc.ClassDoc;
|
||||
import com.sun.javadoc.PackageDoc;
|
||||
|
||||
public class PackageMatcher implements ClassMatcher {
|
||||
protected PackageDoc packageDoc;
|
||||
|
||||
public PackageMatcher(PackageDoc packageDoc) {
|
||||
super();
|
||||
this.packageDoc = packageDoc;
|
||||
}
|
||||
|
||||
public boolean matches(ClassDoc cd) {
|
||||
return cd.containingPackage().equals(packageDoc);
|
||||
}
|
||||
|
||||
public boolean matches(String name) {
|
||||
for (ClassDoc cd : packageDoc.allClasses()) {
|
||||
if (cd.qualifiedName().equals(name))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
package gr.spinellis.umlgraph.doclet;
|
||||
|
||||
import com.sun.javadoc.ClassDoc;
|
||||
import com.sun.javadoc.PackageDoc;
|
||||
import com.sun.javadoc.RootDoc;
|
||||
|
||||
/**
|
||||
* A view designed for UMLDoc, filters out everything that it's not contained in
|
||||
* the specified package.
|
||||
* <p>
|
||||
* As such, can be viewed as a simplified version of a {@linkplain View} using a
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
public class PackageView implements OptionProvider {
|
||||
|
||||
private PackageDoc pd;
|
||||
private OptionProvider parent;
|
||||
private ClassMatcher matcher;
|
||||
private String outputPath;
|
||||
|
||||
public PackageView(String outputFolder, PackageDoc pd, RootDoc root, OptionProvider parent) {
|
||||
this.parent = parent;
|
||||
this.pd = pd;
|
||||
this.matcher = new PackageMatcher(pd);
|
||||
this.outputPath = pd.name().replace('.', '/') + "/" + pd.name() + ".dot";
|
||||
}
|
||||
|
||||
public String getDisplayName() {
|
||||
return "Package view for packages" + pd;
|
||||
}
|
||||
|
||||
public Options getGlobalOptions() {
|
||||
Options go = parent.getGlobalOptions();
|
||||
|
||||
go.setOption(new String[] { "-output", outputPath });
|
||||
go.setOption(new String[] { "-hide" });
|
||||
|
||||
return go;
|
||||
}
|
||||
|
||||
public Options getOptionsFor(ClassDoc cd) {
|
||||
Options go = parent.getGlobalOptions();
|
||||
overrideForClass(go, cd);
|
||||
return go;
|
||||
}
|
||||
|
||||
public Options getOptionsFor(String name) {
|
||||
Options go = parent.getGlobalOptions();
|
||||
overrideForClass(go, name);
|
||||
return go;
|
||||
}
|
||||
|
||||
public void overrideForClass(Options opt, ClassDoc cd) {
|
||||
if (!matcher.matches(cd) || parent.getGlobalOptions().matchesHideExpression(cd.name()))
|
||||
opt.setOption(new String[] { "-hide" });
|
||||
}
|
||||
|
||||
public void overrideForClass(Options opt, String className) {
|
||||
if (!matcher.matches(className))
|
||||
opt.setOption(new String[] { "-hide" });
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,196 @@
|
|||
package gr.spinellis.umlgraph.doclet;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
|
||||
import com.sun.javadoc.ClassDoc;
|
||||
import com.sun.javadoc.LanguageVersion;
|
||||
import com.sun.javadoc.PackageDoc;
|
||||
import com.sun.javadoc.RootDoc;
|
||||
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
|
||||
*
|
||||
*/
|
||||
public class UmlDoc {
|
||||
public static int optionLength(String option) {
|
||||
int result = Standard.optionLength(option);
|
||||
if (result != 0)
|
||||
return result;
|
||||
else
|
||||
return UmlGraph.optionLength(option);
|
||||
}
|
||||
|
||||
public static boolean start(RootDoc root) throws IOException {
|
||||
if (Standard.start(root)) {
|
||||
String outputFolder = findOutputPath(root.options());
|
||||
|
||||
Options opt = new Options();
|
||||
opt.setOptions(root.options());
|
||||
opt.relativeLinksForSourcePackages = true;
|
||||
|
||||
generatePackageDiagrams(root, opt, outputFolder);
|
||||
generateContextDiagrams(root, opt, outputFolder);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static LanguageVersion languageVersion() {
|
||||
return Standard.languageVersion();
|
||||
}
|
||||
|
||||
private static void generatePackageDiagrams(RootDoc root, Options opt, String outputFolder)
|
||||
throws IOException {
|
||||
if (opt.verbose2)
|
||||
System.out.println("Examining packages");
|
||||
for (PackageDoc packageDoc : root.specifiedPackages()) {
|
||||
if (opt.verbose2)
|
||||
System.out.println("Altering javadocs for pacakge " + packageDoc);
|
||||
OptionProvider view = new PackageView(outputFolder, packageDoc, root, opt);
|
||||
UmlGraph.buildGraph(root, view, packageDoc);
|
||||
runGraphviz(outputFolder, packageDoc.name(), packageDoc.name());
|
||||
alterHtmlDocs(outputFolder, packageDoc.name(), packageDoc.name(),
|
||||
"package-summary.html", "</H2>");
|
||||
}
|
||||
}
|
||||
|
||||
private static void generateContextDiagrams(RootDoc root, Options opt, String outputFolder)
|
||||
throws IOException {
|
||||
if (opt.verbose2)
|
||||
System.out.println("Examining classes");
|
||||
for (ClassDoc classDoc : root.classes()) {
|
||||
if (!isIncluded(classDoc, root.specifiedPackages()))
|
||||
continue;
|
||||
if (opt.verbose2)
|
||||
System.out.println("Altering class doc for " + classDoc);
|
||||
ContextView view = new ContextView(outputFolder, classDoc, root, opt);
|
||||
UmlGraph.buildGraph(root, view, classDoc);
|
||||
runGraphviz(outputFolder, classDoc.containingPackage().name(), classDoc.name());
|
||||
alterHtmlDocs(outputFolder, classDoc.containingPackage().name(), classDoc.name(),
|
||||
classDoc.name() + ".html", classDoc.name() + "</H2>");
|
||||
}
|
||||
}
|
||||
|
||||
private static void runGraphviz(String outputFolder, String packageName, String name) {
|
||||
File dotFile = new File(outputFolder, packageName.replace(".", "/") + "/" + name + ".dot");
|
||||
File pngFile = new File(outputFolder, packageName.replace(".", "/") + "/" + name + ".png");
|
||||
File mapFile = new File(outputFolder, packageName.replace(".", "/") + "/" + name + ".map");
|
||||
|
||||
try {
|
||||
String command = "dot -Tcmapx -o" + mapFile.getAbsolutePath() + " -Tpng -o"
|
||||
+ pngFile.getAbsolutePath() + " " + dotFile.getAbsolutePath();
|
||||
Process p = Runtime.getRuntime().exec(command);
|
||||
int result = p.waitFor();
|
||||
if (result != 0)
|
||||
System.out.println("Errors running Graphviz on " + dotFile);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private static void alterHtmlDocs(String outputFolder, String packageName, String name,
|
||||
String htmlFileName, String matchLineEnd) throws IOException {
|
||||
// setup files
|
||||
File output = new File(outputFolder, packageName.replace(".", "/"));
|
||||
File htmlFile = new File(output, htmlFileName);
|
||||
File alteredFile = new File(htmlFile.getAbsolutePath() + ".uml");
|
||||
File mapFile = new File(output, name + ".map");
|
||||
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 FileWriter(alteredFile));
|
||||
reader = new BufferedReader(new FileReader(htmlFile));
|
||||
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
writer.write(line);
|
||||
writer.newLine();
|
||||
if (!matched && line.endsWith(matchLineEnd)) {
|
||||
matched = true;
|
||||
if (mapFile.exists())
|
||||
insertClientSideMap(mapFile, writer);
|
||||
else
|
||||
System.out.println("Could not find map file " + mapFile);
|
||||
writer.write("<div align=\"center\"><img src=\"" + name
|
||||
+ ".png\" alt=\"Package class diagram package " + name
|
||||
+ "\" usemap=\"#G\" border=0/></a></div>");
|
||||
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 {
|
||||
System.out.println("Error, could not find a line that ends with '" + matchLineEnd
|
||||
+ "'.\n Class diagram reference not inserted");
|
||||
alteredFile.delete();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the map file and outputs in to the specified writer
|
||||
* @throws IOException
|
||||
*/
|
||||
private static void insertClientSideMap(File mapFile, BufferedWriter writer) throws IOException {
|
||||
BufferedReader reader = null;
|
||||
try {
|
||||
reader = new BufferedReader(new FileReader(mapFile));
|
||||
String line = null;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
writer.write(line);
|
||||
writer.newLine();
|
||||
}
|
||||
} finally {
|
||||
if (reader != null)
|
||||
reader.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the class name has been specified in the command line
|
||||
*/
|
||||
private static boolean isIncluded(ClassDoc cd, PackageDoc[] docs) {
|
||||
for (PackageDoc pd : docs) {
|
||||
for (ClassDoc pcd : pd.allClasses())
|
||||
if (pcd.equals(cd))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 ".";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -25,6 +25,7 @@ import java.util.ArrayList;
|
|||
import java.util.List;
|
||||
|
||||
import com.sun.javadoc.ClassDoc;
|
||||
import com.sun.javadoc.Doc;
|
||||
import com.sun.javadoc.LanguageVersion;
|
||||
import com.sun.javadoc.RootDoc;
|
||||
|
||||
|
|
@ -52,10 +53,10 @@ public class UmlGraph {
|
|||
if(views == null)
|
||||
return false;
|
||||
if (views.length == 0) {
|
||||
buildGraph(root, opt);
|
||||
buildGraph(root, opt, null);
|
||||
} else {
|
||||
for (int i = 0; i < views.length; i++) {
|
||||
buildGraph(root, views[i]);
|
||||
buildGraph(root, views[i], null);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -76,13 +77,13 @@ public class UmlGraph {
|
|||
/**
|
||||
* Builds and outputs a single graph according to the view overrides
|
||||
*/
|
||||
private static void buildGraph(RootDoc root, OptionProvider op) throws IOException {
|
||||
public static void buildGraph(RootDoc root, OptionProvider op, Doc contextDoc) throws IOException {
|
||||
Options opt = op.getGlobalOptions();
|
||||
if (opt.verbose2)
|
||||
System.out.println("Building " + op.getDisplayName());
|
||||
ClassDoc[] classes = root.classes();
|
||||
|
||||
ClassGraph c = new ClassGraph(root, op);
|
||||
ClassGraph c = new ClassGraph(root, op, contextDoc);
|
||||
c.prologue();
|
||||
for (int i = 0; i < classes.length; i++) {
|
||||
c.printClass(classes[i]);
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ import com.sun.javadoc.Tag;
|
|||
* @depend - - - InterfaceMatcher
|
||||
* @depend - - - PatternMatcher
|
||||
* @depend - - - SubclassMatcher
|
||||
* @depend - - - ContextMatcher
|
||||
*
|
||||
*/
|
||||
class View implements OptionProvider {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* UmlGraph class diagram testing framework
|
||||
*
|
||||
* 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.test;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.PrintWriter;
|
||||
|
||||
public class RunDoc {
|
||||
|
||||
static String sourcesFolder = "src";
|
||||
|
||||
static String docFolder = "javadoc";
|
||||
|
||||
static PrintWriter pw = new PrintWriter(System.out);
|
||||
|
||||
public static void main(String[] args) {
|
||||
File outFolder = new File(docFolder);
|
||||
if (!outFolder.exists())
|
||||
outFolder.mkdirs();
|
||||
String[] options = new String[] { "-docletpath", "build", "-private", "-d", docFolder,
|
||||
"-sourcepath", sourcesFolder, "-subpackages", "gr.spinellis" };
|
||||
runDoclet(options);
|
||||
}
|
||||
|
||||
private static void runDoclet(String[] options) {
|
||||
com.sun.tools.javadoc.Main.execute("UMLGraph test", pw, pw, pw,
|
||||
"gr.spinellis.umlgraph.doclet.UmlDoc", options);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -36,8 +36,8 @@ public class RunOne {
|
|||
if (!outFolder.exists())
|
||||
outFolder.mkdirs();
|
||||
|
||||
runView("gr.spinellis.views.ViewChildEmpty");
|
||||
runSingleClass("foo");
|
||||
// runView("gr.spinellis.views.ViewChildEmpty");
|
||||
runSingleClass("TestHiddenOp");
|
||||
}
|
||||
|
||||
public static void runView(String viewClass) {
|
||||
|
|
|
|||
|
|
@ -56,6 +56,7 @@ import com.sun.javadoc.WildcardType;
|
|||
/**
|
||||
* Class graph generation engine
|
||||
* @depend - - - StringUtil
|
||||
* @depend - - - Options
|
||||
* @composed - - * ClassInfo
|
||||
* @has - - - OptionProvider
|
||||
*
|
||||
|
|
@ -89,16 +90,26 @@ class ClassGraph {
|
|||
protected ClassDoc mapClassDoc;
|
||||
protected String linePostfix;
|
||||
protected String linePrefix;
|
||||
|
||||
|
||||
// used only when generating context class diagrams in UMLDoc, to generate the proper
|
||||
// relative links to other classes in the image map
|
||||
protected Doc contextDoc;
|
||||
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* Create a new ClassGraph. <p>The packages passed as an
|
||||
* argument are the ones specified on the command line.</p>
|
||||
* <p>Local URLs will be generated for these packages.</p>
|
||||
* @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)
|
||||
*/
|
||||
public ClassGraph(RootDoc root, OptionProvider optionProvider) throws IOException {
|
||||
public ClassGraph(RootDoc root, OptionProvider optionProvider, Doc contextDoc) throws IOException {
|
||||
this.optionProvider = optionProvider;
|
||||
this.collectionClassDoc = root.classNamed("java.util.Collection");
|
||||
this.mapClassDoc = root.classNamed("java.util.Map");
|
||||
this.contextDoc = contextDoc;
|
||||
|
||||
specifiedPackages = new HashSet<String>();
|
||||
for (PackageDoc p : root.specifiedPackages())
|
||||
|
|
@ -447,7 +458,7 @@ class ClassGraph {
|
|||
w.println("\t// " + r);
|
||||
// Create label
|
||||
w.print("\t" + ci.name + " [label=");
|
||||
externalTableStart(opt, c.qualifiedName());
|
||||
externalTableStart(opt, c.qualifiedName(), classToUrl(c));
|
||||
innerTableStart();
|
||||
if (c.isInterface())
|
||||
tableLine(Align.CENTER, guilWrap(opt, "interface"));
|
||||
|
|
@ -656,7 +667,7 @@ class ClassGraph {
|
|||
continue;
|
||||
w.println("\t// " + className);
|
||||
w.print("\t" + info.name + "[label=");
|
||||
externalTableStart(opt, className);
|
||||
externalTableStart(opt, className, classToUrl(className));
|
||||
innerTableStart();
|
||||
int idx = className.lastIndexOf(".");
|
||||
if(opt.postfixPackage && idx > 0 && idx < (className.length() - 1)) {
|
||||
|
|
@ -847,24 +858,76 @@ class ClassGraph {
|
|||
return name.substring(0, openIdx);
|
||||
}
|
||||
|
||||
/** Return true if the class name has been specified in the command line */
|
||||
/**
|
||||
* 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) {
|
||||
// building relative path for context and package diagrams
|
||||
if(contextDoc != null && isSpecifiedPackage(cd)) {
|
||||
// determine the context path, relative to the root
|
||||
String[] contextClassPath = null;
|
||||
if(contextDoc instanceof ClassDoc) {
|
||||
contextClassPath = ((ClassDoc) contextDoc).containingPackage().name().split("\\.");
|
||||
} else if(contextDoc instanceof PackageDoc) {
|
||||
contextClassPath = ((PackageDoc) contextDoc).name().split("\\.");
|
||||
} else {
|
||||
return classToUrl(cd.qualifiedName());
|
||||
}
|
||||
|
||||
// path, relative to the root, of the destination class
|
||||
String[] currClassPath = cd.containingPackage().name().split("\\.");
|
||||
|
||||
// compute relative path between the context and the destination
|
||||
// ... first, compute common part
|
||||
int i = 0;
|
||||
while(i < contextClassPath.length && i < currClassPath.length
|
||||
&& contextClassPath[i].equals(currClassPath[i]))
|
||||
i++;
|
||||
// ... go up with ".." to reach the common root
|
||||
StringBuffer buf = new StringBuffer();
|
||||
if(i == contextClassPath.length) {
|
||||
buf.append(".").append(FILE_SEPARATOR);
|
||||
} else {
|
||||
for (int j = i; j < currClassPath.length; j++) {
|
||||
buf.append("..").append(FILE_SEPARATOR);
|
||||
}
|
||||
}
|
||||
// ... go down from the common root to the destination
|
||||
for (int j = i; j < currClassPath.length; j++) {
|
||||
buf.append(currClassPath[j]).append(FILE_SEPARATOR);
|
||||
}
|
||||
buf.append(cd.name()).append(".html");
|
||||
return buf.toString();
|
||||
} else {
|
||||
return classToUrl(cd.qualifiedName());
|
||||
}
|
||||
}
|
||||
|
||||
/** Convert the class name into a corresponding URL */
|
||||
public String classToUrl(String className) {
|
||||
String result = null;
|
||||
String docRoot = mapApiDocRoot(className);
|
||||
if (docRoot != null) {
|
||||
StringBuffer buf = new StringBuffer(docRoot);
|
||||
buf.append(className.replace('.', FILE_SEPARATOR));
|
||||
buf.append(".html");
|
||||
result = buf.toString();
|
||||
}
|
||||
return result;
|
||||
String docRoot = mapApiDocRoot(className);
|
||||
if (docRoot != null) {
|
||||
StringBuffer buf = new StringBuffer(docRoot);
|
||||
buf.append(className.replace('.', FILE_SEPARATOR));
|
||||
buf.append(".html");
|
||||
return buf.toString();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -944,12 +1007,11 @@ class ClassGraph {
|
|||
w.close();
|
||||
}
|
||||
|
||||
private void externalTableStart(Options opt, String name) {
|
||||
private void externalTableStart(Options opt, String name, String url) {
|
||||
String bgcolor = "";
|
||||
if (opt.nodeFillColor != null)
|
||||
bgcolor = " bgcolor=\""+ opt.nodeFillColor + "\"";
|
||||
String href = "";
|
||||
String url = classToUrl(name);
|
||||
if (url != null)
|
||||
href = " href=\"" + url + "\"";
|
||||
w.print("<<table border=\"0\" cellborder=\"1\" cellspacing=\"0\" "
|
||||
|
|
|
|||
|
|
@ -128,7 +128,7 @@ public class ContextMatcher implements ClassMatcher {
|
|||
private static class ClassGraphHack extends ClassGraph {
|
||||
|
||||
public ClassGraphHack(RootDoc root, OptionProvider optionProvider) throws IOException {
|
||||
super(root, optionProvider);
|
||||
super(root, optionProvider, null);
|
||||
prologue();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,74 @@
|
|||
package gr.spinellis.umlgraph.doclet;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import com.sun.javadoc.ClassDoc;
|
||||
import com.sun.javadoc.RootDoc;
|
||||
|
||||
/**
|
||||
* A view designed for UMLDoc, filters out everything that it's not directly
|
||||
* connected to the center class of the context.
|
||||
* <p>
|
||||
* As such, can be viewed as a simplified version of a {@linkplain View} using a
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
public class ContextView implements OptionProvider {
|
||||
|
||||
private ClassDoc cd;
|
||||
private OptionProvider parent;
|
||||
private ContextMatcher matcher;
|
||||
private String outputPath;
|
||||
|
||||
public ContextView(String outputFolder, ClassDoc cd, RootDoc root, OptionProvider parent)
|
||||
throws IOException {
|
||||
this.parent = parent;
|
||||
this.cd = cd;
|
||||
this.matcher = new ContextMatcher(root, Pattern.compile(cd.qualifiedName()),
|
||||
getGlobalOptions());
|
||||
this.outputPath = cd.containingPackage().name().replace('.', '/') + "/" + cd.name()
|
||||
+ ".dot";
|
||||
}
|
||||
|
||||
public String getDisplayName() {
|
||||
return "Context view for class " + cd;
|
||||
}
|
||||
|
||||
public Options getGlobalOptions() {
|
||||
Options go = parent.getGlobalOptions();
|
||||
|
||||
go.setOption(new String[] { "-output", outputPath });
|
||||
go.setOption(new String[] { "-hide" });
|
||||
|
||||
return go;
|
||||
}
|
||||
|
||||
public Options getOptionsFor(ClassDoc cd) {
|
||||
Options go = parent.getGlobalOptions();
|
||||
overrideForClass(go, cd);
|
||||
return go;
|
||||
}
|
||||
|
||||
public Options getOptionsFor(String name) {
|
||||
Options go = parent.getGlobalOptions();
|
||||
overrideForClass(go, name);
|
||||
return go;
|
||||
}
|
||||
|
||||
public void overrideForClass(Options opt, ClassDoc cd) {
|
||||
if (parent.getGlobalOptions().matchesHideExpression(cd.name()) || !matcher.matches(cd))
|
||||
opt.setOption(new String[] { "-hide" });
|
||||
if (cd.equals(this.cd))
|
||||
opt.nodeFillColor = "lemonChiffon";
|
||||
}
|
||||
|
||||
public void overrideForClass(Options opt, String className) {
|
||||
if (!matcher.matches(className))
|
||||
opt.setOption(new String[] { "-hide" });
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -97,6 +97,8 @@ class Options implements Cloneable, OptionProvider {
|
|||
String inferRelationshipType;
|
||||
private Vector<Pattern> collPackages;
|
||||
public boolean compact;
|
||||
// internal option, used by UMLDoc to generate relative links between classes
|
||||
boolean relativeLinksForSourcePackages;
|
||||
|
||||
Options() {
|
||||
showQualified = false;
|
||||
|
|
@ -141,6 +143,7 @@ class Options implements Cloneable, OptionProvider {
|
|||
inferRelationshipType = "navassoc";
|
||||
collPackages = new Vector<Pattern>();
|
||||
compact = false;
|
||||
relativeLinksForSourcePackages = false;
|
||||
}
|
||||
|
||||
public Object clone() {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,26 @@
|
|||
package gr.spinellis.umlgraph.doclet;
|
||||
|
||||
import com.sun.javadoc.ClassDoc;
|
||||
import com.sun.javadoc.PackageDoc;
|
||||
|
||||
public class PackageMatcher implements ClassMatcher {
|
||||
protected PackageDoc packageDoc;
|
||||
|
||||
public PackageMatcher(PackageDoc packageDoc) {
|
||||
super();
|
||||
this.packageDoc = packageDoc;
|
||||
}
|
||||
|
||||
public boolean matches(ClassDoc cd) {
|
||||
return cd.containingPackage().equals(packageDoc);
|
||||
}
|
||||
|
||||
public boolean matches(String name) {
|
||||
for (ClassDoc cd : packageDoc.allClasses()) {
|
||||
if (cd.qualifiedName().equals(name))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
package gr.spinellis.umlgraph.doclet;
|
||||
|
||||
import com.sun.javadoc.ClassDoc;
|
||||
import com.sun.javadoc.PackageDoc;
|
||||
import com.sun.javadoc.RootDoc;
|
||||
|
||||
/**
|
||||
* A view designed for UMLDoc, filters out everything that it's not contained in
|
||||
* the specified package.
|
||||
* <p>
|
||||
* As such, can be viewed as a simplified version of a {@linkplain View} using a
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
public class PackageView implements OptionProvider {
|
||||
|
||||
private PackageDoc pd;
|
||||
private OptionProvider parent;
|
||||
private ClassMatcher matcher;
|
||||
private String outputPath;
|
||||
|
||||
public PackageView(String outputFolder, PackageDoc pd, RootDoc root, OptionProvider parent) {
|
||||
this.parent = parent;
|
||||
this.pd = pd;
|
||||
this.matcher = new PackageMatcher(pd);
|
||||
this.outputPath = pd.name().replace('.', '/') + "/" + pd.name() + ".dot";
|
||||
}
|
||||
|
||||
public String getDisplayName() {
|
||||
return "Package view for packages" + pd;
|
||||
}
|
||||
|
||||
public Options getGlobalOptions() {
|
||||
Options go = parent.getGlobalOptions();
|
||||
|
||||
go.setOption(new String[] { "-output", outputPath });
|
||||
go.setOption(new String[] { "-hide" });
|
||||
|
||||
return go;
|
||||
}
|
||||
|
||||
public Options getOptionsFor(ClassDoc cd) {
|
||||
Options go = parent.getGlobalOptions();
|
||||
overrideForClass(go, cd);
|
||||
return go;
|
||||
}
|
||||
|
||||
public Options getOptionsFor(String name) {
|
||||
Options go = parent.getGlobalOptions();
|
||||
overrideForClass(go, name);
|
||||
return go;
|
||||
}
|
||||
|
||||
public void overrideForClass(Options opt, ClassDoc cd) {
|
||||
if (!matcher.matches(cd) || parent.getGlobalOptions().matchesHideExpression(cd.name()))
|
||||
opt.setOption(new String[] { "-hide" });
|
||||
}
|
||||
|
||||
public void overrideForClass(Options opt, String className) {
|
||||
if (!matcher.matches(className))
|
||||
opt.setOption(new String[] { "-hide" });
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,196 @@
|
|||
package gr.spinellis.umlgraph.doclet;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
|
||||
import com.sun.javadoc.ClassDoc;
|
||||
import com.sun.javadoc.LanguageVersion;
|
||||
import com.sun.javadoc.PackageDoc;
|
||||
import com.sun.javadoc.RootDoc;
|
||||
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
|
||||
*
|
||||
*/
|
||||
public class UmlDoc {
|
||||
public static int optionLength(String option) {
|
||||
int result = Standard.optionLength(option);
|
||||
if (result != 0)
|
||||
return result;
|
||||
else
|
||||
return UmlGraph.optionLength(option);
|
||||
}
|
||||
|
||||
public static boolean start(RootDoc root) throws IOException {
|
||||
if (Standard.start(root)) {
|
||||
String outputFolder = findOutputPath(root.options());
|
||||
|
||||
Options opt = new Options();
|
||||
opt.setOptions(root.options());
|
||||
opt.relativeLinksForSourcePackages = true;
|
||||
|
||||
generatePackageDiagrams(root, opt, outputFolder);
|
||||
generateContextDiagrams(root, opt, outputFolder);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static LanguageVersion languageVersion() {
|
||||
return Standard.languageVersion();
|
||||
}
|
||||
|
||||
private static void generatePackageDiagrams(RootDoc root, Options opt, String outputFolder)
|
||||
throws IOException {
|
||||
if (opt.verbose2)
|
||||
System.out.println("Examining packages");
|
||||
for (PackageDoc packageDoc : root.specifiedPackages()) {
|
||||
if (opt.verbose2)
|
||||
System.out.println("Altering javadocs for pacakge " + packageDoc);
|
||||
OptionProvider view = new PackageView(outputFolder, packageDoc, root, opt);
|
||||
UmlGraph.buildGraph(root, view, packageDoc);
|
||||
runGraphviz(outputFolder, packageDoc.name(), packageDoc.name());
|
||||
alterHtmlDocs(outputFolder, packageDoc.name(), packageDoc.name(),
|
||||
"package-summary.html", "</H2>");
|
||||
}
|
||||
}
|
||||
|
||||
private static void generateContextDiagrams(RootDoc root, Options opt, String outputFolder)
|
||||
throws IOException {
|
||||
if (opt.verbose2)
|
||||
System.out.println("Examining classes");
|
||||
for (ClassDoc classDoc : root.classes()) {
|
||||
if (!isIncluded(classDoc, root.specifiedPackages()))
|
||||
continue;
|
||||
if (opt.verbose2)
|
||||
System.out.println("Altering class doc for " + classDoc);
|
||||
ContextView view = new ContextView(outputFolder, classDoc, root, opt);
|
||||
UmlGraph.buildGraph(root, view, classDoc);
|
||||
runGraphviz(outputFolder, classDoc.containingPackage().name(), classDoc.name());
|
||||
alterHtmlDocs(outputFolder, classDoc.containingPackage().name(), classDoc.name(),
|
||||
classDoc.name() + ".html", classDoc.name() + "</H2>");
|
||||
}
|
||||
}
|
||||
|
||||
private static void runGraphviz(String outputFolder, String packageName, String name) {
|
||||
File dotFile = new File(outputFolder, packageName.replace(".", "/") + "/" + name + ".dot");
|
||||
File pngFile = new File(outputFolder, packageName.replace(".", "/") + "/" + name + ".png");
|
||||
File mapFile = new File(outputFolder, packageName.replace(".", "/") + "/" + name + ".map");
|
||||
|
||||
try {
|
||||
String command = "dot -Tcmapx -o" + mapFile.getAbsolutePath() + " -Tpng -o"
|
||||
+ pngFile.getAbsolutePath() + " " + dotFile.getAbsolutePath();
|
||||
Process p = Runtime.getRuntime().exec(command);
|
||||
int result = p.waitFor();
|
||||
if (result != 0)
|
||||
System.out.println("Errors running Graphviz on " + dotFile);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private static void alterHtmlDocs(String outputFolder, String packageName, String name,
|
||||
String htmlFileName, String matchLineEnd) throws IOException {
|
||||
// setup files
|
||||
File output = new File(outputFolder, packageName.replace(".", "/"));
|
||||
File htmlFile = new File(output, htmlFileName);
|
||||
File alteredFile = new File(htmlFile.getAbsolutePath() + ".uml");
|
||||
File mapFile = new File(output, name + ".map");
|
||||
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 FileWriter(alteredFile));
|
||||
reader = new BufferedReader(new FileReader(htmlFile));
|
||||
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
writer.write(line);
|
||||
writer.newLine();
|
||||
if (!matched && line.endsWith(matchLineEnd)) {
|
||||
matched = true;
|
||||
if (mapFile.exists())
|
||||
insertClientSideMap(mapFile, writer);
|
||||
else
|
||||
System.out.println("Could not find map file " + mapFile);
|
||||
writer.write("<div align=\"center\"><img src=\"" + name
|
||||
+ ".png\" alt=\"Package class diagram package " + name
|
||||
+ "\" usemap=\"#G\" border=0/></a></div>");
|
||||
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 {
|
||||
System.out.println("Error, could not find a line that ends with '" + matchLineEnd
|
||||
+ "'.\n Class diagram reference not inserted");
|
||||
alteredFile.delete();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the map file and outputs in to the specified writer
|
||||
* @throws IOException
|
||||
*/
|
||||
private static void insertClientSideMap(File mapFile, BufferedWriter writer) throws IOException {
|
||||
BufferedReader reader = null;
|
||||
try {
|
||||
reader = new BufferedReader(new FileReader(mapFile));
|
||||
String line = null;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
writer.write(line);
|
||||
writer.newLine();
|
||||
}
|
||||
} finally {
|
||||
if (reader != null)
|
||||
reader.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the class name has been specified in the command line
|
||||
*/
|
||||
private static boolean isIncluded(ClassDoc cd, PackageDoc[] docs) {
|
||||
for (PackageDoc pd : docs) {
|
||||
for (ClassDoc pcd : pd.allClasses())
|
||||
if (pcd.equals(cd))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 ".";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -25,6 +25,7 @@ import java.util.ArrayList;
|
|||
import java.util.List;
|
||||
|
||||
import com.sun.javadoc.ClassDoc;
|
||||
import com.sun.javadoc.Doc;
|
||||
import com.sun.javadoc.LanguageVersion;
|
||||
import com.sun.javadoc.RootDoc;
|
||||
|
||||
|
|
@ -52,10 +53,10 @@ public class UmlGraph {
|
|||
if(views == null)
|
||||
return false;
|
||||
if (views.length == 0) {
|
||||
buildGraph(root, opt);
|
||||
buildGraph(root, opt, null);
|
||||
} else {
|
||||
for (int i = 0; i < views.length; i++) {
|
||||
buildGraph(root, views[i]);
|
||||
buildGraph(root, views[i], null);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -76,13 +77,13 @@ public class UmlGraph {
|
|||
/**
|
||||
* Builds and outputs a single graph according to the view overrides
|
||||
*/
|
||||
private static void buildGraph(RootDoc root, OptionProvider op) throws IOException {
|
||||
public static void buildGraph(RootDoc root, OptionProvider op, Doc contextDoc) throws IOException {
|
||||
Options opt = op.getGlobalOptions();
|
||||
if (opt.verbose2)
|
||||
System.out.println("Building " + op.getDisplayName());
|
||||
ClassDoc[] classes = root.classes();
|
||||
|
||||
ClassGraph c = new ClassGraph(root, op);
|
||||
ClassGraph c = new ClassGraph(root, op, contextDoc);
|
||||
c.prologue();
|
||||
for (int i = 0; i < classes.length; i++) {
|
||||
c.printClass(classes[i]);
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ import com.sun.javadoc.Tag;
|
|||
* @depend - - - InterfaceMatcher
|
||||
* @depend - - - PatternMatcher
|
||||
* @depend - - - SubclassMatcher
|
||||
* @depend - - - ContextMatcher
|
||||
*
|
||||
*/
|
||||
class View implements OptionProvider {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* UmlGraph class diagram testing framework
|
||||
*
|
||||
* 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.test;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.PrintWriter;
|
||||
|
||||
public class RunDoc {
|
||||
|
||||
static String sourcesFolder = "src";
|
||||
|
||||
static String docFolder = "javadoc";
|
||||
|
||||
static PrintWriter pw = new PrintWriter(System.out);
|
||||
|
||||
public static void main(String[] args) {
|
||||
File outFolder = new File(docFolder);
|
||||
if (!outFolder.exists())
|
||||
outFolder.mkdirs();
|
||||
String[] options = new String[] { "-docletpath", "build", "-private", "-d", docFolder,
|
||||
"-sourcepath", sourcesFolder, "-subpackages", "gr.spinellis" };
|
||||
runDoclet(options);
|
||||
}
|
||||
|
||||
private static void runDoclet(String[] options) {
|
||||
com.sun.tools.javadoc.Main.execute("UMLGraph test", pw, pw, pw,
|
||||
"gr.spinellis.umlgraph.doclet.UmlDoc", options);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -36,8 +36,8 @@ public class RunOne {
|
|||
if (!outFolder.exists())
|
||||
outFolder.mkdirs();
|
||||
|
||||
runView("gr.spinellis.views.ViewChildEmpty");
|
||||
runSingleClass("foo");
|
||||
// runView("gr.spinellis.views.ViewChildEmpty");
|
||||
runSingleClass("TestHiddenOp");
|
||||
}
|
||||
|
||||
public static void runView(String viewClass) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue