mirror of https://github.com/dspinellis/UMLGraph
256 lines
8.5 KiB
Java
256 lines
8.5 KiB
Java
/*
|
|
* Create a graphviz graph based on the classes in the specified java
|
|
* source files.
|
|
*
|
|
* (C) Copyright 2002-2010 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.
|
|
*
|
|
*
|
|
*/
|
|
|
|
package org.umlgraph.doclet;
|
|
|
|
import java.io.IOException;
|
|
import java.util.ArrayList;
|
|
import java.util.Collections;
|
|
import java.util.HashSet;
|
|
import java.util.List;
|
|
import java.util.Locale;
|
|
import java.util.Set;
|
|
|
|
import jdk.javadoc.doclet.Doclet;
|
|
import jdk.javadoc.doclet.DocletEnvironment;
|
|
import jdk.javadoc.doclet.Reporter;
|
|
import jdk.javadoc.doclet.StandardDoclet;
|
|
|
|
import javax.lang.model.SourceVersion;
|
|
import javax.lang.model.element.Element;
|
|
import javax.lang.model.element.Modifier;
|
|
import javax.lang.model.element.TypeElement;
|
|
import javax.tools.Diagnostic;
|
|
|
|
import org.umlgraph.doclet.util.ElementUtil;
|
|
import org.umlgraph.doclet.util.TagUtil;
|
|
|
|
/**
|
|
* Doclet API implementation
|
|
*
|
|
* @depend - - - OptionProvider
|
|
* @depend - - - Options
|
|
* @depend - - - View
|
|
* @depend - - - ClassGraph
|
|
* @depend - - - Version
|
|
*
|
|
* @version $Revision$
|
|
* @author <a href="http://www.spinellis.gr">Diomidis Spinellis</a>
|
|
*/
|
|
public class UmlGraph implements Doclet {
|
|
|
|
private static final String programName = "UmlGraph";
|
|
private static final String docletName = "org.umlgraph.doclet.UmlGraph";
|
|
|
|
/** Options used for commenting nodes */
|
|
private static Options commentOptions;
|
|
|
|
|
|
private Locale locale;
|
|
private Reporter reporter;
|
|
private Options options;
|
|
private StandardDoclet standard;
|
|
|
|
public UmlGraph() {
|
|
this.options = new Options();
|
|
this.standard = new StandardDoclet();
|
|
}
|
|
|
|
@Override
|
|
public void init(Locale locale, Reporter reporter) {
|
|
this.locale = locale;
|
|
this.reporter = reporter;
|
|
}
|
|
|
|
@Override
|
|
public String getName() {
|
|
return docletName;
|
|
}
|
|
|
|
@Override
|
|
public Set<? extends Doclet.Option> getSupportedOptions() {
|
|
Set<Doclet.Option> options = new HashSet<>(standard.getSupportedOptions());
|
|
for (Doclet.Option opt : this.options.OPTIONS) {
|
|
options.add(opt);
|
|
}
|
|
return options;
|
|
}
|
|
|
|
@Override
|
|
public SourceVersion getSupportedSourceVersion() {
|
|
return standard.getSupportedSourceVersion();
|
|
}
|
|
|
|
/**
|
|
* Standard doclet entry point
|
|
*
|
|
* @param root
|
|
* @return
|
|
*/
|
|
@Override
|
|
/** Entry point through javadoc */
|
|
public boolean run(DocletEnvironment root) {
|
|
reporter.print(Diagnostic.Kind.NOTE, "UMLGraph doclet version " + Version.VERSION + " started");
|
|
|
|
List<View> views = buildViews(options, root, root);
|
|
if (views == null) {
|
|
return false;
|
|
}
|
|
try {
|
|
if (views.isEmpty()) {
|
|
buildGraph(reporter, root, options, null, null);
|
|
} else {
|
|
for (View view : views) {
|
|
buildGraph(reporter, root, options, view, null);
|
|
}
|
|
}
|
|
} catch (IOException ioe) {
|
|
reporter.print(Diagnostic.Kind.ERROR, "UMLGraph doclet error : " + ioe);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public static Options getCommentOptions() {
|
|
return commentOptions;
|
|
}
|
|
|
|
/**
|
|
* Creates the base Options object. This contains both the options specified on
|
|
* the command line and the ones specified in the UMLOptions class, if
|
|
* available. Also create the globally accessible commentOptions object.
|
|
*/
|
|
public static Options buildOptions(DocletEnvironment root, Options o) {
|
|
commentOptions = o.clone();
|
|
commentOptions.setOptions(root.getDocTrees(), findClass(root, "UMLNoteOptions"));
|
|
commentOptions.shape = Shape.NOTE;
|
|
|
|
Options opt = o.clone();
|
|
opt.setOptions(root.getDocTrees(), findClass(root, "UMLOptions"));
|
|
return opt;
|
|
}
|
|
|
|
/** Return the ClassDoc for the specified class; null if not found. */
|
|
private static TypeElement findClass(DocletEnvironment root, String name) {
|
|
Set<? extends Element> classes = root.getIncludedElements();
|
|
for (Element element : classes) {
|
|
if (element instanceof TypeElement && ((TypeElement) element).getQualifiedName().toString().equals(name)) {
|
|
return (TypeElement) element;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Builds and outputs a single graph according to the view overrides
|
|
*/
|
|
public static void buildGraph(Reporter reporter, DocletEnvironment root, Options options, OptionProvider op, Element contextDoc) throws IOException {
|
|
if (getCommentOptions() == null) {
|
|
buildOptions(root, options);
|
|
}
|
|
Options opt = op.getGlobalOptions();
|
|
reporter.print(Diagnostic.Kind.NOTE, "Building " + op.getDisplayName());
|
|
Set<? extends Element> elements = root.getIncludedElements();
|
|
Set<TypeElement> classes = new HashSet<>();
|
|
for (Element element : elements) {
|
|
if (element instanceof TypeElement) {
|
|
classes.add((TypeElement) element);
|
|
}
|
|
}
|
|
|
|
ClassGraph c = new ClassGraph(root, op, contextDoc);
|
|
c.prologue();
|
|
for (TypeElement cd : classes) {
|
|
c.printClass(cd, true);
|
|
}
|
|
for (TypeElement cd : classes) {
|
|
c.printRelations(cd);
|
|
}
|
|
if (opt.inferRelationships) {
|
|
for (TypeElement cd : classes) {
|
|
c.printInferredRelations(cd);
|
|
}
|
|
}
|
|
if (opt.inferDependencies) {
|
|
for (TypeElement cd : classes) {
|
|
c.printInferredDependencies(cd);
|
|
}
|
|
}
|
|
|
|
c.printExtraClasses(root);
|
|
c.epilogue();
|
|
}
|
|
|
|
/**
|
|
* Builds the views according to the parameters on the command line
|
|
*
|
|
* @param opt The options
|
|
* @param srcRootDoc The RootDoc for the source classes
|
|
* @param viewRootDoc The RootDoc for the view classes (may be different, or may
|
|
* be the same as the srcRootDoc)
|
|
*/
|
|
public static List<View> buildViews(Options opt, DocletEnvironment srcRootDoc, DocletEnvironment viewRootDoc) {
|
|
if (opt.viewName != null) {
|
|
TypeElement viewClass = findClass(viewRootDoc, opt.viewName);
|
|
if (viewClass == null) {
|
|
System.out.println("View " + opt.viewName + " not found! Exiting without generating any output.");
|
|
return null;
|
|
}
|
|
if (TagUtil.getTag(viewRootDoc, viewClass, "view").isEmpty()) {
|
|
System.out.println(viewClass + " is not a view!");
|
|
return null;
|
|
}
|
|
if (viewClass.getModifiers().contains(Modifier.ABSTRACT)) {
|
|
System.out.println(viewClass + " is an abstract view, no output will be generated!");
|
|
return null;
|
|
}
|
|
return List.of(buildView(srcRootDoc, viewClass, opt));
|
|
} else if (opt.findViews) {
|
|
List<View> views = new ArrayList<>();
|
|
Set<? extends Element> classes = viewRootDoc.getIncludedElements();
|
|
|
|
// find view classes
|
|
for (Element elmt : classes) {
|
|
if (!(elmt instanceof TypeElement)) {
|
|
continue;
|
|
}
|
|
TypeElement element = (TypeElement) elmt;
|
|
if (TagUtil.getTag(viewRootDoc, element, "view").size() > 0 && !element.getModifiers().contains(Modifier.ABSTRACT)) {
|
|
views.add(buildView(srcRootDoc, element, opt));
|
|
}
|
|
}
|
|
|
|
return views;
|
|
} else {
|
|
return Collections.emptyList();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Builds a view along with its parent views, recursively
|
|
*/
|
|
private static View buildView(DocletEnvironment root, TypeElement viewClass, OptionProvider provider) {
|
|
TypeElement superClass = ElementUtil.getSuperclass(viewClass);
|
|
if (superClass == null || TagUtil.getTag(root, superClass, "view").isEmpty()) {
|
|
return new View(root, viewClass, provider);
|
|
}
|
|
|
|
return new View(root, viewClass, buildView(root, superClass, provider));
|
|
}
|
|
}
|