7bae6f3179536676f42138ed3c3855d2af115e8f
[javainspect.git] / src / main / java / eu / svjatoslav / inspector / java / structure / ClassGraph.java
1 /*
2  * JavaInspect - Utility to visualize java software
3  * Copyright (C) 2013, Svjatoslav Agejenko, svjatoslav@svjatoslav.eu
4  * 
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of version 2 of the GNU General Public License
7  * as published by the Free Software Foundation.
8  */
9
10 package eu.svjatoslav.inspector.java.structure;
11
12 import java.io.File;
13 import java.io.IOException;
14 import java.io.PrintWriter;
15 import java.util.HashMap;
16 import java.util.Map;
17
18 import eu.svjatoslav.commons.file.CommonPathResolver;
19 import eu.svjatoslav.inspector.java.methods.Clazz;
20 import eu.svjatoslav.inspector.java.methods.ProjectScanner;
21
22 public class ClassGraph {
23
24         public static void render(final String graphName, final Class... classes) {
25                 final ClassGraph classGraph = new ClassGraph();
26
27                 for (final Class clazz : classes)
28                         classGraph.addClass(clazz);
29
30                 classGraph.generateGraph(graphName);
31         }
32
33         /**
34          * Maps class fully qualified names to class descriptors.
35          */
36         Map<String, ClassDescriptor> nameToClassMap = new HashMap<String, ClassDescriptor>();
37
38         private Filter filter = new Filter();
39
40         public ClassGraph() {
41         }
42
43         /**
44          * @param classes
45          *            classes that shall be added to graph
46          */
47         public ClassGraph(final Class<? extends Object>... classes) {
48                 for (final Class<? extends Object> clazz : classes)
49                         addClass(clazz);
50         }
51
52         /**
53          * @param objects
54          *            objects that shall be added to graph
55          */
56         public ClassGraph(final Object... objects) {
57                 for (Object object : objects)
58                         addClass(object.getClass());
59         }
60
61         /**
62          * @param clazz
63          *            class that shall be added to graph
64          */
65         public ClassDescriptor addClass(final Class<? extends Object> clazz) {
66
67                 if (clazz == null)
68                         return null;
69
70                 final String className = clazz.getName();
71
72                 if (nameToClassMap.containsKey(className))
73                         return nameToClassMap.get(className);
74
75                 return new ClassDescriptor(clazz, this);
76         }
77
78         /**
79          * @param object
80          *            object that shall be added to graph
81          */
82         public ClassDescriptor addObject(final Object object) {
83                 return addClass(object.getClass());
84         }
85
86         /**
87          * @param path
88          *            path to recursively scan for java source code could be
89          *            relative to current project or absolute
90          */
91         public void addProject(final String path) {
92                 final ProjectScanner projectScanner = new ProjectScanner(new File(path));
93                 for (final Clazz clazz : projectScanner.getAllClasses())
94                         try {
95                                 System.out.println("Class full name: " + clazz.getFullName());
96                                 final Class c = this.getClass().forName(clazz.getFullName());
97                                 addClass(c);
98                         } catch (final Exception exception) {
99                                 System.out.println("cannot add class: "
100                                                 + exception.getMessage());
101                         }
102         }
103
104         /**
105          * @param resultFileName
106          *            file name for the generated graph. Existing file with the same
107          *            name will be overwritten.
108          */
109         public void generateGraph(final String resultFileName) {
110                 generateGraph(resultFileName, false);
111         }
112
113         /**
114          * @param resultFileName
115          *            file name for the generated graph. File extension will be
116          *            added automatically. Existing file with the same name will be
117          *            overwritten.
118          * 
119          * @param keepDotFile
120          *            if set to <code>true</code> then intermediary GraphViz DOT
121          *            file will be kept.
122          */
123
124         public void generateGraph(final String resultFileName,
125                         final boolean keepDotFile) {
126
127                 final String desktopPath = CommonPathResolver.getDesktopDirectory()
128                                 .getAbsolutePath() + "/";
129
130                 final String dotFilePath = desktopPath + resultFileName + ".dot";
131                 final String imageFilePath = desktopPath + resultFileName + ".png";
132
133                 System.out.println("Dot file path:" + dotFilePath);
134
135                 try {
136                         // write DOT file to disk
137                         final PrintWriter out = new PrintWriter(dotFilePath);
138                         out.write(getDot());
139                         out.close();
140
141                         // execute GraphViz to visualize graph
142                         try {
143                                 Runtime.getRuntime()
144                                 .exec(new String[] { "dot", "-Tpng", dotFilePath, "-o",
145                                                 imageFilePath }).waitFor();
146                         } catch (final InterruptedException e) {
147                         } finally {
148                         }
149
150                         if (!keepDotFile) {
151                                 // delete dot file
152                                 final File dotFile = new File(dotFilePath);
153                                 dotFile.delete();
154                         }
155                 } catch (final IOException e) {
156                         System.err.println(e);
157                 }
158         }
159
160         private String getDot() {
161                 final StringBuffer result = new StringBuffer();
162
163                 result.append("digraph Java {\n");
164                 result.append("graph [rankdir=LR, overlap = false, concentrate=true];\n");
165
166                 for (final Map.Entry<String, ClassDescriptor> entry : nameToClassMap
167                                 .entrySet())
168                         result.append(entry.getValue().getDot());
169
170                 result.append("}\n");
171
172                 final String resultStr = result.toString();
173                 return resultStr;
174         }
175
176         /**
177          * Hide orphaned class that have no references
178          */
179         public void hideOrphanedClasses() {
180
181                 for (final ClassDescriptor classDescriptor : nameToClassMap.values())
182                         classDescriptor.hideClassIfNoReferences();
183
184         }
185
186         public Filter getFilter() {
187                 return filter;
188         }
189
190         public void setFilter(Filter filter) {
191                 this.filter = filter;
192         }
193
194 }