Possibility to provide classpath dir. Updated help and documentation.
[javainspect.git] / src / main / java / eu / svjatoslav / inspector / java / commandline / Main.java
1 package eu.svjatoslav.inspector.java.commandline;
2
3 import eu.svjatoslav.inspector.java.structure.ClassGraph;
4
5 import java.io.File;
6 import java.io.FileInputStream;
7 import java.io.IOException;
8 import java.net.MalformedURLException;
9 import java.net.URL;
10 import java.net.URLClassLoader;
11 import java.util.ArrayList;
12 import java.util.List;
13 import java.util.jar.JarEntry;
14 import java.util.jar.JarInputStream;
15
16 /**
17  * This class acts as a commandline interface for JavaInspect.
18  */
19 public class Main {
20     public static void main(String[] args) throws IOException, ClassNotFoundException {
21         CommandlineConfiguration configuration = new CommandlineConfiguration(args);
22         if (!configuration.configurationOk) {
23             configuration.parser.showHelp();
24             System.exit(1);
25         }
26
27         if (configuration.showHelp.isSpecified()) configuration.parser.showHelp();
28
29         getClassGraph(configuration).generateGraph(configuration.graphName.getValue());
30
31         if (configuration.isDebug())
32             System.out.println("Graph ready.");
33     }
34
35     private static ClassGraph getClassGraph(CommandlineConfiguration configuration) throws IOException, ClassNotFoundException {
36         List<File> jarFiles = configuration.jarFiles.getValue();
37
38         URLClassLoader classLoader = new URLClassLoader(
39                 getClasspathUrls(jarFiles, configuration.classPaths.getValue()),
40                 configuration.getClass().getClassLoader());
41
42         ClassGraph classGraph = new ClassGraph();
43
44         if (configuration.targetDirectory.isSpecified())
45             classGraph.setTargetDirectory(configuration.targetDirectory.getValue());
46
47         if (configuration.targetImageType.isSpecified())
48             classGraph.setTargetImageType(configuration.targetImageType.getValue());
49
50         classGraph.setKeepDotFile(configuration.keepDotFile.getValue());
51
52         if (configuration.rootClasses.isSpecified()) {
53             // add only selected root classes
54             for (String rootClass : configuration.rootClasses.getValue())
55                 attemptClassAdditionByName(classLoader, classGraph, configuration, rootClass);
56
57         } else {
58             // add all classes in the jar files to graph
59             for (File jarFile : jarFiles)
60                 addJarToGraph(jarFile, classLoader, classGraph, configuration);
61         }
62         configuration.blacklistGlob.getValue().forEach(classGraph::blacklistClassGlob);
63         configuration.whitelistGlob.getValue().forEach(classGraph::whitelistClassGlob);
64
65         if (configuration.hideOrphanedClasses.getValue())
66             classGraph.hideOrphanedClasses();
67
68         return classGraph;
69     }
70
71     private static URL[] getClasspathUrls(List<File> jarFiles, List<File> classpathDirectories) {
72         List<URL> urls = new ArrayList<>();
73
74         classpathDirectories.forEach(classpathDirectory -> {
75             try {
76                 urls.add(classpathDirectory.toURI().toURL());
77             } catch (MalformedURLException e) {
78                 throw new RuntimeException(e);
79             }
80         });
81
82         jarFiles.forEach((File file) -> {
83             try {
84                 urls.add(file.toURI().toURL());
85             } catch (MalformedURLException e) {
86                 throw new RuntimeException(e);
87             }
88         });
89
90         return urls.toArray(new URL[urls.size()]);
91     }
92
93     private static void addJarToGraph(
94             File jarFile, URLClassLoader classLoader, ClassGraph classGraph, CommandlineConfiguration configuration)
95             throws IOException, ClassNotFoundException {
96
97         for (String className : getClassNamesFromJar(jarFile))
98             attemptClassAdditionByName(classLoader, classGraph, configuration, className);
99     }
100
101     private static void attemptClassAdditionByName(URLClassLoader classLoader, ClassGraph classGraph, CommandlineConfiguration configuration, String className) throws ClassNotFoundException {
102         if (configuration.isDebug())
103             System.out.println("Adding class to graph: " + className);
104         try {
105             classGraph.add(loadClassByName(classLoader, className));
106         } catch (NoClassDefFoundError e) {
107             if (configuration.isDebug())
108                 System.out.println("Class definition was not found.");
109             // Sometimes referenced classes are not found in the same Jar.
110             // Let's ignore this and proceed with the classes that we have.
111         }
112     }
113
114     private static Class loadClassByName(URLClassLoader classLoader, String className) throws ClassNotFoundException {
115         return Class.forName(className, true, classLoader);
116     }
117
118     public static List<String> getClassNamesFromJar(File jarFile) throws IOException {
119         List<String> result = new ArrayList<>();
120         try (
121                 JarInputStream jarInputStream = new JarInputStream(new FileInputStream(jarFile))
122         ) {
123             while (true) {
124                 JarEntry jarEntry = jarInputStream.getNextJarEntry();
125                 if (jarEntry == null)
126                     break;
127
128                 if (isClassFile(jarEntry))
129                     result.add(getClassNameFromFileName(jarEntry));
130             }
131
132             return result;
133         }
134     }
135
136     private static boolean isClassFile(JarEntry jarEntry) {
137         return jarEntry.getName().endsWith(".class");
138     }
139
140     private static String getClassNameFromFileName(JarEntry jarEntry) {
141         String result = jarEntry.getName().replaceAll("/", "\\.");
142         return result.substring(0, result.lastIndexOf('.'));
143     }
144 }