2 * JavaInspect - Utility to visualize java software
3 * Copyright (C) 2013-2015, Svjatoslav Agejenko, svjatoslav@svjatoslav.eu
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.
10 package eu.svjatoslav.inspector.java.structure;
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;
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;
25 public class ClassGraph {
28 * Maps class fully qualified names to class descriptors.
30 private final Map<String, ClassDescriptor> fullyQualifiedNameToClassMap = new HashMap<String, ClassDescriptor>();
32 private final List<String> blacklistClassPatterns = new ArrayList<String>();
34 private final List<String> whitelistClassPatterns = new ArrayList<String>();
41 * objects that shall be added to graph
43 public ClassGraph add(final Object... objects) {
46 for (final Object object : objects)
52 private void addObject(final Object object) {
53 if (object instanceof Class)
54 getOrCreateClassDescriptor((Class) object);
56 getOrCreateClassDescriptor(object.getClass());
61 * path to recursively scan for java source code could be
62 * relative to current project or absolute
64 public void addProject(final String path) {
65 final ProjectScanner projectScanner = new ProjectScanner(new File(path));
66 for (final Clazz clazz : projectScanner.getAllClasses())
68 System.out.println("Class full name: " + clazz.getFullName());
69 final Class c = this.getClass().forName(clazz.getFullName());
71 } catch (final Exception exception) {
72 System.out.println("cannot add class: "
73 + exception.getMessage());
77 public void blacklistClassPattern(final String pattern) {
78 blacklistClassPatterns.add(pattern);
82 * @param resultFileName
83 * file name for the generated graph. Existing file with the same
84 * name will be overwritten.
86 public void generateGraph(final String resultFileName) {
87 generateGraph(resultFileName, false);
91 * @param resultFileName
92 * file name for the generated graph. File extension will be
93 * added automatically. Existing file with the same name will be
97 * if set to <code>true</code> then intermediary GraphViz DOT
101 public void generateGraph(final String resultFileName,
102 final boolean keepDotFile) {
104 final String desktopPath = CommonPathResolver.getDesktopDirectory()
105 .getAbsolutePath() + "/";
107 generateGraph(desktopPath, resultFileName, keepDotFile);
111 * @param targetDirectory
112 * target directory name
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
120 * if set to <code>true</code> then intermediary GraphViz DOT
124 public void generateGraph(String targetDirectory,
125 final String resultFileName, final boolean keepDotFile) {
127 if (!targetDirectory.endsWith("/"))
128 targetDirectory += "/";
130 final String dotFilePath = targetDirectory + resultFileName + ".dot";
131 final String imageFilePath = targetDirectory + resultFileName + ".png";
133 System.out.println("Dot file path:" + dotFilePath);
136 // write DOT file to disk
137 final PrintWriter out = new PrintWriter(dotFilePath);
141 // execute GraphViz to visualize graph
144 .exec(new String[] { "dot", "-Tpng", dotFilePath, "-o",
145 imageFilePath }).waitFor();
146 } catch (final InterruptedException e) {
152 final File dotFile = new File(dotFilePath);
155 } catch (final IOException e) {
156 System.err.println(e);
161 private String getDot() {
162 final StringBuffer result = new StringBuffer();
164 result.append("digraph Java {\n");
165 result.append("graph [rankdir=LR, overlap = false, concentrate=true];\n");
167 for (final Map.Entry<String, ClassDescriptor> entry : fullyQualifiedNameToClassMap
169 result.append(entry.getValue().getDot());
171 result.append("}\n");
173 final String resultStr = result.toString();
179 * class that shall be added to graph
181 protected ClassDescriptor getOrCreateClassDescriptor(final Class clazz) {
186 final String classFullyQualifiedName = clazz.getName();
188 // reuse existing instance if possible
189 if (fullyQualifiedNameToClassMap.containsKey(classFullyQualifiedName))
190 return fullyQualifiedNameToClassMap.get(classFullyQualifiedName);
192 // create new class descriptor
193 final ClassDescriptor newClassDescriptor = new ClassDescriptor(this);
194 fullyQualifiedNameToClassMap.put(classFullyQualifiedName,
197 newClassDescriptor.analyzeClass(clazz);
199 return newClassDescriptor;
203 * Hide orphaned class that have no references
205 public void hideOrphanedClasses() {
207 for (final ClassDescriptor classDescriptor : fullyQualifiedNameToClassMap
209 classDescriptor.hideClassIfNoReferences();
213 public boolean isClassShown(final String className) {
214 for (final String pattern : blacklistClassPatterns)
215 if (WildCardMatcher.match(className, pattern))
218 if (!whitelistClassPatterns.isEmpty()) {
219 for (final String pattern : whitelistClassPatterns)
220 if (WildCardMatcher.match(className, pattern))
228 public void whitelistClassPattern(final String pattern) {
229 whitelistClassPatterns.add(pattern);