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;
12 import eu.svjatoslav.commons.file.CommonPathResolver;
13 import eu.svjatoslav.commons.string.WildCardMatcher;
14 import eu.svjatoslav.inspector.java.methods.Clazz;
15 import eu.svjatoslav.inspector.java.methods.ProjectScanner;
18 import java.io.IOException;
19 import java.io.PrintWriter;
20 import java.util.ArrayList;
21 import java.util.HashMap;
22 import java.util.List;
25 import static eu.svjatoslav.inspector.java.methods.JavaFile.UTF_8;
26 import static java.io.File.separator;
28 public class ClassGraph {
31 * Maps class fully qualified names to class descriptors.
33 private final Map<String, ClassDescriptor> fullyQualifiedNameToClassMap = new HashMap<String, ClassDescriptor>();
35 private final List<String> blacklistClassPatterns = new ArrayList<String>();
37 private final List<String> whitelistClassPatterns = new ArrayList<String>();
39 private String targetDirectoryPath = CommonPathResolver.getDesktopDirectory()
40 .getAbsolutePath() + separator;
42 private boolean keepDotFile;
44 TargetImageType targetImageType = TargetImageType.SVG;
50 * @param objects objects that shall be added to graph
51 * @return this {@link ClassGraph}
53 public ClassGraph add(final Object... objects) {
56 for (final Object object : objects)
62 private void addObject(final Object object) {
63 if (object instanceof Class)
64 getOrCreateClassDescriptor((Class) object);
66 getOrCreateClassDescriptor(object.getClass());
70 * @param path path to recursively scan for java source code could be
71 * relative to current project or absolute
73 public void addProject(final String path) {
74 final ProjectScanner projectScanner = new ProjectScanner(new File(path));
75 for (final Clazz clazz : projectScanner.getAllClasses())
77 System.out.println("Class full name: " + clazz.getFullName());
78 final Class c = this.getClass().forName(clazz.getFullName());
80 } catch (final Exception exception) {
81 System.out.println("cannot add class: "
82 + exception.getMessage());
86 public void blacklistClassPattern(final String pattern) {
87 blacklistClassPatterns.add(pattern);
90 public void setTargetImageType(TargetImageType targetImageType) {
91 this.targetImageType = targetImageType;
95 * @param resultFileName file name for the generated graph. File extension will be
96 * added automatically. Existing file with the same name will be
100 public void generateGraph(final String resultFileName) {
102 final String dotFilePath = targetDirectoryPath + resultFileName + ".dot";
103 final String imageFilePath = targetDirectoryPath + resultFileName + "." + targetImageType.fileExtension;
106 // write DOT file to disk
107 final PrintWriter out = new PrintWriter(dotFilePath, UTF_8);
111 // execute GraphViz to visualize graph
114 .exec(new String[]{"dot", "-T" + targetImageType.fileExtension, dotFilePath, "-o",
115 imageFilePath}).waitFor();
116 } catch (final InterruptedException ignored) {
121 if (!new File(dotFilePath).delete())
122 throw new RuntimeException("Cannot delete file: " + dotFilePath);
124 } catch (final IOException e) {
125 throw new RuntimeException("Unable to generate graph: " + e.getMessage(), e);
130 private String getDot() {
131 final StringBuffer result = new StringBuffer();
133 result.append("digraph Java {\n");
134 result.append("graph [rankdir=LR, overlap = false, concentrate=true];\n");
136 for (final Map.Entry<String, ClassDescriptor> entry : fullyQualifiedNameToClassMap
138 result.append(entry.getValue().getDot());
140 result.append("}\n");
142 final String resultStr = result.toString();
147 * @param clazz class that shall be added to graph
148 * @return {@link ClassDescriptor} corresponding to given {@link Class}
150 protected ClassDescriptor getOrCreateClassDescriptor(final Class clazz) {
155 final String classFullyQualifiedName = clazz.getName();
157 // reuse existing instance if possible
158 if (fullyQualifiedNameToClassMap.containsKey(classFullyQualifiedName))
159 return fullyQualifiedNameToClassMap.get(classFullyQualifiedName);
161 // create new class descriptor
162 final ClassDescriptor newClassDescriptor = new ClassDescriptor(this);
163 fullyQualifiedNameToClassMap.put(classFullyQualifiedName,
166 newClassDescriptor.analyzeClass(clazz);
168 return newClassDescriptor;
172 * Hide orphaned class that have no references
174 * @return this {@link ClassGraph}
176 public ClassGraph hideOrphanedClasses() {
178 for (final ClassDescriptor classDescriptor : fullyQualifiedNameToClassMap
180 classDescriptor.hideClassIfNoReferences();
185 protected boolean isClassShown(final String className) {
186 for (final String pattern : blacklistClassPatterns)
187 if (WildCardMatcher.match(className, pattern))
190 if (!whitelistClassPatterns.isEmpty()) {
191 for (final String pattern : whitelistClassPatterns)
192 if (WildCardMatcher.match(className, pattern))
200 public ClassGraph setKeepDotFile(final boolean keepDotFile) {
201 this.keepDotFile = keepDotFile;
206 public ClassGraph setTargetDirectoryPath(String directoryPath) {
207 if (!directoryPath.endsWith(separator))
208 directoryPath += separator;
210 targetDirectoryPath = directoryPath;
215 public ClassGraph whitelistClassPattern(final String pattern) {
216 whitelistClassPatterns.add(pattern);