001package com.basilv.examples.packagediagram; 002 003import java.io.*; 004import java.util.*; 005 006import jdepend.framework.*; 007 008public class PackageDiagramCreatorApp { 009 010 public static void main(String[] args) { 011 createPackageDependencyDiagram(); 012 System.exit(0); 013 } 014 015 public static void createPackageDependencyDiagram() { 016 Collection<JavaPackage> packages = analyzePackages(); 017 StringBuilder builder = generateGraph(packages); 018 generateImage("packages", builder.toString()); 019 } 020 021 @SuppressWarnings("unchecked") 022 private static Collection<JavaPackage> analyzePackages() { 023 JDepend jdepend = new JDepend(); 024 try { 025 jdepend.addDirectory("dist/classes"); 026 } catch (IOException e) { 027 throw new RuntimeException("Error adding directory for JDepend to analyze.", e); 028 } 029 Collection<JavaPackage> packages = jdepend.analyze(); 030 return packages; 031 } 032 033 private static StringBuilder generateGraph( 034 Collection<JavaPackage> packages) { 035 StringBuilder builder = new StringBuilder(); 036 builder.append("digraph packages {").append("\n"); 037 builder.append("node [shape=box];").append("\n"); 038 builder.append("rankdir=BT;").append("\n"); 039 Set<String> drawnDependencies = new HashSet<String>(); 040 for (JavaPackage javaPackage : packages) { 041 String packageNodeName = getGraphVizNodeForPackage(javaPackage); 042 if (packageNodeName == null) { 043 continue; 044 } 045 builder.append(packageNodeName).append("\n"); 046 047 @SuppressWarnings("unchecked") 048 Collection<JavaPackage> dependencies = javaPackage.getEfferents(); 049 050 for (JavaPackage dependency : dependencies) { 051 String dependencyNodeName = getGraphVizNodeForPackage(dependency); 052 if (dependencyNodeName == null 053 || packageNodeName.equals(dependencyNodeName)) { 054 continue; 055 } 056 String dependencyKey = packageNodeName + "->" 057 + dependencyNodeName; 058 if (drawnDependencies.contains(dependencyKey)) { 059 continue; 060 } 061 builder.append(packageNodeName).append(" -> ").append( 062 dependencyNodeName).append(" [weight=4]").append("\n"); 063 drawnDependencies.add(dependencyKey); 064 } 065 } 066 builder.append("}\n"); 067 return builder; 068 } 069 070 private static String getGraphVizNodeForPackage( 071 JavaPackage javaPackage) { 072 073 String rootPackage = "com.basilv.examples.packagediagram"; 074 String packageName = javaPackage.getName(); 075 if (!packageName.startsWith(rootPackage)) { 076 return null; 077 } 078 079 return packageName.replace(".", "_"); 080 } 081 082 private static void generateImage(String fileName, 083 String graphVizDotFormattedGraph) { 084 try { 085 File graphFile = createFileWithContents(fileName 086 + ".txt", graphVizDotFormattedGraph); 087 088 // This requires the GraphViz software to be installed - 089 // see http://graphviz.org/ 090 String imageFileLocation = fileName + ".png"; 091 Runtime.getRuntime().exec( 092 "dot -v -Tpng " + graphFile.getName() + " -o " 093 + imageFileLocation); 094 095 System.out.println("Image file available at " 096 + new File(imageFileLocation).getAbsolutePath()); 097 } catch (IOException e) { 098 throw new RuntimeException("Error generating image " + fileName, e); 099 } 100 } 101 102 private static File createFileWithContents( 103 String fileName, String graphVizDotFormattedGraph) 104 throws IOException { 105 File graphFile = new File(fileName); 106 FileWriter writer = new FileWriter(graphFile, false); 107 try { 108 writer.append(graphVizDotFormattedGraph); 109 } finally { 110 writer.close(); 111 } 112 return graphFile; 113 } 114 115} 116 117