fixed javadoc issues
[javainspect.git] / src / main / java / eu / svjatoslav / inspector / java / structure / ClassGraph.java
1 /*
2  * JavaInspect - Utility to visualize java software
3  * Copyright (C) 2013-2015, 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 3 of the GNU Lesser General Public License
7  * or later 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.ArrayList;
16 import java.util.HashMap;
17 import java.util.List;
18 import java.util.Map;
19
20 import eu.svjatoslav.commons.file.CommonPathResolver;
21 import eu.svjatoslav.commons.string.WildCardMatcher;
22 import eu.svjatoslav.inspector.java.methods.Clazz;
23 import eu.svjatoslav.inspector.java.methods.ProjectScanner;
24
25 public class ClassGraph {
26
27         /**
28          * Maps class fully qualified names to class descriptors.
29          */
30         private final Map<String, ClassDescriptor> fullyQualifiedNameToClassMap = new HashMap<String, ClassDescriptor>();
31
32         private final List<String> blacklistClassPatterns = new ArrayList<String>();
33
34         private final List<String> whitelistClassPatterns = new ArrayList<String>();
35
36         private String targetDirectory = CommonPathResolver.getDesktopDirectory()
37                         .getAbsolutePath() + "/";
38
39         private boolean keepDotFile;
40
41         public ClassGraph() {
42         }
43
44         /**
45          * @param objects
46          *            objects that shall be added to graph
47          *
48          * @return this {@link ClassGraph}
49          */
50         public ClassGraph add(final Object... objects) {
51
52                 if (objects != null)
53                         for (final Object object : objects)
54                                 addObject(object);
55
56                 return this;
57         }
58
59         private void addObject(final Object object) {
60                 if (object instanceof Class)
61                         getOrCreateClassDescriptor((Class) object);
62                 else
63                         getOrCreateClassDescriptor(object.getClass());
64         }
65
66         /**
67          * @param path
68          *            path to recursively scan for java source code could be
69          *            relative to current project or absolute
70          */
71         public void addProject(final String path) {
72                 final ProjectScanner projectScanner = new ProjectScanner(new File(path));
73                 for (final Clazz clazz : projectScanner.getAllClasses())
74                         try {
75                                 System.out.println("Class full name: " + clazz.getFullName());
76                                 final Class c = this.getClass().forName(clazz.getFullName());
77                                 addObject(c);
78                         } catch (final Exception exception) {
79                                 System.out.println("cannot add class: "
80                                                 + exception.getMessage());
81                         }
82         }
83
84         public void blacklistClassPattern(final String pattern) {
85                 blacklistClassPatterns.add(pattern);
86         }
87
88         /**
89          * @param resultFileName
90          *            file name for the generated graph. File extension will be
91          *            added automatically. Existing file with the same name will be
92          *            overwritten.
93          *
94          */
95
96         public void generateGraph(final String resultFileName) {
97
98                 final String dotFilePath = targetDirectory + resultFileName + ".dot";
99                 final String imageFilePath = targetDirectory + resultFileName + ".png";
100
101                 System.out.println("Dot file path:" + dotFilePath);
102
103                 try {
104                         // write DOT file to disk
105                         final PrintWriter out = new PrintWriter(dotFilePath);
106                         out.write(getDot());
107                         out.close();
108
109                         // execute GraphViz to visualize graph
110                         try {
111                                 Runtime.getRuntime()
112                                                 .exec(new String[] { "dot", "-Tpng", dotFilePath, "-o",
113                                                                 imageFilePath }).waitFor();
114                         } catch (final InterruptedException e) {
115                         } finally {
116                         }
117
118                         if (!keepDotFile)
119                                 // delete dot file
120                                 new File(dotFilePath).delete();
121                 } catch (final IOException e) {
122                         System.err.println(e);
123                 }
124
125         }
126
127         private String getDot() {
128                 final StringBuffer result = new StringBuffer();
129
130                 result.append("digraph Java {\n");
131                 result.append("graph [rankdir=LR, overlap = false, concentrate=true];\n");
132
133                 for (final Map.Entry<String, ClassDescriptor> entry : fullyQualifiedNameToClassMap
134                                 .entrySet())
135                         result.append(entry.getValue().getDot());
136
137                 result.append("}\n");
138
139                 final String resultStr = result.toString();
140                 return resultStr;
141         }
142
143         /**
144          * @param clazz
145          *            class that shall be added to graph
146          *
147          * @return {@link ClassDescriptor} corresponding to given {@link Class}
148          */
149         protected ClassDescriptor getOrCreateClassDescriptor(final Class clazz) {
150
151                 if (clazz == null)
152                         return null;
153
154                 final String classFullyQualifiedName = clazz.getName();
155
156                 // reuse existing instance if possible
157                 if (fullyQualifiedNameToClassMap.containsKey(classFullyQualifiedName))
158                         return fullyQualifiedNameToClassMap.get(classFullyQualifiedName);
159
160                 // create new class descriptor
161                 final ClassDescriptor newClassDescriptor = new ClassDescriptor(this);
162                 fullyQualifiedNameToClassMap.put(classFullyQualifiedName,
163                                 newClassDescriptor);
164
165                 newClassDescriptor.analyzeClass(clazz);
166
167                 return newClassDescriptor;
168         }
169
170         /**
171          * Hide orphaned class that have no references
172          *
173          * @return this {@link ClassGraph}
174          */
175         public ClassGraph hideOrphanedClasses() {
176
177                 for (final ClassDescriptor classDescriptor : fullyQualifiedNameToClassMap
178                                 .values())
179                         classDescriptor.hideClassIfNoReferences();
180
181                 return this;
182         }
183
184         protected boolean isClassShown(final String className) {
185                 for (final String pattern : blacklistClassPatterns)
186                         if (WildCardMatcher.match(className, pattern))
187                                 return false;
188
189                 if (!whitelistClassPatterns.isEmpty()) {
190                         for (final String pattern : whitelistClassPatterns)
191                                 if (WildCardMatcher.match(className, pattern))
192                                         return true;
193                         return false;
194                 }
195
196                 return true;
197         }
198
199         public ClassGraph setKeepDotFile(final boolean keepDotFile) {
200                 this.keepDotFile = keepDotFile;
201
202                 return this;
203         }
204
205         public ClassGraph setTargetDirectory(String directoryPath) {
206                 if (!directoryPath.endsWith("/"))
207                         directoryPath += "/";
208
209                 targetDirectory = directoryPath;
210
211                 return this;
212         }
213
214         public ClassGraph whitelistClassPattern(final String pattern) {
215                 whitelistClassPatterns.add(pattern);
216
217                 return this;
218         }
219
220 }