more tests
This commit is contained in:
parent
1083c9a4c7
commit
ba53b67ccf
25 changed files with 154 additions and 838 deletions
|
|
@ -2,3 +2,8 @@ yooze
|
||||||
=====
|
=====
|
||||||
|
|
||||||
visualizes java class dependencies
|
visualizes java class dependencies
|
||||||
|
|
||||||
|
=====
|
||||||
|
|
||||||
|
Not a finished project yet, just poking around with javassist.
|
||||||
|
It does build a model, and you you could pick up dot files to create pictures of the graph. It just isn't very pretty yet.
|
||||||
|
|
|
||||||
BIN
example.png
BIN
example.png
Binary file not shown.
|
Before Width: | Height: | Size: 7.3 MiB |
8
pom.xml
8
pom.xml
|
|
@ -8,7 +8,7 @@
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
<version>0.1-SNAPSHOT</version>
|
<version>0.1-SNAPSHOT</version>
|
||||||
<name>yooze</name>
|
<name>yooze</name>
|
||||||
<url>www.cjib.nl</url>
|
<url>http://jssl.org/yooze</url>
|
||||||
<build>
|
<build>
|
||||||
<plugins>
|
<plugins>
|
||||||
<plugin>
|
<plugin>
|
||||||
|
|
@ -130,6 +130,12 @@
|
||||||
<artifactId>jackson-mapper-asl</artifactId>
|
<artifactId>jackson-mapper-asl</artifactId>
|
||||||
<version>1.9.10</version>
|
<version>1.9.10</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.mockito</groupId>
|
||||||
|
<artifactId>mockito-core</artifactId>
|
||||||
|
<version>1.9.5</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</project>
|
</project>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,8 +21,7 @@ import yooze.domain.MethodModel;
|
||||||
* Builds a ClassModel.
|
* Builds a ClassModel.
|
||||||
*/
|
*/
|
||||||
public class ClassModelBuilder {
|
public class ClassModelBuilder {
|
||||||
private static Logger log = LoggerFactory
|
private static Logger log = LoggerFactory.getLogger(ClassModelBuilder.class);
|
||||||
.getLogger(ClassModelBuilder.class);
|
|
||||||
|
|
||||||
private Pattern[] packageIncludePatterns;
|
private Pattern[] packageIncludePatterns;
|
||||||
private Pattern[] packageExcludePatterns;
|
private Pattern[] packageExcludePatterns;
|
||||||
|
|
@ -47,17 +46,11 @@ public class ClassModelBuilder {
|
||||||
private ClassModel scan(String className) {
|
private ClassModel scan(String className) {
|
||||||
ClassModel model = new ClassModel(className);
|
ClassModel model = new ClassModel(className);
|
||||||
ClassCache.add(className, model);
|
ClassCache.add(className, model);
|
||||||
try {
|
|
||||||
return tryScan(className, model);
|
return tryScan(className, model);
|
||||||
} catch (Exception e) {
|
|
||||||
log.warn("Loading class,", e);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private ClassModel tryScan(String className, ClassModel model)
|
private ClassModel tryScan(String className, ClassModel model) {
|
||||||
throws NotFoundException {
|
CtClass ctClass = getClassFromJavassist(className);
|
||||||
CtClass ctClass = pool.get(className);
|
|
||||||
if (isScannable(ctClass)) {
|
if (isScannable(ctClass)) {
|
||||||
ConstPool constPool = ctClass.getClassFile().getConstPool();
|
ConstPool constPool = ctClass.getClassFile().getConstPool();
|
||||||
|
|
||||||
|
|
@ -66,7 +59,15 @@ public class ClassModelBuilder {
|
||||||
resolveMethodReferences();
|
resolveMethodReferences();
|
||||||
return model;
|
return model;
|
||||||
} else {
|
} else {
|
||||||
return null;
|
throw new ClassNotFound(className);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private CtClass getClassFromJavassist(String className) {
|
||||||
|
try {
|
||||||
|
return pool.get(className);
|
||||||
|
} catch (NotFoundException e) {
|
||||||
|
throw new ClassNotFound(className);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -88,11 +89,11 @@ public class ClassModelBuilder {
|
||||||
private void addMethods(ClassModel containingClass, CtClass ctClass) {
|
private void addMethods(ClassModel containingClass, CtClass ctClass) {
|
||||||
CtMethod[] methods = ctClass.getMethods();
|
CtMethod[] methods = ctClass.getMethods();
|
||||||
for (CtMethod method : methods) {
|
for (CtMethod method : methods) {
|
||||||
containingClass.addMethod(MethodModel.create(containingClass,
|
containingClass.addMethod(MethodModel.create(containingClass, method));
|
||||||
method));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
private void addClassReferences(ClassModel model, ConstPool constPool) {
|
private void addClassReferences(ClassModel model, ConstPool constPool) {
|
||||||
Set<String> classNames = constPool.getClassNames();
|
Set<String> classNames = constPool.getClassNames();
|
||||||
for (String classResourcename : classNames) {
|
for (String classResourcename : classNames) {
|
||||||
|
|
|
||||||
|
|
@ -1,28 +0,0 @@
|
||||||
package yooze;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import javassist.ClassPath;
|
|
||||||
import yooze.scanner.Scanner;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* reads classes as .class files from a directory
|
|
||||||
*/
|
|
||||||
public class ClassesDirScanner implements Scanner {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<ClassPath> scanArchive(String archiveName) throws IOException {
|
|
||||||
return scanArchive(new File(archiveName));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<ClassPath> scanArchive(File file) throws IOException {
|
|
||||||
List<ClassPath> result = new ArrayList<ClassPath>();
|
|
||||||
result.add(new DirClassPath(file));
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,90 +0,0 @@
|
||||||
package yooze;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.net.MalformedURLException;
|
|
||||||
import java.net.URL;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import javassist.ClassPath;
|
|
||||||
import javassist.NotFoundException;
|
|
||||||
|
|
||||||
public class DirClassPath implements ClassPath, Inspectable {
|
|
||||||
|
|
||||||
private final File dir;
|
|
||||||
|
|
||||||
public DirClassPath(File dir) {
|
|
||||||
super();
|
|
||||||
this.dir = dir;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void close() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public URL find(String className) {
|
|
||||||
try {
|
|
||||||
return new URL("file:///" + dir.getCanonicalPath() + "/" + Util.toClassResource(className));
|
|
||||||
} catch (MalformedURLException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "DirectoryClasspath[" + dir + "]";
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<String> getClasses() {
|
|
||||||
List<String> classes = new ArrayList<String>();
|
|
||||||
getClasses(dir, dir, classes);
|
|
||||||
return classes;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void getClasses(File root, File dir, List<String> classes) {
|
|
||||||
File[] fileList = dir.listFiles();
|
|
||||||
for (File entry : fileList) {
|
|
||||||
if (entry.isDirectory()) {
|
|
||||||
// recurse deeper
|
|
||||||
getClasses(root, entry, classes);
|
|
||||||
} else if (isClassFile(entry)) {
|
|
||||||
classes.add(createQualifiedClassNameFromFileLocation(root, entry));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isClassFile(File entry) {
|
|
||||||
return entry.isFile() && entry.getName().endsWith(".class");
|
|
||||||
}
|
|
||||||
|
|
||||||
private String createQualifiedClassNameFromFileLocation(File root, File classFile) {
|
|
||||||
String absolutePath = classFile.getAbsolutePath();
|
|
||||||
String relativePath = absolutePath.substring(root.getAbsolutePath().length() + 1);
|
|
||||||
String packageFormat = relativePath.replaceAll("\\\\", ".").replaceAll("/", ".");
|
|
||||||
String substring = packageFormat.substring(0, packageFormat.length() - 6);
|
|
||||||
return substring;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getResourceName() {
|
|
||||||
return dir.getName();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public InputStream openClassfile(String className) throws NotFoundException {
|
|
||||||
File classFile = new File(dir, Util.toClassResource(className) + ".class");
|
|
||||||
if (!classFile.exists()) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
return new ClassByteCountingInputStream(className, new FileInputStream(classFile));
|
|
||||||
} catch (FileNotFoundException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,59 +0,0 @@
|
||||||
package yooze;
|
|
||||||
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.io.PrintStream;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
|
|
||||||
import yooze.domain.ClassModel;
|
|
||||||
import yooze.domain.Graph;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* prints the graph as a graphviz dot file. Takes care of circular dependencies. Not threadsafe.
|
|
||||||
*/
|
|
||||||
public class DotPrinter extends PrintStream {
|
|
||||||
|
|
||||||
private ArrayList<String> printedRelations;
|
|
||||||
|
|
||||||
public DotPrinter(OutputStream out) {
|
|
||||||
super(out);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void print(Graph g) {
|
|
||||||
printedRelations = new ArrayList<String>();
|
|
||||||
println("digraph \"" + g.getName() + "\" {");
|
|
||||||
println("graph [size=100,100];");
|
|
||||||
for (ClassModel cm : g.getChildren()) {
|
|
||||||
print(cm);
|
|
||||||
}
|
|
||||||
println("}");
|
|
||||||
close();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void print(ClassModel cm) {
|
|
||||||
double boxsize = Math.sqrt(Statistics.getByteCodeSizeForClass(cm.getName()));
|
|
||||||
|
|
||||||
print("\"");
|
|
||||||
print(cm.getName());
|
|
||||||
println("\" [shape=box, height=" + boxsize / 20 + "];");
|
|
||||||
|
|
||||||
if (cm.getReferences() == null || cm.getReferences().size() == 0) {
|
|
||||||
print("\"");
|
|
||||||
print(cm.getName());
|
|
||||||
println("\";");
|
|
||||||
} else {
|
|
||||||
for (ClassModel ref : cm.getReferences()) {
|
|
||||||
String relation = cm.getName() + "-" + ref.getName();
|
|
||||||
if (!printedRelations.contains(relation)) {
|
|
||||||
print("\"");
|
|
||||||
print(cm.getName());
|
|
||||||
print("\" -> \"");
|
|
||||||
print(ref.getName());
|
|
||||||
println("\"");
|
|
||||||
printedRelations.add(relation);
|
|
||||||
print(ref);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -8,14 +8,9 @@ import javassist.ClassPath;
|
||||||
import javassist.ClassPool;
|
import javassist.ClassPool;
|
||||||
import yooze.domain.ClassModel;
|
import yooze.domain.ClassModel;
|
||||||
import yooze.domain.Graph;
|
import yooze.domain.Graph;
|
||||||
import yooze.scanner.ArchiveScanner;
|
|
||||||
import yooze.scanner.LibScanner;
|
|
||||||
import yooze.scanner.Scanner;
|
|
||||||
import yooze.scanner.TgzScanner;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builds a class dependency graph from given classpath. Delegates to
|
* Builds a class dependency graph from given classpath. Delegates to ClassModelBuilder.
|
||||||
* ClassModelBuilder.
|
|
||||||
*/
|
*/
|
||||||
public class GraphBuilder {
|
public class GraphBuilder {
|
||||||
private Scanner scanner;
|
private Scanner scanner;
|
||||||
|
|
@ -23,83 +18,67 @@ public class GraphBuilder {
|
||||||
private String[] packageIncludePatterns;
|
private String[] packageIncludePatterns;
|
||||||
private String[] packageExcludePatterns;
|
private String[] packageExcludePatterns;
|
||||||
|
|
||||||
/**
|
public GraphBuilder(Scanner scanner) {
|
||||||
* Factory method for getting a builder that does earfiles
|
|
||||||
*/
|
|
||||||
public static GraphBuilder getEarBuilder() {
|
|
||||||
return new GraphBuilder(new ArchiveScanner());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Factory method for getting a builder that does (downloaded) .tar.gz files
|
|
||||||
*/
|
|
||||||
public static GraphBuilder getDefaultTgzBuilder() {
|
|
||||||
GraphBuilder tgzBuilder = new GraphBuilder(new TgzScanner());
|
|
||||||
tgzBuilder.setPackageExcludePatterns("java.*", "sun.*", "com.sun.*");
|
|
||||||
return tgzBuilder;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Factory method for getting a builder that scans a lib directory
|
|
||||||
* (containing jars)
|
|
||||||
*/
|
|
||||||
public static GraphBuilder getLibDirectoryBuilder() {
|
|
||||||
return new GraphBuilder(new LibScanner());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Factory method for getting a builder that scans a directory containing
|
|
||||||
* classes
|
|
||||||
*/
|
|
||||||
public static GraphBuilder getClassesDirectoryBuilder() {
|
|
||||||
return new GraphBuilder(new ClassesDirScanner());
|
|
||||||
}
|
|
||||||
|
|
||||||
private GraphBuilder(Scanner scanner) {
|
|
||||||
this.scanner = scanner;
|
this.scanner = scanner;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* primary function for this class.
|
* Builds a graph from a give starting point(class)
|
||||||
|
*
|
||||||
|
* @param archiveFilename
|
||||||
|
* @param className
|
||||||
|
* the name of the class that is the starting point. Only classes referenced from here will be included.
|
||||||
|
* @return a Graph containing all calculated dependencies
|
||||||
|
* @throws IOException
|
||||||
|
* when file reading fails
|
||||||
|
*/
|
||||||
|
public Graph build(String archiveFilename, String className) throws IOException {
|
||||||
|
return buildClassDepencyGraph(new File(archiveFilename), className, new IncludeDecision() {
|
||||||
|
public boolean shouldIncludeClass(String name, String startingpointname) {
|
||||||
|
return name.equals(startingpointname);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds a graph for all classes (all included via package patterns and not excluded)
|
||||||
*
|
*
|
||||||
* @param archiveFilename
|
* @param archiveFilename
|
||||||
* @return a Graph containing all calculated dependencies
|
* @return a Graph containing all calculated dependencies
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
* when file reading fails
|
* when file reading fails
|
||||||
*/
|
*/
|
||||||
public Graph build(String archiveFilename, String className)
|
public Graph build(String archiveFilename) throws IOException {
|
||||||
throws IOException {
|
return buildClassDepencyGraph(new File(archiveFilename), null, new IncludeDecision() {
|
||||||
return buildClassDepencyGraph(new File(archiveFilename), className);
|
public boolean shouldIncludeClass(String name, String startingpointname) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Graph buildClassDepencyGraph(File archiveFile, String className)
|
Graph buildClassDepencyGraph(File archiveFile, String className, IncludeDecision e) throws IOException {
|
||||||
throws IOException {
|
List<InspectableClasspath> cpList = scanner.scanArchive(archiveFile);
|
||||||
List<ClassPath> cpList = scanner.scanArchive(archiveFile);
|
|
||||||
|
|
||||||
ClassPool pool = ClassPool.getDefault();
|
ClassPool pool = ClassPool.getDefault();
|
||||||
for (ClassPath cp : cpList) {
|
for (ClassPath cp : cpList) {
|
||||||
pool.appendClassPath(cp);
|
pool.appendClassPath(cp);
|
||||||
}
|
}
|
||||||
|
|
||||||
Graph graph = createClassDependencyGraph(pool, cpList, className);
|
Graph graph = createClassDependencyGraph(pool, cpList, className, e);
|
||||||
graph.setName(archiveFile.getName());
|
graph.setName(archiveFile.getName());
|
||||||
return graph;
|
return graph;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Graph createClassDependencyGraph(ClassPool pool,
|
private Graph createClassDependencyGraph(ClassPool pool, List<InspectableClasspath> classpath, String className,
|
||||||
List<ClassPath> classpath, String className) {
|
IncludeDecision decide) {
|
||||||
Graph graph = new Graph();
|
Graph graph = new Graph();
|
||||||
classModelBuilder = new ClassModelBuilder(pool);
|
classModelBuilder = new ClassModelBuilder(pool);
|
||||||
classModelBuilder.setPackageExcludePatterns(packageExcludePatterns);
|
classModelBuilder.setPackageExcludePatterns(packageExcludePatterns);
|
||||||
classModelBuilder.setPackageIncludePatterns(packageIncludePatterns);
|
classModelBuilder.setPackageIncludePatterns(packageIncludePatterns);
|
||||||
for (ClassPath lib : classpath) {
|
for (InspectableClasspath lib : classpath) {
|
||||||
assert (lib instanceof Inspectable);
|
for (String name : lib.getClasses()) {
|
||||||
|
if (decide.shouldIncludeClass(name, className)) {
|
||||||
List<String> classes = ((Inspectable) lib).getClasses();
|
ClassModel newModel = classModelBuilder.scanClassOrSkip(className);
|
||||||
for (String name : classes) {
|
|
||||||
if (name.equals(className)) {
|
|
||||||
ClassModel newModel = classModelBuilder
|
|
||||||
.scanClassOrSkip(className);
|
|
||||||
if (newModel != null) {
|
if (newModel != null) {
|
||||||
graph.add(newModel);
|
graph.add(newModel);
|
||||||
}
|
}
|
||||||
|
|
@ -117,4 +96,7 @@ public class GraphBuilder {
|
||||||
this.packageExcludePatterns = packageExcludePatterns;
|
this.packageExcludePatterns = packageExcludePatterns;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface IncludeDecision {
|
||||||
|
boolean shouldIncludeClass(String name, String startingpointname);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
package yooze;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public interface Inspectable {
|
|
||||||
public String getResourceName();
|
|
||||||
public List<String> getClasses();
|
|
||||||
}
|
|
||||||
|
|
@ -1,78 +0,0 @@
|
||||||
package yooze;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.net.MalformedURLException;
|
|
||||||
import java.net.URL;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Enumeration;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.jar.JarEntry;
|
|
||||||
import java.util.jar.JarFile;
|
|
||||||
import java.util.zip.ZipEntry;
|
|
||||||
|
|
||||||
import javassist.ClassPath;
|
|
||||||
import javassist.NotFoundException;
|
|
||||||
|
|
||||||
public class JarClassPath implements ClassPath, Inspectable {
|
|
||||||
|
|
||||||
private final JarFile jar;
|
|
||||||
|
|
||||||
public JarClassPath(JarFile jar) {
|
|
||||||
super();
|
|
||||||
this.jar = jar;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void close() {
|
|
||||||
try {
|
|
||||||
jar.close();
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public URL find(String className) {
|
|
||||||
try {
|
|
||||||
return new URL("file:///"+jar.getName()+"!"+Util.toClassResource(className));
|
|
||||||
} catch (MalformedURLException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "JarClasspath[" + jar.getName() + "]";
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<String> getClasses() {
|
|
||||||
List<String> classes = new ArrayList<String>();
|
|
||||||
for (Enumeration<JarEntry> entries = jar.entries(); entries
|
|
||||||
.hasMoreElements();) {
|
|
||||||
String name = entries.nextElement().getName().replaceAll("/", ".");
|
|
||||||
if (name.endsWith(".class")) {
|
|
||||||
classes.add(name.substring(0, name.length() - 6));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return classes;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public String getResourceName() {
|
|
||||||
return jar.getName();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public InputStream openClassfile(String className) throws NotFoundException {
|
|
||||||
ZipEntry entry = jar.getEntry(Util.toClassResource(className));
|
|
||||||
if (entry == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
return new ClassByteCountingInputStream(className,jar.getInputStream(entry));
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -19,10 +19,9 @@ public class MethodCallModel {
|
||||||
public MethodModel getCalledMethod() {
|
public MethodModel getCalledMethod() {
|
||||||
try {
|
try {
|
||||||
ParameterList parameterList = ParameterList.create(methodCall.getMethod());
|
ParameterList parameterList = ParameterList.create(methodCall.getMethod());
|
||||||
return MethodCache.getInstance().get(
|
return MethodCache.getInstance().get(createQualifiedMethodname(parameterList));
|
||||||
createQualifiedMethodname(parameterList));
|
|
||||||
} catch (NotFoundException e) {
|
} catch (NotFoundException e) {
|
||||||
throw new RuntimeException(e);
|
throw new MethodNotFound(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,48 +0,0 @@
|
||||||
package yooze.etc;
|
|
||||||
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
|
|
||||||
import yooze.Util;
|
|
||||||
import yooze.domain.ClassModel;
|
|
||||||
|
|
||||||
import javassist.ClassPath;
|
|
||||||
import javassist.ClassPool;
|
|
||||||
import javassist.CtClass;
|
|
||||||
import javassist.NotFoundException;
|
|
||||||
import javassist.bytecode.ConstPool;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated does not seem to be in use
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public class ClassBuilder {
|
|
||||||
|
|
||||||
private final ConcurrentHashMap<String, ClassModel> classes = new ConcurrentHashMap<String, ClassModel>();
|
|
||||||
|
|
||||||
private ClassPool pool = ClassPool.getDefault();
|
|
||||||
|
|
||||||
private ClassBuilder(List<ClassPath> classpaths) {
|
|
||||||
super();
|
|
||||||
for (ClassPath cpEntry : classpaths) {
|
|
||||||
pool.appendClassPath(cpEntry);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public ClassModel load(String className) throws NotFoundException {
|
|
||||||
ClassModel model;
|
|
||||||
if ((model = classes.get(className)) != null) {
|
|
||||||
return model;
|
|
||||||
}
|
|
||||||
|
|
||||||
CtClass ctClass = pool.getCtClass(className);
|
|
||||||
model = new ClassModel(className);
|
|
||||||
ConstPool constPool = ctClass.getClassFile().getConstPool();
|
|
||||||
for (Iterator<?> classNames = constPool.getClassNames().iterator(); classNames.hasNext();) {
|
|
||||||
model.addReference(load(Util.toClassName(classNames.next().toString())));
|
|
||||||
}
|
|
||||||
return model;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,89 +0,0 @@
|
||||||
package yooze.etc;
|
|
||||||
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
|
|
||||||
import org.neo4j.graphdb.Direction;
|
|
||||||
import org.neo4j.graphdb.GraphDatabaseService;
|
|
||||||
import org.neo4j.graphdb.Node;
|
|
||||||
import org.neo4j.graphdb.RelationshipType;
|
|
||||||
import org.neo4j.graphdb.ReturnableEvaluator;
|
|
||||||
import org.neo4j.graphdb.StopEvaluator;
|
|
||||||
import org.neo4j.graphdb.Transaction;
|
|
||||||
import org.neo4j.graphdb.Traverser;
|
|
||||||
import org.neo4j.kernel.EmbeddedGraphDatabase;
|
|
||||||
|
|
||||||
import yooze.domain.ClassModel;
|
|
||||||
|
|
||||||
public class Neo4jDao {
|
|
||||||
private GraphDatabaseService graphDb;
|
|
||||||
private Node rootNode;
|
|
||||||
private ConcurrentHashMap<String, Node> nodes = new ConcurrentHashMap<String, Node>();
|
|
||||||
|
|
||||||
public enum MyRelationshipTypes implements RelationshipType {
|
|
||||||
CONTAINS, REFERENCES
|
|
||||||
}
|
|
||||||
|
|
||||||
public Neo4jDao(String database) {
|
|
||||||
graphDb = new EmbeddedGraphDatabase(database);
|
|
||||||
Transaction tx = graphDb.beginTx();
|
|
||||||
try {
|
|
||||||
rootNode = graphDb.createNode();
|
|
||||||
rootNode.setProperty("name", "root");
|
|
||||||
tx.success();
|
|
||||||
} finally {
|
|
||||||
tx.finish();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void insertClass(ClassModel classModel) {
|
|
||||||
Transaction tx = graphDb.beginTx();
|
|
||||||
try {
|
|
||||||
Node newNode = findOrCreateNode(classModel);
|
|
||||||
|
|
||||||
for (ClassModel ref : classModel.getReferences()) {
|
|
||||||
Node refNode = findOrCreateNode(ref);
|
|
||||||
newNode.createRelationshipTo(refNode,
|
|
||||||
MyRelationshipTypes.REFERENCES);
|
|
||||||
}
|
|
||||||
tx.success();
|
|
||||||
} finally {
|
|
||||||
tx.finish();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Node findOrCreateNode(ClassModel classModel) {
|
|
||||||
Node newNode = findNode(classModel.getName());
|
|
||||||
if (newNode == null) {
|
|
||||||
Transaction tx = graphDb.beginTx();
|
|
||||||
try {
|
|
||||||
newNode = graphDb.createNode();
|
|
||||||
newNode.setProperty("name", classModel.getName());
|
|
||||||
|
|
||||||
tx.success();
|
|
||||||
} finally {
|
|
||||||
tx.finish();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return newNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Node findNode(String className) {
|
|
||||||
Node node = nodes.get(className);
|
|
||||||
if (node != null) {
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
// do "tablescan". is there a better way?
|
|
||||||
Traverser classesTraverser = rootNode.traverse(
|
|
||||||
Traverser.Order.BREADTH_FIRST, StopEvaluator.DEPTH_ONE,
|
|
||||||
ReturnableEvaluator.ALL_BUT_START_NODE,
|
|
||||||
MyRelationshipTypes.CONTAINS, Direction.OUTGOING);
|
|
||||||
for (Node nextNode : classesTraverser) {
|
|
||||||
if (nextNode.getProperty("name").equals(className)) {
|
|
||||||
nodes.put(className, nextNode);
|
|
||||||
return nextNode;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;// not found
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,43 +0,0 @@
|
||||||
package yooze.etc;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import yooze.GraphBuilder;
|
|
||||||
import yooze.domain.ClassModel;
|
|
||||||
import yooze.domain.Graph;
|
|
||||||
|
|
||||||
public class Yooze {
|
|
||||||
private String neo4jDb;
|
|
||||||
|
|
||||||
public static void main(String[] args) throws IOException {
|
|
||||||
String neoDb = args[0];
|
|
||||||
String earfile = args[1];
|
|
||||||
String in = args[2];
|
|
||||||
String ex = args[2];
|
|
||||||
String startingClassname = args[3];
|
|
||||||
new Yooze(neoDb).createNeoGraph(earfile, in, ex, startingClassname);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public Yooze(String neo4jDb) {
|
|
||||||
super();
|
|
||||||
this.neo4jDb = neo4jDb;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void createNeoGraph(String archive, String packageIncludePatterns,
|
|
||||||
String packageExcludePatterns, String startingClass)
|
|
||||||
throws IOException {
|
|
||||||
GraphBuilder libDirectoryBuilder = GraphBuilder
|
|
||||||
.getLibDirectoryBuilder();
|
|
||||||
libDirectoryBuilder.setPackageExcludePatterns(packageExcludePatterns);
|
|
||||||
libDirectoryBuilder.setPackageIncludePatterns(packageIncludePatterns);
|
|
||||||
|
|
||||||
Graph graph = libDirectoryBuilder.build(archive, startingClass);
|
|
||||||
|
|
||||||
Neo4jDao neo4jDao = new Neo4jDao(neo4jDb);
|
|
||||||
for (ClassModel model : graph.getChildren()) {
|
|
||||||
neo4jDao.insertClass(model);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
package yooze.scanner;
|
package yooze.scanner;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
@ -9,40 +8,62 @@ import java.util.Enumeration;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.jar.JarEntry;
|
import java.util.jar.JarEntry;
|
||||||
import java.util.jar.JarFile;
|
import java.util.jar.JarFile;
|
||||||
import java.util.regex.Matcher;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
import java.util.zip.ZipEntry;
|
|
||||||
|
|
||||||
import javassist.ClassPath;
|
import yooze.InspectableClasspath;
|
||||||
|
import yooze.Scanner;
|
||||||
import org.apache.commons.io.IOUtils;
|
|
||||||
|
|
||||||
import yooze.DirClassPath;
|
|
||||||
import yooze.JarClassPath;
|
|
||||||
import yooze.Util;
|
import yooze.Util;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author shautvast TODO separate models for wars
|
* TODO separate models for wars
|
||||||
*/
|
*/
|
||||||
public class ArchiveScanner implements Scanner {
|
public class ArchiveScanner implements Scanner {
|
||||||
private final static Pattern classPattern = Pattern.compile("WEB-INF/classes/(.*)\\.class");
|
private WarScanner warScanner;
|
||||||
private final static Pattern packagePattern = Pattern.compile("(.+\\/+)(.+\\.class)");
|
|
||||||
|
|
||||||
public List<ClassPath> scanArchive(String archiveName) throws IOException {
|
public ArchiveScanner(WarScanner warScanner) {
|
||||||
|
this.warScanner = warScanner;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<InspectableClasspath> scanArchive(String archiveName) {
|
||||||
return scanArchive(new File(archiveName));
|
return scanArchive(new File(archiveName));
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<ClassPath> scanArchive(File archiveFile) throws IOException {
|
public List<InspectableClasspath> scanArchive(File archiveFile) {
|
||||||
List<ClassPath> result = new ArrayList<ClassPath>();
|
List<InspectableClasspath> result = new ArrayList<InspectableClasspath>();
|
||||||
if (!archiveFile.exists()) {
|
if (!archiveFile.exists()) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (archiveFile.isDirectory()) {
|
if (archiveFile.isDirectory()) {
|
||||||
|
return directoryAsClasspath(archiveFile, result);
|
||||||
|
} else {
|
||||||
|
JarFile archive = createJar(archiveFile);
|
||||||
|
if (isEarFile(archive)) {
|
||||||
|
result.addAll(scanRoot(archive));
|
||||||
|
result.addAll(warScanner.scanWars(getWars(archive)));
|
||||||
|
|
||||||
|
} else if (isWarFile(archive)) {
|
||||||
|
result.addAll(warScanner.scanWars(Arrays.asList(new JarFile[] { archive })));
|
||||||
|
} else {
|
||||||
|
// treat as jar file
|
||||||
|
result.add(new JarClassPath(archive));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isWarFile(JarFile archive) {
|
||||||
|
return archive.getName().endsWith(".war");
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isEarFile(JarFile archive) {
|
||||||
|
return archive.getName().endsWith(".ear");
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<InspectableClasspath> directoryAsClasspath(File archiveFile, List<InspectableClasspath> result) {
|
||||||
File[] list = archiveFile.listFiles();
|
File[] list = archiveFile.listFiles();
|
||||||
for (File entry : list) {
|
for (File entry : list) {
|
||||||
if (entry.getName().endsWith(".jar")) {
|
if (entry.getName().endsWith(".jar")) {
|
||||||
result.add(new JarClassPath(new JarFile(entry)));
|
result.add(new JarClassPath(createJar(entry)));
|
||||||
} else if (entry.getName().endsWith(".class")) {
|
} else if (entry.getName().endsWith(".class")) {
|
||||||
result.add(new DirClassPath(archiveFile));
|
result.add(new DirClassPath(archiveFile));
|
||||||
break;
|
break;
|
||||||
|
|
@ -52,102 +73,12 @@ public class ArchiveScanner implements Scanner {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
JarFile archive = new JarFile(archiveFile);
|
private JarFile createJar(File archiveFile) {
|
||||||
if (archive.getName().endsWith(".ear")) {
|
|
||||||
result.addAll(scanRoot(archive));
|
|
||||||
result.addAll(scanWars(getWars(archive)));
|
|
||||||
|
|
||||||
} else if (archive.getName().endsWith(".war")) {
|
|
||||||
result.addAll(scanWars(Arrays.asList(new JarFile[] { archive })));
|
|
||||||
} else {
|
|
||||||
// treat as jar file
|
|
||||||
result.add(new JarClassPath(archive));
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<ClassPath> scanWars(List<JarFile> wars) {
|
|
||||||
List<ClassPath> classpaths = new ArrayList<ClassPath>();
|
|
||||||
for (JarFile war : wars) {
|
|
||||||
classpaths.addAll(scanWar(war));
|
|
||||||
}
|
|
||||||
return classpaths;
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<ClassPath> scanWar(JarFile warfile) {
|
|
||||||
List<ClassPath> classpaths = new ArrayList<ClassPath>();
|
|
||||||
File classesDir = createTempLocation(classpaths);
|
|
||||||
classpaths.add(new DirClassPath(classesDir));
|
|
||||||
for (Enumeration<JarEntry> entries = warfile.entries(); entries.hasMoreElements();) {
|
|
||||||
JarEntry entry = (JarEntry) entries.nextElement();
|
|
||||||
if (isArchive(entry)) {
|
|
||||||
try {
|
try {
|
||||||
addToClasspath(warfile, classpaths, entry);
|
return new JarFile(archiveFile);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new RuntimeException(e);
|
throw new JarCouldNotBeCreated(archiveFile.getAbsolutePath());
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
extractClass(warfile, entry, classesDir);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return classpaths;
|
|
||||||
}
|
|
||||||
|
|
||||||
private File createTempLocation(List<ClassPath> classpaths) {
|
|
||||||
File classesDir = new File(new File(System.getProperty("java.io.tmpdir")), "classes"
|
|
||||||
+ System.currentTimeMillis());
|
|
||||||
boolean dirsMade = classesDir.mkdirs();
|
|
||||||
if (!dirsMade) {
|
|
||||||
throw new RuntimeException("Directory " + classesDir + " could not be created");
|
|
||||||
}
|
|
||||||
return classesDir;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addToClasspath(JarFile warfile, List<ClassPath> classpaths, JarEntry entry) throws IOException {
|
|
||||||
File jarFile = Util.extractFile(warfile, entry);
|
|
||||||
classpaths.add(new JarClassPath(new JarFile(jarFile)));
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isArchive(JarEntry entry) {
|
|
||||||
String name = entry.getName();
|
|
||||||
return name.startsWith("WEB-INF/lib") && name.endsWith(".jar");
|
|
||||||
}
|
|
||||||
|
|
||||||
private File extractClass(JarFile warfile, ZipEntry entry, File classesDir) {
|
|
||||||
Matcher matcher = classPattern.matcher(entry.getName());
|
|
||||||
if (matcher.matches()) {
|
|
||||||
String className = matcher.group(1) + ".class";
|
|
||||||
Matcher matcher2 = packagePattern.matcher(className);
|
|
||||||
if (matcher2.matches()) {
|
|
||||||
String packageName = matcher2.group(1);
|
|
||||||
File classDir = createUnarchivedPackageDicectory(classesDir, packageName);
|
|
||||||
String simpleClassName = matcher2.group(2);
|
|
||||||
File classFile = new File(classDir, simpleClassName);
|
|
||||||
return createUnarchivedClassfile(warfile, entry, classFile);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private File createUnarchivedClassfile(JarFile warfile, ZipEntry entry, File classFile) {
|
|
||||||
try {
|
|
||||||
FileOutputStream out = new FileOutputStream(classFile);
|
|
||||||
IOUtils.copy(warfile.getInputStream(entry), out);
|
|
||||||
return classFile;
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private File createUnarchivedPackageDicectory(File classesDir, String packageName) {
|
|
||||||
File classDir = new File(classesDir, packageName);
|
|
||||||
if (!classDir.exists()) {
|
|
||||||
boolean packageDirsMade = classDir.mkdirs();
|
|
||||||
if (!packageDirsMade) {
|
|
||||||
throw new RuntimeException("Directory " + classDir + " could not be created");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return classDir;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<JarFile> getWars(JarFile earfile) {
|
private List<JarFile> getWars(JarFile earfile) {
|
||||||
|
|
@ -170,13 +101,13 @@ public class ArchiveScanner implements Scanner {
|
||||||
return entry.getName().endsWith(".war");
|
return entry.getName().endsWith(".war");
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<ClassPath> scanRoot(JarFile earfile) {
|
private List<InspectableClasspath> scanRoot(JarFile earfile) {
|
||||||
List<ClassPath> classpaths = new ArrayList<ClassPath>();
|
List<InspectableClasspath> classpaths = new ArrayList<InspectableClasspath>();
|
||||||
for (Enumeration<JarEntry> entries = earfile.entries(); entries.hasMoreElements();) {
|
for (Enumeration<JarEntry> entries = earfile.entries(); entries.hasMoreElements();) {
|
||||||
JarEntry entry = (JarEntry) entries.nextElement();
|
JarEntry entry = (JarEntry) entries.nextElement();
|
||||||
if (isJarfile(entry)) {
|
if (isJarfile(entry)) {
|
||||||
try {
|
try {
|
||||||
addToClasspath(earfile, classpaths, entry);
|
ClasspathAdder.addEntriesFromWarToClasspath(earfile, classpaths, entry);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
|
|
@ -189,4 +120,10 @@ public class ArchiveScanner implements Scanner {
|
||||||
return entry.getName().endsWith(".jar");
|
return entry.getName().endsWith(".jar");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("serial")
|
||||||
|
private static class JarCouldNotBeCreated extends RuntimeException {
|
||||||
|
public JarCouldNotBeCreated(String name) {
|
||||||
|
super(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,33 +6,30 @@ import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.jar.JarFile;
|
import java.util.jar.JarFile;
|
||||||
|
|
||||||
import yooze.JarClassPath;
|
import yooze.InspectableClasspath;
|
||||||
|
import yooze.Scanner;
|
||||||
import javassist.ClassPath;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Scans a directory ("lib") recursively for jarfiles and adds them to the
|
* Scans a directory ("lib") recursively for jarfiles and adds them to the classpath
|
||||||
* classpath
|
|
||||||
*
|
|
||||||
* @author sander
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public class LibScanner implements Scanner {
|
public class LibScanner implements Scanner {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<ClassPath> scanArchive(String archiveName) throws IOException {
|
public List<InspectableClasspath> scanArchive(String archiveName) throws IOException {
|
||||||
return scanArchive(new File(archiveName));
|
return scanArchive(new File(archiveName));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<ClassPath> scanArchive(File file) throws IOException {
|
public List<InspectableClasspath> scanArchive(File file) throws IOException {
|
||||||
List<ClassPath> classpaths = new ArrayList<ClassPath>();
|
List<InspectableClasspath> classpaths = new ArrayList<InspectableClasspath>();
|
||||||
return doScanArchive(classpaths,file);
|
return doScanArchive(classpaths, file);
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<ClassPath> doScanArchive(List<ClassPath> classpaths, File file)
|
/*
|
||||||
|
* return argument classpaths for sake of recursion
|
||||||
|
*/
|
||||||
|
private List<InspectableClasspath> doScanArchive(List<InspectableClasspath> classpaths, File file)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
|
|
||||||
File[] entries = file.listFiles();
|
File[] entries = file.listFiles();
|
||||||
for (File entry : entries) {
|
for (File entry : entries) {
|
||||||
if (entry.isDirectory()) {
|
if (entry.isDirectory()) {
|
||||||
|
|
@ -43,5 +40,4 @@ public class LibScanner implements Scanner {
|
||||||
}
|
}
|
||||||
return classpaths;
|
return classpaths;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,13 +0,0 @@
|
||||||
package yooze.scanner;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import javassist.ClassPath;
|
|
||||||
|
|
||||||
public interface Scanner {
|
|
||||||
public List<ClassPath> scanArchive(String archiveName) throws IOException;
|
|
||||||
|
|
||||||
public List<ClassPath> scanArchive(File file) throws IOException;
|
|
||||||
}
|
|
||||||
|
|
@ -11,34 +11,32 @@ import java.util.List;
|
||||||
import java.util.jar.JarFile;
|
import java.util.jar.JarFile;
|
||||||
import java.util.zip.GZIPInputStream;
|
import java.util.zip.GZIPInputStream;
|
||||||
|
|
||||||
import javassist.ClassPath;
|
|
||||||
|
|
||||||
import org.xeustechnologies.jtar.TarEntry;
|
import org.xeustechnologies.jtar.TarEntry;
|
||||||
import org.xeustechnologies.jtar.TarInputStream;
|
import org.xeustechnologies.jtar.TarInputStream;
|
||||||
|
|
||||||
import yooze.JarClassPath;
|
import yooze.InspectableClasspath;
|
||||||
|
import yooze.Scanner;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author sander
|
* @author sander
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class TgzScanner implements Scanner {
|
public class TgzScanner implements Scanner {
|
||||||
public List<ClassPath> scanArchive(String archiveName) throws IOException {
|
public List<InspectableClasspath> scanArchive(String archiveName) throws IOException {
|
||||||
return scanArchive(new File(archiveName));
|
return scanArchive(new File(archiveName));
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<ClassPath> scanArchive(File file) throws IOException {
|
public List<InspectableClasspath> scanArchive(File file) throws IOException {
|
||||||
List<ClassPath> classpaths = new ArrayList<ClassPath>();
|
List<InspectableClasspath> classpaths = new ArrayList<InspectableClasspath>();
|
||||||
TarInputStream tarInputStream = new TarInputStream(new GZIPInputStream(
|
TarInputStream tarInputStream = new TarInputStream(new GZIPInputStream(new BufferedInputStream(
|
||||||
new BufferedInputStream(new FileInputStream(file))));
|
new FileInputStream(file))));
|
||||||
TarEntry entry;
|
TarEntry entry;
|
||||||
while ((entry = tarInputStream.getNextEntry()) != null) {
|
while ((entry = tarInputStream.getNextEntry()) != null) {
|
||||||
if (entry.getName().endsWith(".jar")) {
|
if (entry.getName().endsWith(".jar")) {
|
||||||
int count;
|
int count;
|
||||||
byte data[] = new byte[2048];
|
byte data[] = new byte[2048];
|
||||||
|
|
||||||
File tempFile = File.createTempFile(
|
File tempFile = File.createTempFile(singleName(entry.getName()), ".jar");
|
||||||
singleName(entry.getName()), ".jar");
|
|
||||||
FileOutputStream fos = new FileOutputStream(tempFile);
|
FileOutputStream fos = new FileOutputStream(tempFile);
|
||||||
BufferedOutputStream dest = new BufferedOutputStream(fos);
|
BufferedOutputStream dest = new BufferedOutputStream(fos);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,22 +0,0 @@
|
||||||
package yooze;
|
|
||||||
|
|
||||||
import java.util.Iterator;
|
|
||||||
|
|
||||||
import javassist.ClassPool;
|
|
||||||
import javassist.CtClass;
|
|
||||||
import javassist.NotFoundException;
|
|
||||||
import javassist.bytecode.ConstPool;
|
|
||||||
|
|
||||||
public class AssTest {
|
|
||||||
public static void main(String[] args) throws NotFoundException {
|
|
||||||
ClassPool pool = ClassPool.getDefault();
|
|
||||||
CtClass c1 = pool.get("yooze.Class1");
|
|
||||||
ConstPool constPool = c1.getClassFile().getConstPool();
|
|
||||||
|
|
||||||
|
|
||||||
for (Iterator iterator = constPool.getClassNames().iterator();iterator.hasNext();){
|
|
||||||
System.out.println(iterator.next());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,80 +0,0 @@
|
||||||
package yooze;
|
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import junit.framework.Assert;
|
|
||||||
|
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.Test;
|
|
||||||
import org.junit.runner.RunWith;
|
|
||||||
import org.springframework.test.context.ContextConfiguration;
|
|
||||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
|
||||||
|
|
||||||
import yooze.domain.Graph;
|
|
||||||
|
|
||||||
@RunWith(SpringJUnit4ClassRunner.class)
|
|
||||||
@ContextConfiguration(locations = "classpath:applicationContext-test.xml")
|
|
||||||
public class DotPrinterTest {
|
|
||||||
|
|
||||||
@Before
|
|
||||||
public void clearClassCache() {
|
|
||||||
ClassCache.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void dotPrinting() throws IOException {
|
|
||||||
GraphBuilder directoryBuilder = GraphBuilder
|
|
||||||
.getClassesDirectoryBuilder();
|
|
||||||
directoryBuilder.setPackageExcludePatterns(".*?Class4");
|
|
||||||
directoryBuilder.setPackageIncludePatterns(".*?.Class.");
|
|
||||||
Graph graph = directoryBuilder.build("target/test-classes",
|
|
||||||
"yooze.Class1");
|
|
||||||
|
|
||||||
ByteArrayOutputStream bytes = new ByteArrayOutputStream(500);
|
|
||||||
DotPrinter d = new DotPrinter(bytes);
|
|
||||||
d.print(graph);
|
|
||||||
String dotText = new String(bytes.toByteArray());
|
|
||||||
d.close();
|
|
||||||
String[] expectedDotTextLines = { "digraph \"test-classes\" {",
|
|
||||||
"graph [size=100,100];",
|
|
||||||
"\"yooze.Class1\" [shape=box, height=0.0];",
|
|
||||||
"\"yooze.Class1\" -> \"yooze.Class2\"",
|
|
||||||
"\"yooze.Class2\" [shape=box, height=0.0];",
|
|
||||||
"\"yooze.Class2\" -> \"yooze.Class3\"",
|
|
||||||
"\"yooze.Class3\" [shape=box, height=0.0];",
|
|
||||||
"\"yooze.Class3\" -> \"yooze.Class1\"",
|
|
||||||
"\"yooze.Class1\" [shape=box, height=0.0];",
|
|
||||||
"\"yooze.Class2\" [shape=box, height=0.0];",
|
|
||||||
"\"yooze.Class3\" [shape=box, height=0.0];", "}" };
|
|
||||||
expectTextContainsLines(dotText, expectedDotTextLines);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void expectTextContainsLines(String dotText,
|
|
||||||
String[] expectedDotTextLines) {
|
|
||||||
for (String line : expectedDotTextLines) {
|
|
||||||
Assert.assertTrue("Not found:" + line, dotText.contains(line));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void noReference() throws IOException {
|
|
||||||
GraphBuilder directoryBuilder = GraphBuilder
|
|
||||||
.getClassesDirectoryBuilder();
|
|
||||||
directoryBuilder.setPackageExcludePatterns("");
|
|
||||||
directoryBuilder.setPackageIncludePatterns("yooze.Class4");
|
|
||||||
Graph graph = directoryBuilder.build("target/test-classes",
|
|
||||||
"yooze.Class4");
|
|
||||||
ByteArrayOutputStream bytes = new ByteArrayOutputStream(1000);
|
|
||||||
DotPrinter d = new DotPrinter(bytes);
|
|
||||||
d.print(graph);
|
|
||||||
String dotText = new String(bytes.toByteArray());
|
|
||||||
System.out.println(dotText);
|
|
||||||
String[] expectedDotTextLines = { "digraph \"test-classes\" {",
|
|
||||||
"graph [size=100,100];",
|
|
||||||
"\"yooze.Class4\" [shape=box, height=0.0];",
|
|
||||||
"\"yooze.Class4\";", "}" };
|
|
||||||
d.close();
|
|
||||||
expectTextContainsLines(dotText, expectedDotTextLines);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,50 +0,0 @@
|
||||||
package yooze;
|
|
||||||
|
|
||||||
import static org.hamcrest.core.Is.is;
|
|
||||||
import static org.junit.Assert.assertThat;
|
|
||||||
import static org.junit.Assert.assertTrue;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import javassist.ClassPath;
|
|
||||||
|
|
||||||
import org.junit.Test;
|
|
||||||
import org.junit.runner.RunWith;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.test.context.ContextConfiguration;
|
|
||||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
|
||||||
|
|
||||||
import yooze.scanner.ArchiveScanner;
|
|
||||||
|
|
||||||
@RunWith(SpringJUnit4ClassRunner.class)
|
|
||||||
@ContextConfiguration(locations = "classpath:applicationContext-test.xml")
|
|
||||||
public class EarScannerTest {
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private Config config;
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void scanner() throws IOException {
|
|
||||||
List<ClassPath> classpaths = new ArchiveScanner().scanArchive(config
|
|
||||||
.getEarFile());
|
|
||||||
for (ClassPath path : classpaths) {
|
|
||||||
if (path instanceof DirClassPath) {
|
|
||||||
List<String> classes = ((Inspectable) path).getClasses();
|
|
||||||
assertThat(classes.size(), is(49));
|
|
||||||
}
|
|
||||||
if (path instanceof JarClassPath) {
|
|
||||||
String name = ((Inspectable) path).getResourceName();
|
|
||||||
if (name.contains("standard")) {
|
|
||||||
List<String> classes = ((Inspectable) path).getClasses();
|
|
||||||
assertTrue(classes.contains("org.apache.taglibs.standard.tag.common.sql.DataSourceUtil"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setConfig(Config config) {
|
|
||||||
this.config = config;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -12,6 +12,7 @@ import org.junit.runner.RunWith;
|
||||||
import org.springframework.test.context.ContextConfiguration;
|
import org.springframework.test.context.ContextConfiguration;
|
||||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||||
|
|
||||||
|
import yooze.application.GraphBuilderFactory;
|
||||||
import yooze.domain.ClassModel;
|
import yooze.domain.ClassModel;
|
||||||
import yooze.domain.Graph;
|
import yooze.domain.Graph;
|
||||||
|
|
||||||
|
|
@ -28,7 +29,7 @@ public class GraphTest {
|
||||||
public void buildGraph() throws IOException {
|
public void buildGraph() throws IOException {
|
||||||
// new Yooze("/tmp/test").createNeoGraph("target/test-classes",
|
// new Yooze("/tmp/test").createNeoGraph("target/test-classes",
|
||||||
// ".*?.Class.");
|
// ".*?.Class.");
|
||||||
GraphBuilder libDirectoryBuilder = GraphBuilder
|
GraphBuilder libDirectoryBuilder = GraphBuilderFactory
|
||||||
.getClassesDirectoryBuilder();
|
.getClassesDirectoryBuilder();
|
||||||
libDirectoryBuilder.setPackageIncludePatterns(".*?.Class.");
|
libDirectoryBuilder.setPackageIncludePatterns(".*?.Class.");
|
||||||
libDirectoryBuilder.setPackageExcludePatterns("");
|
libDirectoryBuilder.setPackageExcludePatterns("");
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,9 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.test.context.ContextConfiguration;
|
import org.springframework.test.context.ContextConfiguration;
|
||||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||||
|
|
||||||
|
import yooze.application.GraphBuilderFactory;
|
||||||
import yooze.domain.Graph;
|
import yooze.domain.Graph;
|
||||||
|
import yooze.output.DotPrinter;
|
||||||
|
|
||||||
@RunWith(SpringJUnit4ClassRunner.class)
|
@RunWith(SpringJUnit4ClassRunner.class)
|
||||||
@ContextConfiguration(locations = "classpath:applicationContext-test.xml")
|
@ContextConfiguration(locations = "classpath:applicationContext-test.xml")
|
||||||
|
|
@ -20,7 +22,7 @@ public class LargePackageTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void largePackage() throws IOException {
|
public void largePackage() throws IOException {
|
||||||
GraphBuilder earBuilder = GraphBuilder.getEarBuilder();
|
GraphBuilder earBuilder = GraphBuilderFactory.getEarBuilder();
|
||||||
earBuilder.setPackageIncludePatterns("");
|
earBuilder.setPackageIncludePatterns("");
|
||||||
earBuilder.setPackageExcludePatterns("java.*");
|
earBuilder.setPackageExcludePatterns("java.*");
|
||||||
Graph graph = earBuilder.buildClassDepencyGraph(config.getEarFile(),
|
Graph graph = earBuilder.buildClassDepencyGraph(config.getEarFile(),
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ import org.junit.runner.RunWith;
|
||||||
import org.springframework.test.context.ContextConfiguration;
|
import org.springframework.test.context.ContextConfiguration;
|
||||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||||
|
|
||||||
import yooze.domain.Graph;
|
import yooze.application.GraphBuilderFactory;
|
||||||
import yooze.domain.MethodModel;
|
import yooze.domain.MethodModel;
|
||||||
import yooze.dto.MethodDto;
|
import yooze.dto.MethodDto;
|
||||||
|
|
||||||
|
|
@ -22,22 +22,18 @@ import yooze.dto.MethodDto;
|
||||||
public class MethodReferencesTest {
|
public class MethodReferencesTest {
|
||||||
@Test
|
@Test
|
||||||
public void test() throws IOException {
|
public void test() throws IOException {
|
||||||
GraphBuilder directoryBuilder = GraphBuilder
|
GraphBuilder directoryBuilder = GraphBuilderFactory.getClassesDirectoryBuilder();
|
||||||
.getClassesDirectoryBuilder();
|
|
||||||
directoryBuilder.setPackageIncludePatterns("yooze.Class.*");
|
directoryBuilder.setPackageIncludePatterns("yooze.Class.*");
|
||||||
Graph graph = directoryBuilder.build("target/test-classes",
|
directoryBuilder.build("target/test-classes", "yooze.Class1");
|
||||||
"yooze.Class1");
|
MethodModel mm1 = MethodCache.getInstance().get("yooze.Class1.rup(int)");
|
||||||
MethodModel mm1 = MethodCache.getInstance()
|
|
||||||
.get("yooze.Class1.rup(int)");
|
|
||||||
Assert.assertNotNull(mm1);
|
Assert.assertNotNull(mm1);
|
||||||
MethodModel mm2 = MethodCache.getInstance().get("yooze.Class3.dof()");
|
MethodModel mm2 = MethodCache.getInstance().get("yooze.Class3.dof()");
|
||||||
Assert.assertNotNull(mm2);
|
Assert.assertNotNull(mm2);
|
||||||
List<MethodModel> callers = mm1.getCallers();
|
List<MethodModel> callers = mm1.getCallers();
|
||||||
Assert.assertTrue(callers.contains(mm2));
|
Assert.assertTrue(callers.contains(mm2));
|
||||||
MethodDto dto = MethodDto.create(MethodCache.getInstance().get(
|
MethodDto dto = MethodDto.create(MethodCache.getInstance().get("yooze.Class1.zoef(yooze.Class2)"));
|
||||||
"yooze.Class1.zoef(yooze.Class2)"));
|
JsonGenerator jg = new ObjectMapper().getJsonFactory().createJsonGenerator(
|
||||||
JsonGenerator jg = new ObjectMapper().getJsonFactory()
|
new FileOutputStream("c:\\ff\\out.json"));
|
||||||
.createJsonGenerator(new FileOutputStream("c:\\ff\\out.json"));
|
|
||||||
jg.writeObject(dto);
|
jg.writeObject(dto);
|
||||||
jg.close();
|
jg.close();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.test.context.ContextConfiguration;
|
import org.springframework.test.context.ContextConfiguration;
|
||||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||||
|
|
||||||
|
import yooze.application.GraphBuilderFactory;
|
||||||
import yooze.domain.ClassModel;
|
import yooze.domain.ClassModel;
|
||||||
import yooze.domain.Graph;
|
import yooze.domain.Graph;
|
||||||
|
|
||||||
|
|
@ -23,7 +24,7 @@ public class TgzBuilderTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void tgzBuilder() throws IOException {
|
public void tgzBuilder() throws IOException {
|
||||||
GraphBuilder tgzBuilder = GraphBuilder.getDefaultTgzBuilder();
|
GraphBuilder tgzBuilder = GraphBuilderFactory.getDefaultTgzBuilder();
|
||||||
tgzBuilder.setPackageIncludePatterns("nl.*");
|
tgzBuilder.setPackageIncludePatterns("nl.*");
|
||||||
tgzBuilder.setPackageExcludePatterns("");
|
tgzBuilder.setPackageExcludePatterns("");
|
||||||
Graph graph = tgzBuilder.buildClassDepencyGraph(config.getTgzFile(),
|
Graph graph = tgzBuilder.buildClassDepencyGraph(config.getTgzFile(),
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue