import java.io.*; import java.util.*; import java.util.jar.*; import org.apache.bcel.*; import org.apache.bcel.classfile.*; import org.apache.bcel.generic.*; /** * Creates a GraphViz graph of the packages for the given jar files. * Example usage: * * % java MakePackageGraph example1.jar example2.jar * * This requires the BCEL. */ public final class MakePackageGraph { public static void main(String[] args) throws Exception { new MakePackageGraph().process(args); } private final Graph classGraph = new Graph(); void process(String[] args) throws Exception { if (args.length == 0) { System.err.println("Usage: java " + getClass().getName() + " ... "); return; } for (String arg : args) process(arg); dump(); } private void dump() { outln("digraph g {"); for (Map.Entry> e : classGraph.adj.entrySet()) { String from = e.getKey(); Set tos = e.getValue(); for (String to : tos) { if (to.equals("")) continue; if (from.equals(to)) continue; if (from.startsWith("java")) continue; if (to.startsWith("java")) continue; outln(" " + safeForGraphviz(from) + " -> " + safeForGraphviz(to) + ";"); } } outln("}"); } private String safeForGraphviz(String s) { return s.replaceAll("\\.","_"); } private void outln(String s) { System.out.println(s); } private void process(String fileName) throws Exception { File f = new File(fileName); if (f.isDirectory()) { processDirectory(f); } else { processJarfile(f); } } private void processDirectory(File dir) throws Exception { } private void processJarfile(File jar) throws Exception { JarFile jf = new JarFile(jar); for (Enumeration en = jf.entries(); en.hasMoreElements();) { processClass(((JarEntry)en.nextElement()).getName()); } } private boolean processClass(String classFileName) throws Exception { if (!classFileName.endsWith(".class")) return false; processClass(Repository.lookupClass (classFileName.substring(0, classFileName.length()-6).replace("/","."))); return true; } private void processClass(JavaClass clazz) { if (clazz == null) return; try { processClassInternal(clazz); } catch (Exception e) { // ignore } } private void processClassInternal(JavaClass clazz) throws Exception { String className = clazz.getClassName(); for (Field f : clazz.getFields()) { process(className,f.getType()); } for (Method m : clazz.getMethods()) { process(className, m.getReturnType()); for (Type t : m.getArgumentTypes()) { process(className,t); } } processClass(clazz.getSuperClass()); for (JavaClass c : clazz.getInterfaces()) { processClass(c); } } private void process(String fromClass, Type t) { process(fromClass,String.valueOf(t)); } private void process(String fromClass, String toClass) { classGraph.addEdge(getPackage(fromClass),getPackage(toClass)); } private String getPackage(String className) { int ilast = className.lastIndexOf("."); return ilast == -1 ? "" : className.substring(0,ilast); } /** * A simple graph of Strings. */ private static class Graph { final Map> adj = new HashMap>(); void addEdge(String from, String to) { Set edges = adj.get(from); if (edges == null) { adj.put(from, edges = new HashSet()); } edges.add(to); } } }