package org.openlca.core;
import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.net.URL;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.List;
import java.util.Queue;
import java.util.Set;
import javax.persistence.Embeddable;
import org.openlca.core.model.AbstractEntity;
import org.openlca.core.model.RootEntity;
/**
* Calculates and prints a dependency graph of the openLCA core model. The graph
* is written in the Graphviz syntax and can be visualized e.g. via
* http://webgraphviz.com/.
*/
public class DependencyGraph {
public static void print() throws Exception {
Queue<Class<?>> queue = new ArrayDeque<>();
queue.addAll(getSubTypes(AbstractEntity.class, "org.openlca.core.model"));
Set<Class<?>> nodes = new HashSet<>();
List<Link> links = new ArrayList<>();
while (!queue.isEmpty()) {
Class<?> next = queue.poll();
nodes.add(next);
for (Link link : getLinks(next)) {
Class<?> ref = link.to;
if (!nodes.contains(ref) && !queue.contains(ref))
queue.add(ref);
links.add(link);
}
}
printGraph(nodes, links);
}
public static List<Class<?>> getSubTypes(Class<?> superType,
String packageName) throws Exception {
List<Class<?>> types = new ArrayList<>();
Enumeration<URL> urls = Tests.class.getClassLoader().getResources(
packageName.replace('.', '/'));
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
File dir = new File(url.toURI());
for (String fileName : dir.list()) {
if (!fileName.endsWith(".class"))
continue;
String shortName = fileName.substring(0, fileName.length() - 6);
String fullName = packageName + "." + shortName;
Class<?> type = Class.forName(fullName);
if (!superType.isAssignableFrom(type)
|| Modifier.isAbstract(type.getModifiers()))
continue;
types.add(type);
}
}
return types;
}
private static List<Link> getLinks(Class<?> next) throws Exception {
List<Link> links = new ArrayList<>();
for (Field field : getFields(next)) {
Class<?> refType = field.getType();
if (isPrimitive(refType))
continue;
Link link = new Link();
link.from = next;
link.name = field.getName();
if (List.class.isAssignableFrom(refType)) {
ParameterizedType pType = (ParameterizedType) field.getGenericType();
Type arg = pType.getActualTypeArguments()[0];
if (arg instanceof Class) {
Class<?> type = (Class<?>) arg;
link.to = type;
link.name += " (*)";
} else {
link.to = refType;
link.name += " (?)";
}
} else {
link.to = refType;
link.name += " (0,1)";
}
links.add(link);
}
return links;
}
private static List<Field> getFields(Class<?> type) {
if (type == null)
return Collections.emptyList();
List<Field> fields = new ArrayList<>();
Class<?> superType = type.getSuperclass();
if (superType != null && !superType.equals(Object.class))
fields.addAll(getFields(type.getSuperclass()));
for (Field field : type.getDeclaredFields()) {
fields.add(field);
}
return fields;
}
private static boolean isPrimitive(Class<?> type) {
if (type.isEnum())
return true;
Class<?>[] primitives = {
int.class, double.class, boolean.class, double[].class,
long.class, short.class, Double.class, String.class,
Long.class, Date.class, Short.class
};
for (Class<?> primitive : primitives) {
if (type.equals(primitive))
return true;
}
return false;
}
private static void printGraph(Set<Class<?>> nodes, List<Link> links) {
p("digraph model {");
p(" node [style = filled];");
for (Class<?> node : nodes) {
printNode(node);
}
p("");
for (Link link : links) {
p(" \"" + link.from.getSimpleName()
+ "\" -> \"" + link.to.getSimpleName()
+ "\" [ label = \"" + link.name + "\", fontsize = 8 ] ;");
}
p("}");
}
private static void printNode(Class<?> node) {
String color = "white";
if (node.isAnnotationPresent(Embeddable.class))
color = "grey";
else if (RootEntity.class.isAssignableFrom(node))
color = "plum";
else if (AbstractEntity.class.isAssignableFrom(node))
color = "wheat";
p(" \"" + node.getSimpleName() + "\" [color=" + color + "];");
}
private static void p(String s) {
System.out.println(s);
}
private static class Link {
Class<?> from;
Class<?> to;
String name;
}
public static void main(String[] args) {
try {
DependencyGraph.print();
} catch (Exception e) {
e.printStackTrace();
}
}
}