Updated copyright info
[javainspect.git] / src / main / java / eu / svjatoslav / inspector / java / structure / ClassGraph.java
index 27eff03..c31124c 100755 (executable)
@@ -1,6 +1,6 @@
 /*
  * JavaInspect - Utility to visualize java software
- * Copyright (C) 2013-2015, Svjatoslav Agejenko, svjatoslav@svjatoslav.eu
+ * Copyright (C) 2013-2020, Svjatoslav Agejenko, svjatoslav@svjatoslav.eu
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of version 3 of the GNU Lesser General Public License
 
 package eu.svjatoslav.inspector.java.structure;
 
+import eu.svjatoslav.commons.file.CommonPathResolver;
+import eu.svjatoslav.commons.string.WildCardMatcher;
+import eu.svjatoslav.inspector.java.methods.Clazz;
+import eu.svjatoslav.inspector.java.methods.ProjectScanner;
+
 import java.io.File;
 import java.io.IOException;
 import java.io.PrintWriter;
+import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
-import eu.svjatoslav.commons.file.CommonPathResolver;
-import eu.svjatoslav.inspector.java.methods.Clazz;
-import eu.svjatoslav.inspector.java.methods.ProjectScanner;
+import static eu.svjatoslav.inspector.java.methods.JavaFile.UTF_8;
 
 public class ClassGraph {
 
-       /**
-        * Maps class fully qualified names to class descriptors.
-        */
-       private final Map<String, ClassDescriptor> fullyQualifiedNameToClassMap = new HashMap<String, ClassDescriptor>();
-
-       private final Filter filter = new Filter();
-
-       public ClassGraph() {
-       }
-
-       /**
-        * @param objects
-        *            objects that shall be added to graph
-        */
-       public ClassGraph add(final Object... objects) {
-
-               if (objects != null)
-                       for (final Object object : objects)
-                               addObject(object);
-
-               return this;
-       }
-
-       private void addObject(final Object object) {
-               if (object instanceof Class)
-                       getOrCreateClassDescriptor((Class) object);
-               else
-                       getOrCreateClassDescriptor(object.getClass());
-       }
-
-       /**
-        * @param path
-        *            path to recursively scan for java source code could be
-        *            relative to current project or absolute
-        */
-       public void addProject(final String path) {
-               final ProjectScanner projectScanner = new ProjectScanner(new File(path));
-               for (final Clazz clazz : projectScanner.getAllClasses())
-                       try {
-                               System.out.println("Class full name: " + clazz.getFullName());
-                               final Class c = this.getClass().forName(clazz.getFullName());
-                               addObject(c);
-                       } catch (final Exception exception) {
-                               System.out.println("cannot add class: "
-                                               + exception.getMessage());
-                       }
-       }
-
-       /**
-        * @param resultFileName
-        *            file name for the generated graph. Existing file with the same
-        *            name will be overwritten.
-        */
-       public void generateGraph(final String resultFileName) {
-               generateGraph(resultFileName, false);
-       }
-
-       /**
-        * @param resultFileName
-        *            file name for the generated graph. File extension will be
-        *            added automatically. Existing file with the same name will be
-        *            overwritten.
-        *
-        * @param keepDotFile
-        *            if set to <code>true</code> then intermediary GraphViz DOT
-        *            file will be kept.
-        */
-
-       public void generateGraph(final String resultFileName,
-                       final boolean keepDotFile) {
-
-               final String desktopPath = CommonPathResolver.getDesktopDirectory()
-                               .getAbsolutePath() + "/";
-
-               generateGraph(desktopPath, resultFileName, keepDotFile);
-       }
-
-       /**
-        * @param targetDirectory
-        *            target directory name
-        *
-        * @param resultFileName
-        *            file name for the generated graph. File extension will be
-        *            added automatically. Existing file with the same name will be
-        *            overwritten.
-        *
-        * @param keepDotFile
-        *            if set to <code>true</code> then intermediary GraphViz DOT
-        *            file will be kept.
-        */
-
-       public void generateGraph(String targetDirectory,
-                       final String resultFileName, final boolean keepDotFile) {
-
-               if (!targetDirectory.endsWith("/"))
-                       targetDirectory += "/";
-
-               final String dotFilePath = targetDirectory + resultFileName + ".dot";
-               final String imageFilePath = targetDirectory + resultFileName + ".png";
-
-               System.out.println("Dot file path:" + dotFilePath);
-
-               try {
-                       // write DOT file to disk
-                       final PrintWriter out = new PrintWriter(dotFilePath);
-                       out.write(getDot());
-                       out.close();
-
-                       // execute GraphViz to visualize graph
-                       try {
-                               Runtime.getRuntime()
-                                               .exec(new String[] { "dot", "-Tpng", dotFilePath, "-o",
-                                                               imageFilePath }).waitFor();
-                       } catch (final InterruptedException e) {
-                       } finally {
-                       }
-
-                       if (!keepDotFile) {
-                               // delete dot file
-                               final File dotFile = new File(dotFilePath);
-                               dotFile.delete();
-                       }
-               } catch (final IOException e) {
-                       System.err.println(e);
-               }
-
-       }
-
-       private String getDot() {
-               final StringBuffer result = new StringBuffer();
-
-               result.append("digraph Java {\n");
-               result.append("graph [rankdir=LR, overlap = false, concentrate=true];\n");
-
-               for (final Map.Entry<String, ClassDescriptor> entry : fullyQualifiedNameToClassMap
-                               .entrySet())
-                       result.append(entry.getValue().getDot());
-
-               result.append("}\n");
-
-               final String resultStr = result.toString();
-               return resultStr;
-       }
-
-       public Filter getFilter() {
-               return filter;
-       }
-
-       /**
-        * @param clazz
-        *            class that shall be added to graph
-        */
-       protected ClassDescriptor getOrCreateClassDescriptor(final Class clazz) {
-
-               if (clazz == null)
-                       return null;
-
-               final String classFullyQualifiedName = clazz.getName();
-
-               // reuse existing instance if possible
-               if (fullyQualifiedNameToClassMap.containsKey(classFullyQualifiedName))
-                       return fullyQualifiedNameToClassMap.get(classFullyQualifiedName);
-
-               // create new class descriptor
-               final ClassDescriptor newClassDescriptor = new ClassDescriptor(this);
-               fullyQualifiedNameToClassMap.put(classFullyQualifiedName,
-                               newClassDescriptor);
-
-               newClassDescriptor.analyzeClass(clazz);
-
-               return newClassDescriptor;
-       }
-
-       /**
-        * Hide orphaned class that have no references
-        */
-       public void hideOrphanedClasses() {
-
-               for (final ClassDescriptor classDescriptor : fullyQualifiedNameToClassMap
-                               .values())
-                       classDescriptor.hideClassIfNoReferences();
-
-       }
+    /**
+     * Maps class fully qualified names to class descriptors.
+     */
+    private final Map<String, ClassDescriptor> fullyQualifiedNameToClassMap = new HashMap<>();
+
+    private final List<String> blacklistClassGlobs = new ArrayList<>();
+
+    private final List<String> whitelistClassGlobs = new ArrayList<>();
+    TargetImageType targetImageType = TargetImageType.SVG;
+    private File targetDirectory = CommonPathResolver.getDesktopDirectory();
+    private boolean keepDotFile;
+
+    public ClassGraph() {
+    }
+
+    /**
+     * @param objects objects that shall be added to graph
+     * @return this {@link ClassGraph}
+     */
+    public ClassGraph add(final Object... objects) {
+
+        if (objects != null)
+            for (final Object object : objects)
+                addObject(object);
+
+        return this;
+    }
+
+    private void addObject(final Object object) {
+        if (object instanceof Class)
+            getOrCreateClassDescriptor((Class) object);
+        else
+            getOrCreateClassDescriptor(object.getClass());
+    }
+
+    /**
+     * @param path path to recursively scan for java source code could be
+     *             relative to current project or absolute
+     */
+    public void addProject(final String path) {
+        final ProjectScanner projectScanner = new ProjectScanner(new File(path));
+        for (final Clazz clazz : projectScanner.getAllClasses())
+            try {
+                System.out.println("Class full name: " + clazz.getFullName());
+                final Class c = Class.forName(clazz.getFullName());
+                addObject(c);
+            } catch (final Exception exception) {
+                System.out.println("cannot add class: "
+                        + exception.getMessage());
+            }
+    }
+
+    public void blacklistClassGlob(final String glob) {
+        blacklistClassGlobs.add(glob);
+    }
+
+    public void setTargetImageType(TargetImageType targetImageType) {
+        this.targetImageType = targetImageType;
+    }
+
+    /**
+     * @param resultFileName file name for the generated graph. File extension will be
+     *                       added automatically. Existing file with the same name will be
+     *                       overwritten.
+     */
+
+    public void generateGraph(final String resultFileName) {
+
+        final File dotFile = new File(targetDirectory, resultFileName + ".dot");
+        final File imageFile = new File(targetDirectory, resultFileName + "." + targetImageType.fileExtension);
+
+        try {
+            // write DOT file to disk
+            final PrintWriter out = new PrintWriter(dotFile, UTF_8);
+            out.write(getDot());
+            out.close();
+
+            // execute GraphViz to visualize graph
+            try {
+                Runtime.getRuntime()
+                        .exec(new String[]{"dot",
+                                "-T" + targetImageType.fileExtension,
+                                dotFile.getAbsolutePath(),
+                                "-o",
+                                imageFile.getAbsolutePath()}).waitFor();
+            } catch (final InterruptedException ignored) {
+            }
+
+            if (!keepDotFile)
+                // delete dot file
+                if (!dotFile.delete())
+                    throw new RuntimeException("Cannot delete file: " + dotFile.getAbsolutePath());
+
+        } catch (final IOException e) {
+            throw new RuntimeException("Unable to generate graph: " + e.getMessage(), e);
+        }
+
+    }
+
+    private String getDot() {
+        final StringBuilder result = new StringBuilder();
+
+        result.append("digraph Java {\n");
+        result.append("graph [rankdir=LR, overlap = false, concentrate=true];\n");
+
+        for (final Map.Entry<String, ClassDescriptor> entry : fullyQualifiedNameToClassMap
+                .entrySet())
+            result.append(entry.getValue().getDot());
+
+        result.append("}\n");
+
+        return result.toString();
+    }
+
+    /**
+     * @param clazz class that shall be added to graph
+     * @return {@link ClassDescriptor} corresponding to given {@link Class}
+     */
+    protected ClassDescriptor getOrCreateClassDescriptor(final Class clazz) {
+
+        if (clazz == null)
+            return null;
+
+        final String classFullyQualifiedName = clazz.getName();
+
+        // reuse existing instance if possible
+        if (fullyQualifiedNameToClassMap.containsKey(classFullyQualifiedName))
+            return fullyQualifiedNameToClassMap.get(classFullyQualifiedName);
+
+        // create new class descriptor
+        final ClassDescriptor newClassDescriptor = new ClassDescriptor(this);
+        fullyQualifiedNameToClassMap.put(classFullyQualifiedName,
+                newClassDescriptor);
+
+        newClassDescriptor.analyzeClass(clazz);
+
+        return newClassDescriptor;
+    }
+
+    /**
+     * Hide orphaned class that have no references
+     *
+     * @return this {@link ClassGraph}
+     */
+    public ClassGraph hideOrphanedClasses() {
+
+        for (final ClassDescriptor classDescriptor : fullyQualifiedNameToClassMap
+                .values())
+            classDescriptor.hideClassIfNoReferences();
+
+        return this;
+    }
+
+    protected boolean isClassShown(final String className) {
+        for (final String pattern : blacklistClassGlobs)
+            if (WildCardMatcher.match(className, pattern))
+                return false;
+
+        if (!whitelistClassGlobs.isEmpty()) {
+            for (final String pattern : whitelistClassGlobs)
+                if (WildCardMatcher.match(className, pattern))
+                    return true;
+            return false;
+        }
+
+        return true;
+    }
+
+    public ClassGraph setKeepDotFile(final boolean keepDotFile) {
+        this.keepDotFile = keepDotFile;
+
+        return this;
+    }
+
+    public ClassGraph setTargetDirectory(File targetDirectory) {
+        this.targetDirectory = targetDirectory;
+        return this;
+    }
+
+    public ClassGraph whitelistClassGlob(final String glob) {
+        whitelistClassGlobs.add(glob);
+        return this;
+    }
 
 }