usability improvement
[javainspect.git] / src / main / java / eu / svjatoslav / inspector / java / structure / ClassGraph.java
index 31ddbed..62e0911 100755 (executable)
@@ -1,7 +1,7 @@
 /*
  * JavaInspect - Utility to visualize java software
- * Copyright (C) 2013-2014, Svjatoslav Agejenko, svjatoslav@svjatoslav.eu
- * 
+ * Copyright (C) 2013-2015, 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
  * or later as published by the Free Software Foundation.
@@ -12,72 +12,53 @@ package eu.svjatoslav.inspector.java.structure;
 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.commons.string.WildCardMatcher;
 import eu.svjatoslav.inspector.java.methods.Clazz;
 import eu.svjatoslav.inspector.java.methods.ProjectScanner;
 
 public class ClassGraph {
 
-       public static void render(final String graphName, final Class... classes) {
-               final ClassGraph classGraph = new ClassGraph(classes);
-
-               classGraph.generateGraph(graphName);
-       }
-
        /**
         * Maps class fully qualified names to class descriptors.
         */
-       Map<String, ClassDescriptor> nameToClassMap = new HashMap<String, ClassDescriptor>();
+       private final Map<String, ClassDescriptor> fullyQualifiedNameToClassMap = new HashMap<String, ClassDescriptor>();
 
-       private Filter filter = new Filter();
+       private final List<String> blacklistClassPatterns = new ArrayList<String>();
 
-       public ClassGraph() {
-       }
+       private final List<String> whitelistClassPatterns = new ArrayList<String>();
 
-       /**
-        * @param classes
-        *            classes that shall be added to graph
-        */
-       public ClassGraph(final Class<? extends Object>... classes) {
-               for (final Class<? extends Object> clazz : classes)
-                       addClass(clazz);
+       private String targetDirectory = CommonPathResolver.getDesktopDirectory()
+                       .getAbsolutePath() + "/";
+
+       private boolean keepDotFile;
+
+       public ClassGraph() {
        }
 
        /**
         * @param objects
         *            objects that shall be added to graph
         */
-       public ClassGraph(final Object... objects) {
-               for (final Object object : objects)
-                       addClass(object.getClass());
-       }
-
-       /**
-        * @param clazz
-        *            class that shall be added to graph
-        */
-       public ClassDescriptor addClass(final Class<? extends Object> clazz) {
+       public ClassGraph add(final Object... objects) {
 
-               if (clazz == null)
-                       return null;
+               if (objects != null)
+                       for (final Object object : objects)
+                               addObject(object);
 
-               final String className = clazz.getName();
-
-               if (nameToClassMap.containsKey(className))
-                       return nameToClassMap.get(className);
-
-               return new ClassDescriptor(clazz, this);
+               return this;
        }
 
-       /**
-        * @param object
-        *            object that shall be added to graph
-        */
-       public ClassDescriptor addObject(final Object object) {
-               return addClass(object.getClass());
+       private void addObject(final Object object) {
+               if (object instanceof Class)
+                       getOrCreateClassDescriptor((Class) object);
+               else
+                       getOrCreateClassDescriptor(object.getClass());
        }
 
        /**
@@ -91,41 +72,35 @@ public class ClassGraph {
                        try {
                                System.out.println("Class full name: " + clazz.getFullName());
                                final Class c = this.getClass().forName(clazz.getFullName());
-                               addClass(c);
+                               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);
+       public void blacklistClassPattern(final String pattern) {
+               blacklistClassPatterns.add(pattern);
        }
 
        /**
+        * @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(final String resultFileName,
-                       final boolean keepDotFile) {
-
-               final String desktopPath = CommonPathResolver.getDesktopDirectory()
-                               .getAbsolutePath() + "/";
+       public void generateGraph(final String resultFileName) {
 
-               final String dotFilePath = desktopPath + resultFileName + ".dot";
-               final String imageFilePath = desktopPath + resultFileName + ".png";
+               final String dotFilePath = targetDirectory + resultFileName + ".dot";
+               final String imageFilePath = targetDirectory + resultFileName + ".png";
 
                System.out.println("Dot file path:" + dotFilePath);
 
@@ -138,20 +113,19 @@ public class ClassGraph {
                        // execute GraphViz to visualize graph
                        try {
                                Runtime.getRuntime()
-                                               .exec(new String[] { "dot", "-Tpng", dotFilePath, "-o",
-                                                               imageFilePath }).waitFor();
+                               .exec(new String[] { "dot", "-Tpng", dotFilePath, "-o",
+                                               imageFilePath }).waitFor();
                        } catch (final InterruptedException e) {
                        } finally {
                        }
 
-                       if (!keepDotFile) {
+                       if (!keepDotFile)
                                // delete dot file
-                               final File dotFile = new File(dotFilePath);
-                               dotFile.delete();
-                       }
+                               new File(dotFilePath).delete();
                } catch (final IOException e) {
                        System.err.println(e);
                }
+
        }
 
        private String getDot() {
@@ -160,7 +134,7 @@ public class ClassGraph {
                result.append("digraph Java {\n");
                result.append("graph [rankdir=LR, overlap = false, concentrate=true];\n");
 
-               for (final Map.Entry<String, ClassDescriptor> entry : nameToClassMap
+               for (final Map.Entry<String, ClassDescriptor> entry : fullyQualifiedNameToClassMap
                                .entrySet())
                        result.append(entry.getValue().getDot());
 
@@ -170,22 +144,77 @@ public class ClassGraph {
                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() {
+       public ClassGraph hideOrphanedClasses() {
 
-               for (final ClassDescriptor classDescriptor : nameToClassMap.values())
+               for (final ClassDescriptor classDescriptor : fullyQualifiedNameToClassMap
+                               .values())
                        classDescriptor.hideClassIfNoReferences();
 
+               return this;
        }
 
-       public void setFilter(final Filter filter) {
-               this.filter = filter;
+       protected boolean isClassShown(final String className) {
+               for (final String pattern : blacklistClassPatterns)
+                       if (WildCardMatcher.match(className, pattern))
+                               return false;
+
+               if (!whitelistClassPatterns.isEmpty()) {
+                       for (final String pattern : whitelistClassPatterns)
+                               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(String directoryPath) {
+               if (!directoryPath.endsWith("/"))
+                       directoryPath += "/";
+
+               targetDirectory = directoryPath;
+
+               return this;
+       }
+
+       public ClassGraph whitelistClassPattern(final String pattern) {
+               whitelistClassPatterns.add(pattern);
+
+               return this;
        }
 
 }