new
This commit is contained in:
parent
85d2346835
commit
b24a3db5fd
48 changed files with 2061 additions and 0 deletions
BIN
example.png
Normal file
BIN
example.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 7.3 MiB |
135
pom.xml
Normal file
135
pom.xml
Normal file
|
|
@ -0,0 +1,135 @@
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
|
||||||
|
http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<groupId>nl.yooze</groupId>
|
||||||
|
<artifactId>yooze</artifactId>
|
||||||
|
<packaging>jar</packaging>
|
||||||
|
<version>0.1-SNAPSHOT</version>
|
||||||
|
<name>yooze</name>
|
||||||
|
<url>www.cjib.nl</url>
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<version>2.3.2</version>
|
||||||
|
<configuration>
|
||||||
|
<source>1.6</source>
|
||||||
|
<target>1.6</target>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.codehaus.mojo</groupId>
|
||||||
|
<artifactId>build-helper-maven-plugin</artifactId>
|
||||||
|
<version>1.5</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>add-source</id>
|
||||||
|
<phase>generate-sources</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>add-test-source</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<sources>
|
||||||
|
<source>src/testdummies/java</source>
|
||||||
|
</sources>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.neo4j</groupId>
|
||||||
|
<artifactId>neo4j</artifactId>
|
||||||
|
<version>1.4.M06</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>commons-io</groupId>
|
||||||
|
<artifactId>commons-io</artifactId>
|
||||||
|
<version>1.4</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>junit</groupId>
|
||||||
|
<artifactId>junit</artifactId>
|
||||||
|
<version>4.8.2</version>
|
||||||
|
<type>jar</type>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework</groupId>
|
||||||
|
<artifactId>spring-beans</artifactId>
|
||||||
|
<version>3.0.5.RELEASE</version>
|
||||||
|
<type>jar</type>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework</groupId>
|
||||||
|
<artifactId>spring-test</artifactId>
|
||||||
|
<version>3.0.5.RELEASE</version>
|
||||||
|
<type>jar</type>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>javax.annotation</groupId>
|
||||||
|
<artifactId>jsr250-api</artifactId>
|
||||||
|
<version>1.0</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework</groupId>
|
||||||
|
<artifactId>spring-context</artifactId>
|
||||||
|
<version>3.0.5.RELEASE</version>
|
||||||
|
<type>jar</type>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>javassist</groupId>
|
||||||
|
<artifactId>javassist</artifactId>
|
||||||
|
<version>3.12.1.GA</version>
|
||||||
|
<type>jar</type>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>ch.qos.logback</groupId>
|
||||||
|
<artifactId>logback-core</artifactId>
|
||||||
|
<version>0.9.29</version>
|
||||||
|
<type>jar</type>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>slf4j-api</artifactId>
|
||||||
|
<version>1.6.1</version>
|
||||||
|
<type>jar</type>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>ch.qos.logback</groupId>
|
||||||
|
<artifactId>logback-classic</artifactId>
|
||||||
|
<version>0.9.29</version>
|
||||||
|
<type>jar</type>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.xeustechnologies</groupId>
|
||||||
|
<artifactId>jtar</artifactId>
|
||||||
|
<version>1.0.4</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.codehaus.jackson</groupId>
|
||||||
|
<artifactId>jackson-mapper-asl</artifactId>
|
||||||
|
<version>1.9.10</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</project>
|
||||||
|
|
||||||
BIN
src/._main
Normal file
BIN
src/._main
Normal file
Binary file not shown.
30
src/main/java/yooze/ClassByteCountingInputStream.java
Normal file
30
src/main/java/yooze/ClassByteCountingInputStream.java
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
package yooze;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
public class ClassByteCountingInputStream extends InputStream {
|
||||||
|
|
||||||
|
private InputStream nestedStream;
|
||||||
|
private String className;
|
||||||
|
private long count=0;
|
||||||
|
|
||||||
|
public ClassByteCountingInputStream(String className,
|
||||||
|
InputStream inputStream) {
|
||||||
|
this.className=className;
|
||||||
|
this.nestedStream=inputStream;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int read() throws IOException {
|
||||||
|
count++;
|
||||||
|
return nestedStream.read();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() throws IOException {
|
||||||
|
nestedStream.close();
|
||||||
|
Statistics.addBytecodeSizeForClass(className, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
28
src/main/java/yooze/ClassCache.java
Normal file
28
src/main/java/yooze/ClassCache.java
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
package yooze;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
import yooze.domain.ClassModel;
|
||||||
|
|
||||||
|
public class ClassCache {
|
||||||
|
private final static Map<String, ClassModel> entries = new ConcurrentHashMap<String, ClassModel>();
|
||||||
|
|
||||||
|
public static boolean contains(String classname) {
|
||||||
|
return entries.containsKey(classname);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ClassModel createNewDummyModel(String name) {
|
||||||
|
ClassModel classModel = new ClassModel(name);
|
||||||
|
entries.put(name, classModel);
|
||||||
|
return classModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ClassModel get(String className) {
|
||||||
|
return entries.get(className);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void add(String className, ClassModel model) {
|
||||||
|
entries.put(className, model);
|
||||||
|
}
|
||||||
|
}
|
||||||
177
src/main/java/yooze/ClassModelBuilder.java
Normal file
177
src/main/java/yooze/ClassModelBuilder.java
Normal file
|
|
@ -0,0 +1,177 @@
|
||||||
|
package yooze;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
import javassist.ClassPool;
|
||||||
|
import javassist.CtClass;
|
||||||
|
import javassist.CtMethod;
|
||||||
|
import javassist.NotFoundException;
|
||||||
|
import javassist.bytecode.ConstPool;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import yooze.domain.ClassModel;
|
||||||
|
import yooze.domain.MethodCallModel;
|
||||||
|
import yooze.domain.MethodModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds a ClassModel.
|
||||||
|
*/
|
||||||
|
public class ClassModelBuilder {
|
||||||
|
private static Logger log = LoggerFactory.getLogger(ClassModelBuilder.class);
|
||||||
|
|
||||||
|
private Pattern[] packageIncludePatterns;
|
||||||
|
private Pattern[] packageExcludePatterns;
|
||||||
|
private ClassPool pool;
|
||||||
|
|
||||||
|
public ClassModelBuilder(ClassPool pool) {
|
||||||
|
this.pool = pool;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClassModel scanClassOrSkip(String className) {
|
||||||
|
if (shouldSkip(className))
|
||||||
|
return null;
|
||||||
|
if (ClassCache.contains(className)) {
|
||||||
|
return ClassCache.get(className);
|
||||||
|
}
|
||||||
|
log.info("scanning {}", className);
|
||||||
|
|
||||||
|
return scan(className);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private ClassModel scan(String className) {
|
||||||
|
ClassModel model = new ClassModel(className);
|
||||||
|
ClassCache.add(className, model);
|
||||||
|
try {
|
||||||
|
return tryScan(className, model);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn("Loading class,", e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private ClassModel tryScan(String className, ClassModel model) throws NotFoundException {
|
||||||
|
CtClass ctClass = pool.get(className);
|
||||||
|
if (isScannable(ctClass)) {
|
||||||
|
ConstPool constPool = ctClass.getClassFile().getConstPool();
|
||||||
|
|
||||||
|
addClassReferences(model, constPool);
|
||||||
|
addMethods(model, ctClass);
|
||||||
|
resolveMethodReferences();
|
||||||
|
return model;
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isScannable(CtClass ctClass) {
|
||||||
|
return !ctClass.isFrozen();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void resolveMethodReferences() {
|
||||||
|
for (MethodModel method : MethodCache.getInstance().getMethods()) {
|
||||||
|
for (MethodCallModel methodCall : method.getMethodCalls()) {
|
||||||
|
MethodModel calledMethod = methodCall.getCalledMethod();
|
||||||
|
if (calledMethod != null && calledMethod != method) {
|
||||||
|
calledMethod.addCaller(method);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addMethods(ClassModel containingClass, CtClass ctClass) {
|
||||||
|
CtMethod[] methods = ctClass.getMethods();
|
||||||
|
for (CtMethod method : methods) {
|
||||||
|
containingClass.addMethod(MethodModel.create(containingClass, method));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addClassReferences(ClassModel model, ConstPool constPool) {
|
||||||
|
Set<String> classNames = constPool.getClassNames();
|
||||||
|
for (String classResourcename : classNames) {
|
||||||
|
String refClassName = Util.toClassName(classResourcename);
|
||||||
|
addClassReference(model, refClassName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addClassReference(ClassModel model, String refClassName) {
|
||||||
|
/* recursive invocation */
|
||||||
|
ClassModel scannedClass = scanClassOrSkip(refClassName);
|
||||||
|
if (scannedClass != null && !scannedClass.equals(model)) {
|
||||||
|
model.addReference(scannedClass);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean shouldSkip(String className) {
|
||||||
|
if (!isIncluded(className)) {
|
||||||
|
log.debug("skipping {}", className);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (isExcluded(className)) {
|
||||||
|
log.debug("skipping {}", className);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if (isInnerClass(className)) {
|
||||||
|
// log.debug("skipping inner class {}", className);
|
||||||
|
// return true;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if (className.equals("java.lang.Object")) {
|
||||||
|
// return true;
|
||||||
|
// }
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isInnerClass(String className) {
|
||||||
|
return className.contains("$");
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isExcluded(String className) {
|
||||||
|
if (packageExcludePatterns != null) {
|
||||||
|
for (Pattern excludePattern : packageExcludePatterns) {
|
||||||
|
Matcher matcher = excludePattern.matcher(className);
|
||||||
|
if (matcher.matches()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isIncluded(String className) {
|
||||||
|
if (packageIncludePatterns != null) {
|
||||||
|
for (Pattern includePattern : packageIncludePatterns) {
|
||||||
|
Matcher matcher = includePattern.matcher(className);
|
||||||
|
if (matcher.matches()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPackageIncludePatterns(String... packageIncludePatterns) {
|
||||||
|
if (packageIncludePatterns != null) {
|
||||||
|
this.packageIncludePatterns = new Pattern[packageIncludePatterns.length];
|
||||||
|
int i = 0;
|
||||||
|
for (String pattern : packageIncludePatterns) {
|
||||||
|
this.packageIncludePatterns[i++] = Pattern.compile(pattern);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPackageExcludePatterns(String... packageExcludePatterns) {
|
||||||
|
if (packageExcludePatterns != null) {
|
||||||
|
this.packageExcludePatterns = new Pattern[packageExcludePatterns.length];
|
||||||
|
int i = 0;
|
||||||
|
for (String pattern : packageExcludePatterns) {
|
||||||
|
this.packageExcludePatterns[i++] = Pattern.compile(pattern);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
28
src/main/java/yooze/ClassesDirScanner.java
Normal file
28
src/main/java/yooze/ClassesDirScanner.java
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
90
src/main/java/yooze/DirClassPath.java
Normal file
90
src/main/java/yooze/DirClassPath.java
Normal file
|
|
@ -0,0 +1,90 @@
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
59
src/main/java/yooze/DotPrinter.java
Normal file
59
src/main/java/yooze/DotPrinter.java
Normal file
|
|
@ -0,0 +1,59 @@
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
105
src/main/java/yooze/GraphBuilder.java
Normal file
105
src/main/java/yooze/GraphBuilder.java
Normal file
|
|
@ -0,0 +1,105 @@
|
||||||
|
package yooze;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import javassist.ClassPath;
|
||||||
|
import javassist.ClassPool;
|
||||||
|
import yooze.domain.ClassModel;
|
||||||
|
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 ClassModelBuilder.
|
||||||
|
*/
|
||||||
|
public class GraphBuilder {
|
||||||
|
|
||||||
|
private Scanner scanner;
|
||||||
|
private ClassModelBuilder classModelBuilder;
|
||||||
|
private String[] packageIncludePatterns;
|
||||||
|
private String[] packageExcludePatterns;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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) {
|
||||||
|
super();
|
||||||
|
this.scanner = scanner;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Graph build(String archive) throws IOException {
|
||||||
|
return buildClassDepencyGraph(new File(archive));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Graph buildClassDepencyGraph(File archiveFile) throws IOException {
|
||||||
|
List<ClassPath> cpList = scanner.scanArchive(archiveFile);
|
||||||
|
|
||||||
|
ClassPool pool = ClassPool.getDefault();
|
||||||
|
for (ClassPath cp : cpList) {
|
||||||
|
pool.appendClassPath(cp);
|
||||||
|
}
|
||||||
|
|
||||||
|
Graph graph = createClassDependencyGraph(pool, cpList);
|
||||||
|
graph.setName(archiveFile.getName());
|
||||||
|
return graph;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Graph createClassDependencyGraph(ClassPool pool, List<ClassPath> classpath) {
|
||||||
|
Graph graph = new Graph();
|
||||||
|
classModelBuilder = new ClassModelBuilder(pool);
|
||||||
|
classModelBuilder.setPackageExcludePatterns(packageExcludePatterns);
|
||||||
|
classModelBuilder.setPackageIncludePatterns(packageIncludePatterns);
|
||||||
|
for (ClassPath lib : classpath) {
|
||||||
|
assert (lib instanceof Inspectable);
|
||||||
|
|
||||||
|
List<String> classes = ((Inspectable) lib).getClasses();
|
||||||
|
for (String className : classes) {
|
||||||
|
ClassModel newModel = classModelBuilder.scanClassOrSkip(className);
|
||||||
|
if (newModel != null) {
|
||||||
|
graph.add(newModel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return graph;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPackageIncludePatterns(String... packageIncludePatterns) {
|
||||||
|
this.packageIncludePatterns = packageIncludePatterns;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPackageExcludePatterns(String... packageExcludePatterns) {
|
||||||
|
this.packageExcludePatterns = packageExcludePatterns;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
8
src/main/java/yooze/Inspectable.java
Normal file
8
src/main/java/yooze/Inspectable.java
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
package yooze;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public interface Inspectable {
|
||||||
|
public String getResourceName();
|
||||||
|
public List<String> getClasses();
|
||||||
|
}
|
||||||
78
src/main/java/yooze/JarClassPath.java
Normal file
78
src/main/java/yooze/JarClassPath.java
Normal file
|
|
@ -0,0 +1,78 @@
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
32
src/main/java/yooze/MethodCache.java
Normal file
32
src/main/java/yooze/MethodCache.java
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
package yooze;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
import yooze.domain.MethodModel;
|
||||||
|
|
||||||
|
public class MethodCache {
|
||||||
|
private final Map<String, MethodModel> entries = new ConcurrentHashMap<String, MethodModel>();
|
||||||
|
private final static MethodCache instance = new MethodCache();
|
||||||
|
|
||||||
|
public static MethodCache getInstance() {
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean contains(String classname) {
|
||||||
|
return entries.containsKey(classname);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MethodModel get(String fullName) {
|
||||||
|
return entries.get(fullName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void add(MethodModel methodmodel) {
|
||||||
|
entries.put(methodmodel.getFullname(), methodmodel);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Collection<MethodModel> getMethods() {
|
||||||
|
return entries.values();
|
||||||
|
}
|
||||||
|
}
|
||||||
16
src/main/java/yooze/Statistics.java
Normal file
16
src/main/java/yooze/Statistics.java
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
package yooze;
|
||||||
|
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
public class Statistics {
|
||||||
|
private static ConcurrentHashMap<String, Long> bytecodeSizes=new ConcurrentHashMap<String, Long>();
|
||||||
|
|
||||||
|
public static void addBytecodeSizeForClass(String className, long size){
|
||||||
|
bytecodeSizes.put(className, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Long getByteCodeSizeForClass(String className){
|
||||||
|
Long value = bytecodeSizes.get(className);
|
||||||
|
return value==null?0:value;
|
||||||
|
}
|
||||||
|
}
|
||||||
39
src/main/java/yooze/Util.java
Normal file
39
src/main/java/yooze/Util.java
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
package yooze;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
import java.util.zip.ZipEntry;
|
||||||
|
import java.util.zip.ZipFile;
|
||||||
|
|
||||||
|
import org.apache.commons.io.IOUtils;
|
||||||
|
|
||||||
|
public class Util {
|
||||||
|
private final static Pattern fileNamePattern = Pattern.compile(".+/(.+)");
|
||||||
|
|
||||||
|
public static File extractFile(ZipFile file, ZipEntry entry)
|
||||||
|
throws IOException {
|
||||||
|
String name=entry.getName();
|
||||||
|
Matcher m = fileNamePattern.matcher(name);
|
||||||
|
if (m.matches()){//chop off path
|
||||||
|
name=m.group(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
File tempFile = File.createTempFile(name, ".file");
|
||||||
|
InputStream in = file.getInputStream(entry);
|
||||||
|
FileOutputStream out = new FileOutputStream(tempFile);
|
||||||
|
IOUtils.copy(in, out);
|
||||||
|
return tempFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String toClassResource(String className) {
|
||||||
|
return className.replaceAll("\\.", "/")+".class";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String toClassName(String classResource) {
|
||||||
|
return classResource.replaceAll("/", ".");
|
||||||
|
}
|
||||||
|
}
|
||||||
67
src/main/java/yooze/domain/ClassModel.java
Normal file
67
src/main/java/yooze/domain/ClassModel.java
Normal file
|
|
@ -0,0 +1,67 @@
|
||||||
|
package yooze.domain;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class ClassModel {
|
||||||
|
final private String name;
|
||||||
|
|
||||||
|
final private List<ClassModel> references = new ArrayList<ClassModel>();
|
||||||
|
final private List<MethodModel> methods = new ArrayList<MethodModel>();
|
||||||
|
|
||||||
|
public ClassModel(String name) {
|
||||||
|
super();
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addReference(ClassModel classModel) {
|
||||||
|
references.add(classModel);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addMethod(MethodModel method) {
|
||||||
|
methods.add(method);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<ClassModel> getReferences() {
|
||||||
|
return new ArrayList<ClassModel>(references);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "class " + name;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
final int prime = 31;
|
||||||
|
int result = 1;
|
||||||
|
result = prime * result + ((name == null) ? 0 : name.hashCode());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj)
|
||||||
|
return true;
|
||||||
|
if (obj == null)
|
||||||
|
return false;
|
||||||
|
if (getClass() != obj.getClass())
|
||||||
|
return false;
|
||||||
|
ClassModel other = (ClassModel) obj;
|
||||||
|
if (name == null) {
|
||||||
|
if (other.name != null)
|
||||||
|
return false;
|
||||||
|
} else if (!name.equals(other.name))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
28
src/main/java/yooze/domain/Graph.java
Normal file
28
src/main/java/yooze/domain/Graph.java
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
package yooze.domain;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
|
||||||
|
public class Graph {
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
private final List<ClassModel> classes = new ArrayList<ClassModel>();
|
||||||
|
|
||||||
|
public void add(ClassModel model) {
|
||||||
|
classes.add(model);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<ClassModel> getChildren() {
|
||||||
|
return classes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
32
src/main/java/yooze/domain/MethodCallModel.java
Normal file
32
src/main/java/yooze/domain/MethodCallModel.java
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
package yooze.domain;
|
||||||
|
|
||||||
|
import javassist.NotFoundException;
|
||||||
|
import javassist.expr.MethodCall;
|
||||||
|
import yooze.ClassCache;
|
||||||
|
import yooze.MethodCache;
|
||||||
|
|
||||||
|
public class MethodCallModel {
|
||||||
|
private MethodCall methodCall;
|
||||||
|
|
||||||
|
public MethodCallModel(MethodCall m) {
|
||||||
|
this.methodCall = m;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClassModel getCalledClass() {
|
||||||
|
return ClassCache.get(methodCall.getClassName());
|
||||||
|
}
|
||||||
|
|
||||||
|
public MethodModel getCalledMethod() {
|
||||||
|
try {
|
||||||
|
ParameterList parameterList = ParameterList.create(methodCall.getMethod());
|
||||||
|
return MethodCache.getInstance().get(
|
||||||
|
createQualifiedMethodname(parameterList));
|
||||||
|
} catch (NotFoundException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String createQualifiedMethodname(ParameterList parameterList) {
|
||||||
|
return methodCall.getClassName() + "." + methodCall.getMethodName() + "(" + parameterList.asText() + ")";
|
||||||
|
}
|
||||||
|
}
|
||||||
91
src/main/java/yooze/domain/MethodModel.java
Normal file
91
src/main/java/yooze/domain/MethodModel.java
Normal file
|
|
@ -0,0 +1,91 @@
|
||||||
|
package yooze.domain;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import javassist.CannotCompileException;
|
||||||
|
import javassist.CtMethod;
|
||||||
|
import javassist.expr.ExprEditor;
|
||||||
|
import javassist.expr.MethodCall;
|
||||||
|
import yooze.MethodCache;
|
||||||
|
|
||||||
|
public class MethodModel {
|
||||||
|
private ClassModel containingClass;
|
||||||
|
private String name;
|
||||||
|
private ParameterList parameterList;
|
||||||
|
private final List<MethodCallModel> methodCalls = new ArrayList<MethodCallModel>();
|
||||||
|
private final Set<MethodModel> callers = new HashSet<MethodModel>();
|
||||||
|
|
||||||
|
public static MethodModel create(ClassModel containingClass, CtMethod method) {
|
||||||
|
MethodModel methodModel = new MethodModel(containingClass, method);
|
||||||
|
MethodCache.getInstance().add(methodModel);
|
||||||
|
methodModel.scanSubsequentMethodCalls(method);
|
||||||
|
return methodModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
private MethodModel(ClassModel containingClass, CtMethod method) {
|
||||||
|
this.containingClass = containingClass;
|
||||||
|
name = method.getName();
|
||||||
|
parameterList = ParameterList.create(method);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addCaller(MethodModel method) {
|
||||||
|
callers.add(method);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<MethodModel> getCallers() {
|
||||||
|
return new ArrayList<MethodModel>(callers);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<MethodCallModel> getMethodCalls() {
|
||||||
|
return methodCalls;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void scanSubsequentMethodCalls(CtMethod method) {
|
||||||
|
try {
|
||||||
|
method.instrument(new ExprEditor() {
|
||||||
|
@Override
|
||||||
|
public void edit(MethodCall m) throws CannotCompileException {
|
||||||
|
MethodCallModel methodCallModel = new MethodCallModel(m);
|
||||||
|
methodCalls.add(methodCallModel);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (CannotCompileException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFullname() {
|
||||||
|
return containingClass.getName() + "." + name + "(" + parameterList.asText() + ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return getFullname();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (obj == this) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (obj == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!(obj instanceof MethodModel)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
MethodModel other = (MethodModel) obj;
|
||||||
|
return this.getFullname().equals(other.getFullname());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return getFullname().hashCode();
|
||||||
|
}
|
||||||
|
}
|
||||||
58
src/main/java/yooze/domain/ParameterList.java
Normal file
58
src/main/java/yooze/domain/ParameterList.java
Normal file
|
|
@ -0,0 +1,58 @@
|
||||||
|
package yooze.domain;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import javassist.CtClass;
|
||||||
|
import javassist.CtMethod;
|
||||||
|
import javassist.NotFoundException;
|
||||||
|
|
||||||
|
public class ParameterList {
|
||||||
|
|
||||||
|
private List<ParameterModel> parameters = new ArrayList<ParameterModel>();
|
||||||
|
|
||||||
|
public static ParameterList create(CtMethod method) {
|
||||||
|
ParameterList parameterList = new ParameterList();
|
||||||
|
parameterList.parameters = getParameters(method);
|
||||||
|
return parameterList;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<ParameterModel> getParameters(CtMethod method) {
|
||||||
|
try {
|
||||||
|
List<ParameterModel> parameters = new ArrayList<ParameterModel>();
|
||||||
|
CtClass[] parameterTypes = method.getParameterTypes();
|
||||||
|
for (CtClass parameterType : parameterTypes) {
|
||||||
|
parameters.add(new ParameterModel(parameterType));
|
||||||
|
}
|
||||||
|
return parameters;
|
||||||
|
|
||||||
|
} catch (NotFoundException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String asText() {
|
||||||
|
String parameterText = "";
|
||||||
|
int index = 0;
|
||||||
|
int size = parameters.size();
|
||||||
|
for (ParameterModel parameter : parameters) {
|
||||||
|
parameterText = addType(parameterText, parameter);
|
||||||
|
parameterText = addComma(parameterText, index, size);
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
return parameterText;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String addComma(String parameterText, int i, int size) {
|
||||||
|
if (i < (size - 1)) {
|
||||||
|
parameterText += ", ";
|
||||||
|
}
|
||||||
|
return parameterText;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String addType(String parameterText, ParameterModel parameter) {
|
||||||
|
parameterText += parameter.getType().getName();
|
||||||
|
return parameterText;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
22
src/main/java/yooze/domain/ParameterModel.java
Normal file
22
src/main/java/yooze/domain/ParameterModel.java
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
package yooze.domain;
|
||||||
|
|
||||||
|
import yooze.ClassCache;
|
||||||
|
import javassist.CtClass;
|
||||||
|
|
||||||
|
public class ParameterModel {
|
||||||
|
private ClassModel type;
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
public ParameterModel(CtClass typeAsCtClass) {
|
||||||
|
String classname = typeAsCtClass.getName();
|
||||||
|
type = ClassCache.get(classname);
|
||||||
|
if (type == null) {
|
||||||
|
type = ClassCache.createNewDummyModel(classname);
|
||||||
|
}
|
||||||
|
name = "";// javassist doesn't give me this (?)
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClassModel getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
}
|
||||||
41
src/main/java/yooze/dto/MethodDto.java
Normal file
41
src/main/java/yooze/dto/MethodDto.java
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
package yooze.dto;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import yooze.domain.MethodModel;
|
||||||
|
|
||||||
|
public class MethodDto {
|
||||||
|
private String name;
|
||||||
|
private List<MethodDto> callers = new ArrayList<MethodDto>();
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<MethodDto> getCallers() {
|
||||||
|
return callers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCallers(List<MethodDto> callers) {
|
||||||
|
this.callers = callers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addCaller(MethodDto caller) {
|
||||||
|
callers.add(caller);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MethodDto create(MethodModel startMethod) {
|
||||||
|
MethodDto methodDto = new MethodDto();
|
||||||
|
methodDto.setName(startMethod.getFullname());
|
||||||
|
for (MethodModel caller : startMethod.getCallers()) {
|
||||||
|
methodDto.addCaller(create(caller));
|
||||||
|
}
|
||||||
|
return methodDto;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
48
src/main/java/yooze/etc/ClassBuilder.java
Normal file
48
src/main/java/yooze/etc/ClassBuilder.java
Normal file
|
|
@ -0,0 +1,48 @@
|
||||||
|
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;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
89
src/main/java/yooze/etc/Neo4jDao.java
Normal file
89
src/main/java/yooze/etc/Neo4jDao.java
Normal file
|
|
@ -0,0 +1,89 @@
|
||||||
|
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
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
41
src/main/java/yooze/etc/Yooze.java
Normal file
41
src/main/java/yooze/etc/Yooze.java
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
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];
|
||||||
|
new Yooze(neoDb).createNeoGraph(earfile, in,ex);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public Yooze(String neo4jDb) {
|
||||||
|
super();
|
||||||
|
this.neo4jDb = neo4jDb;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void createNeoGraph(String archive, String packageIncludePatterns, String packageExcludePatterns)
|
||||||
|
throws IOException{
|
||||||
|
GraphBuilder libDirectoryBuilder = GraphBuilder.getLibDirectoryBuilder();
|
||||||
|
libDirectoryBuilder.setPackageExcludePatterns(packageExcludePatterns);
|
||||||
|
libDirectoryBuilder.setPackageIncludePatterns(packageIncludePatterns);
|
||||||
|
|
||||||
|
Graph graph = libDirectoryBuilder.build(archive);
|
||||||
|
|
||||||
|
Neo4jDao neo4jDao = new Neo4jDao(neo4jDb);
|
||||||
|
for (ClassModel model:graph.getChildren()){
|
||||||
|
neo4jDao.insertClass(model);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
192
src/main/java/yooze/scanner/ArchiveScanner.java
Normal file
192
src/main/java/yooze/scanner/ArchiveScanner.java
Normal file
|
|
@ -0,0 +1,192 @@
|
||||||
|
package yooze.scanner;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Enumeration;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.jar.JarEntry;
|
||||||
|
import java.util.jar.JarFile;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
import java.util.zip.ZipEntry;
|
||||||
|
|
||||||
|
import javassist.ClassPath;
|
||||||
|
|
||||||
|
import org.apache.commons.io.IOUtils;
|
||||||
|
|
||||||
|
import yooze.DirClassPath;
|
||||||
|
import yooze.JarClassPath;
|
||||||
|
import yooze.Util;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author shautvast TODO separate models for wars
|
||||||
|
*/
|
||||||
|
public class ArchiveScanner implements Scanner {
|
||||||
|
private final static Pattern classPattern = Pattern.compile("WEB-INF/classes/(.*)\\.class");
|
||||||
|
private final static Pattern packagePattern = Pattern.compile("(.+\\/+)(.+\\.class)");
|
||||||
|
|
||||||
|
public List<ClassPath> scanArchive(String archiveName) throws IOException {
|
||||||
|
return scanArchive(new File(archiveName));
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<ClassPath> scanArchive(File archiveFile) throws IOException {
|
||||||
|
List<ClassPath> result = new ArrayList<ClassPath>();
|
||||||
|
if (!archiveFile.exists()) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (archiveFile.isDirectory()) {
|
||||||
|
File[] list = archiveFile.listFiles();
|
||||||
|
for (File entry : list) {
|
||||||
|
if (entry.getName().endsWith(".jar")) {
|
||||||
|
result.add(new JarClassPath(new JarFile(entry)));
|
||||||
|
} else if (entry.getName().endsWith(".class")) {
|
||||||
|
result.add(new DirClassPath(archiveFile));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
JarFile archive = new JarFile(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 {
|
||||||
|
addToClasspath(warfile, classpaths, entry);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
} 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) {
|
||||||
|
List<JarFile> wars = new ArrayList<JarFile>();
|
||||||
|
for (Enumeration<JarEntry> entries = earfile.entries(); entries.hasMoreElements();) {
|
||||||
|
JarEntry entry = (JarEntry) entries.nextElement();
|
||||||
|
if (isWarfile(entry)) {
|
||||||
|
try {
|
||||||
|
File warFile = Util.extractFile(earfile, entry);
|
||||||
|
wars.add(new JarFile(warFile));
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return wars;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isWarfile(JarEntry entry) {
|
||||||
|
return entry.getName().endsWith(".war");
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<ClassPath> scanRoot(JarFile earfile) {
|
||||||
|
List<ClassPath> classpaths = new ArrayList<ClassPath>();
|
||||||
|
for (Enumeration<JarEntry> entries = earfile.entries(); entries.hasMoreElements();) {
|
||||||
|
JarEntry entry = (JarEntry) entries.nextElement();
|
||||||
|
if (isJarfile(entry)) {
|
||||||
|
try {
|
||||||
|
addToClasspath(earfile, classpaths, entry);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return classpaths;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isJarfile(JarEntry entry) {
|
||||||
|
return entry.getName().endsWith(".jar");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
47
src/main/java/yooze/scanner/LibScanner.java
Normal file
47
src/main/java/yooze/scanner/LibScanner.java
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
package yooze.scanner;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.jar.JarFile;
|
||||||
|
|
||||||
|
import yooze.JarClassPath;
|
||||||
|
|
||||||
|
import javassist.ClassPath;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scans a directory ("lib") recursively for jarfiles and adds them to the
|
||||||
|
* classpath
|
||||||
|
*
|
||||||
|
* @author sander
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class LibScanner 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> classpaths = new ArrayList<ClassPath>();
|
||||||
|
return doScanArchive(classpaths,file);
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<ClassPath> doScanArchive(List<ClassPath> classpaths, File file)
|
||||||
|
throws IOException {
|
||||||
|
|
||||||
|
File[] entries = file.listFiles();
|
||||||
|
for (File entry : entries) {
|
||||||
|
if (entry.isDirectory()) {
|
||||||
|
doScanArchive(classpaths, entry);
|
||||||
|
} else if (entry.getName().endsWith(".jar")) {
|
||||||
|
classpaths.add(new JarClassPath(new JarFile(entry)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return classpaths;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
13
src/main/java/yooze/scanner/Scanner.java
Normal file
13
src/main/java/yooze/scanner/Scanner.java
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
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;
|
||||||
|
}
|
||||||
65
src/main/java/yooze/scanner/TgzScanner.java
Normal file
65
src/main/java/yooze/scanner/TgzScanner.java
Normal file
|
|
@ -0,0 +1,65 @@
|
||||||
|
package yooze.scanner;
|
||||||
|
|
||||||
|
import java.io.BufferedInputStream;
|
||||||
|
import java.io.BufferedOutputStream;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.jar.JarFile;
|
||||||
|
import java.util.zip.GZIPInputStream;
|
||||||
|
|
||||||
|
import javassist.ClassPath;
|
||||||
|
|
||||||
|
import org.xeustechnologies.jtar.TarEntry;
|
||||||
|
import org.xeustechnologies.jtar.TarInputStream;
|
||||||
|
|
||||||
|
import yooze.JarClassPath;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author sander
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class TgzScanner implements Scanner {
|
||||||
|
public List<ClassPath> scanArchive(String archiveName) throws IOException {
|
||||||
|
return scanArchive(new File(archiveName));
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<ClassPath> scanArchive(File file) throws IOException {
|
||||||
|
List<ClassPath> classpaths = new ArrayList<ClassPath>();
|
||||||
|
TarInputStream tarInputStream = new TarInputStream(new GZIPInputStream(
|
||||||
|
new BufferedInputStream(new FileInputStream(file))));
|
||||||
|
TarEntry entry;
|
||||||
|
while ((entry = tarInputStream.getNextEntry()) != null) {
|
||||||
|
if (entry.getName().endsWith(".jar")) {
|
||||||
|
int count;
|
||||||
|
byte data[] = new byte[2048];
|
||||||
|
|
||||||
|
File tempFile = File.createTempFile(
|
||||||
|
singleName(entry.getName()), ".jar");
|
||||||
|
FileOutputStream fos = new FileOutputStream(tempFile);
|
||||||
|
BufferedOutputStream dest = new BufferedOutputStream(fos);
|
||||||
|
|
||||||
|
while ((count = tarInputStream.read(data)) != -1) {
|
||||||
|
dest.write(data, 0, count);
|
||||||
|
}
|
||||||
|
dest.flush();
|
||||||
|
dest.close();
|
||||||
|
classpaths.add(new JarClassPath(new JarFile(tempFile)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tarInputStream.close();
|
||||||
|
return classpaths;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String singleName(String name) {
|
||||||
|
int slash = name.lastIndexOf("/");
|
||||||
|
if (slash > -1) {
|
||||||
|
return name.substring(slash + 1);
|
||||||
|
} else {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
22
src/test/java/yooze/AssTest.java
Normal file
22
src/test/java/yooze/AssTest.java
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
26
src/test/java/yooze/Config.java
Normal file
26
src/test/java/yooze/Config.java
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
package yooze;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
public class Config {
|
||||||
|
private File earFile;
|
||||||
|
private File tgzFile;
|
||||||
|
|
||||||
|
public void setEarFile(File earFile) {
|
||||||
|
this.earFile = earFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
public File getEarFile() {
|
||||||
|
return earFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
public File getTgzFile() {
|
||||||
|
return tgzFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTgzFile(File tgzFile) {
|
||||||
|
this.tgzFile = tgzFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
64
src/test/java/yooze/DotPrinterTest.java
Normal file
64
src/test/java/yooze/DotPrinterTest.java
Normal file
|
|
@ -0,0 +1,64 @@
|
||||||
|
package yooze;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
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 {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void dotPrinting() throws IOException {
|
||||||
|
GraphBuilder directoryBuilder = GraphBuilder.getClassesDirectoryBuilder();
|
||||||
|
directoryBuilder.setPackageExcludePatterns(".*?Class4");
|
||||||
|
directoryBuilder.setPackageIncludePatterns(".*?.Class.");
|
||||||
|
Graph graph = directoryBuilder.build("target/test-classes");
|
||||||
|
|
||||||
|
ByteArrayOutputStream bytes = new ByteArrayOutputStream(500);
|
||||||
|
DotPrinter d = new DotPrinter(bytes);
|
||||||
|
d.print(graph);
|
||||||
|
String dotText = new String(bytes.toByteArray());
|
||||||
|
d.close();
|
||||||
|
String expectedDotText = "digraph \"test-classes\" {\r\n" //
|
||||||
|
+ "graph [size=100,100];\r\n"
|
||||||
|
+ "\"yooze.Class1\" [shape=box, height=0.0];\r\n" //
|
||||||
|
+ "\"yooze.Class1\" -> \"yooze.Class2\"\r\n"
|
||||||
|
+ "\"yooze.Class2\" [shape=box, height=0.0];\r\n"
|
||||||
|
+ "\"yooze.Class2\" -> \"yooze.Class3\"\r\n"
|
||||||
|
+ "\"yooze.Class3\" [shape=box, height=0.0];\r\n"
|
||||||
|
+ "\"yooze.Class3\" -> \"yooze.Class1\"\r\n"
|
||||||
|
+ "\"yooze.Class1\" [shape=box, height=0.0];\r\n"
|
||||||
|
+ "\"yooze.Class2\" [shape=box, height=0.0];\r\n" //
|
||||||
|
+ "\"yooze.Class3\" [shape=box, height=0.0];\r\n" + "}\r\n";
|
||||||
|
|
||||||
|
assertEquals(expectedDotText, dotText);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void noReference() throws IOException {
|
||||||
|
GraphBuilder directoryBuilder = GraphBuilder.getClassesDirectoryBuilder();
|
||||||
|
directoryBuilder.setPackageExcludePatterns("");
|
||||||
|
directoryBuilder.setPackageIncludePatterns("yooze.Class4");
|
||||||
|
Graph graph = directoryBuilder.build("target/test-classes");
|
||||||
|
ByteArrayOutputStream bytes = new ByteArrayOutputStream(1000);
|
||||||
|
DotPrinter d = new DotPrinter(bytes);
|
||||||
|
d.print(graph);
|
||||||
|
String dotText = new String(bytes.toByteArray());
|
||||||
|
String expectedDotText = "digraph \"test-classes\" {\r\n" //
|
||||||
|
+ "graph [size=100,100];\r\n"//
|
||||||
|
+ "\"yooze.Class4\" [shape=box, height=0.0];\r\n" //
|
||||||
|
+ "\"yooze.Class4\";\r\n" //
|
||||||
|
+ "}\r\n";
|
||||||
|
d.close();
|
||||||
|
assertEquals(expectedDotText, dotText);
|
||||||
|
}
|
||||||
|
}
|
||||||
50
src/test/java/yooze/EarScannerTest.java
Normal file
50
src/test/java/yooze/EarScannerTest.java
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
40
src/test/java/yooze/GraphTest.java
Normal file
40
src/test/java/yooze/GraphTest.java
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
package yooze;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
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.ClassModel;
|
||||||
|
import yooze.domain.Graph;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
@RunWith(SpringJUnit4ClassRunner.class)
|
||||||
|
@ContextConfiguration(locations = "classpath:applicationContext-test.xml")
|
||||||
|
public class GraphTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void buildGraph() throws IOException{
|
||||||
|
// new Yooze("/tmp/test").createNeoGraph("target/test-classes", ".*?.Class.");
|
||||||
|
GraphBuilder libDirectoryBuilder = GraphBuilder.getLibDirectoryBuilder();
|
||||||
|
libDirectoryBuilder.setPackageIncludePatterns(".*?.Class.");
|
||||||
|
libDirectoryBuilder.setPackageExcludePatterns("");
|
||||||
|
Graph graph = libDirectoryBuilder.build("target/test-classes");
|
||||||
|
ClassModel class1=graph.getChildren().get(0);
|
||||||
|
|
||||||
|
assertTrue(class1!=null);
|
||||||
|
ClassModel class2Dummy=new ClassModel("yooze.Class2");
|
||||||
|
assertTrue(class1.getReferences().contains(class2Dummy));
|
||||||
|
|
||||||
|
ClassModel class2=class1.getReferences().get(0);
|
||||||
|
assertTrue (class2.getName().equals("yooze.Class2"));
|
||||||
|
ClassModel class3=class2.getReferences().get(0);
|
||||||
|
assertTrue (class3.getName().equals("yooze.Class3"));
|
||||||
|
|
||||||
|
assertTrue(class2.getReferences().contains(class3));
|
||||||
|
assertTrue(class3.getReferences().contains(class1));
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
40
src/test/java/yooze/LargePackageTest.java
Normal file
40
src/test/java/yooze/LargePackageTest.java
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
package yooze;
|
||||||
|
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
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.domain.Graph;
|
||||||
|
|
||||||
|
@RunWith(SpringJUnit4ClassRunner.class)
|
||||||
|
@ContextConfiguration(locations = "classpath:applicationContext-test.xml")
|
||||||
|
public class LargePackageTest {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private Config config;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void largePackage() throws IOException{
|
||||||
|
GraphBuilder earBuilder = GraphBuilder.getEarBuilder();
|
||||||
|
earBuilder.setPackageIncludePatterns("");
|
||||||
|
earBuilder.setPackageExcludePatterns("java.*");
|
||||||
|
Graph graph = earBuilder.buildClassDepencyGraph(config.getEarFile());
|
||||||
|
new DotPrinter(new FileOutputStream("/tmp/example.dot")).print(graph);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public Config getConfig() {
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setConfig(Config config) {
|
||||||
|
this.config = config;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
40
src/test/java/yooze/MethodReferencesTest.java
Normal file
40
src/test/java/yooze/MethodReferencesTest.java
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
package yooze;
|
||||||
|
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import junit.framework.Assert;
|
||||||
|
|
||||||
|
import org.codehaus.jackson.JsonGenerator;
|
||||||
|
import org.codehaus.jackson.map.ObjectMapper;
|
||||||
|
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;
|
||||||
|
import yooze.domain.MethodModel;
|
||||||
|
import yooze.dto.MethodDto;
|
||||||
|
|
||||||
|
@RunWith(SpringJUnit4ClassRunner.class)
|
||||||
|
@ContextConfiguration(locations = "classpath:applicationContext-test.xml")
|
||||||
|
public class MethodReferencesTest {
|
||||||
|
@Test
|
||||||
|
public void test() throws IOException {
|
||||||
|
GraphBuilder directoryBuilder = GraphBuilder.getClassesDirectoryBuilder();
|
||||||
|
directoryBuilder.setPackageIncludePatterns("yooze.Class.*");
|
||||||
|
Graph graph = directoryBuilder.build("target/test-classes");
|
||||||
|
MethodModel mm1 = MethodCache.getInstance().get("yooze.Class1.rup(int)");
|
||||||
|
Assert.assertNotNull(mm1);
|
||||||
|
MethodModel mm2 = MethodCache.getInstance().get("yooze.Class3.dof()");
|
||||||
|
Assert.assertNotNull(mm2);
|
||||||
|
List<MethodModel> callers = mm1.getCallers();
|
||||||
|
Assert.assertTrue(callers.contains(mm2));
|
||||||
|
MethodDto dto = MethodDto.create(MethodCache.getInstance().get("yooze.Class1.zoef(yooze.Class2)"));
|
||||||
|
JsonGenerator jg = new ObjectMapper().getJsonFactory().createJsonGenerator(
|
||||||
|
new FileOutputStream("c:\\ff\\out.json"));
|
||||||
|
jg.writeObject(dto);
|
||||||
|
jg.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
52
src/test/java/yooze/TgzBuilderTest.java
Normal file
52
src/test/java/yooze/TgzBuilderTest.java
Normal file
|
|
@ -0,0 +1,52 @@
|
||||||
|
package yooze;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
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.domain.ClassModel;
|
||||||
|
import yooze.domain.Graph;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
@RunWith(SpringJUnit4ClassRunner.class)
|
||||||
|
@ContextConfiguration(locations = "classpath:applicationContext-test.xml")
|
||||||
|
public class TgzBuilderTest {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private Config config;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void tgzBuilder() throws IOException {
|
||||||
|
GraphBuilder tgzBuilder = GraphBuilder.getDefaultTgzBuilder();
|
||||||
|
tgzBuilder.setPackageIncludePatterns("nl.*");
|
||||||
|
tgzBuilder.setPackageExcludePatterns("");
|
||||||
|
Graph graph = tgzBuilder.buildClassDepencyGraph(config.getTgzFile());
|
||||||
|
|
||||||
|
ArrayList<String> names = new ArrayList<String>();
|
||||||
|
|
||||||
|
for (ClassModel cm : graph.getChildren()) {
|
||||||
|
names.add(cm.getName());
|
||||||
|
}
|
||||||
|
assertTrue(names.contains("nl.jssl.jas.Main"));
|
||||||
|
assertTrue(names.contains("nl.jssl.jas.agent.Agent"));
|
||||||
|
assertTrue(names
|
||||||
|
.contains("nl.jssl.jas.instrumentation.ClassTransformer"));
|
||||||
|
assertTrue(names
|
||||||
|
.contains("nl.jssl.jas.instrumentation.JavassistInstrumenter"));
|
||||||
|
assertTrue(names.contains("nl.jssl.jas.measurement.Measurement"));
|
||||||
|
assertTrue(names.contains("nl.jssl.jas.measurement.Stopwatch"));
|
||||||
|
assertTrue(names.contains("nl.jssl.testjas.TestClass"));
|
||||||
|
assertTrue(names.contains("nl.jssl.testjas.Instrument"));
|
||||||
|
assertTrue(names.contains("nl.jssl.testjas.AgentTest"));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setConfig(Config config) {
|
||||||
|
this.config = config;
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
src/test/resources/.DS_Store
vendored
Normal file
BIN
src/test/resources/.DS_Store
vendored
Normal file
Binary file not shown.
BIN
src/test/resources/._.DS_Store
Normal file
BIN
src/test/resources/._.DS_Store
Normal file
Binary file not shown.
BIN
src/test/resources/agent.tar.gz
Normal file
BIN
src/test/resources/agent.tar.gz
Normal file
Binary file not shown.
9
src/test/resources/applicationContext-test.xml
Normal file
9
src/test/resources/applicationContext-test.xml
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
|
||||||
|
<bean id="config" class="yooze.Config">
|
||||||
|
<property name="earFile" value="classpath:examples.ear"></property>
|
||||||
|
<property name="tgzFile" value="classpath:agent.tar.gz"></property>
|
||||||
|
</bean>
|
||||||
|
</beans>
|
||||||
BIN
src/test/resources/examples.ear
Normal file
BIN
src/test/resources/examples.ear
Normal file
Binary file not shown.
BIN
src/test/resources/examples.war
Normal file
BIN
src/test/resources/examples.war
Normal file
Binary file not shown.
12
src/test/resources/logback.xml
Normal file
12
src/test/resources/logback.xml
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
<configuration>
|
||||||
|
|
||||||
|
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||||
|
<layout class="ch.qos.logback.classic.PatternLayout">
|
||||||
|
<Pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</Pattern>
|
||||||
|
</layout>
|
||||||
|
</appender>
|
||||||
|
|
||||||
|
<root level="DEBUG">
|
||||||
|
<appender-ref ref="STDOUT" />
|
||||||
|
</root>
|
||||||
|
</configuration>
|
||||||
15
src/testdummies/java/yooze/Class1.java
Normal file
15
src/testdummies/java/yooze/Class1.java
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
package yooze;
|
||||||
|
|
||||||
|
public class Class1 {
|
||||||
|
Class2 class2;
|
||||||
|
|
||||||
|
public void rup(int k) {
|
||||||
|
System.out.println(k);
|
||||||
|
class2.annoy();
|
||||||
|
zoef(class2);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void zoef(Class2 envy) {
|
||||||
|
System.out.println(envy);
|
||||||
|
}
|
||||||
|
}
|
||||||
10
src/testdummies/java/yooze/Class2.java
Normal file
10
src/testdummies/java/yooze/Class2.java
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
package yooze;
|
||||||
|
|
||||||
|
public class Class2 {
|
||||||
|
public static Class3 class3=new Class3();
|
||||||
|
|
||||||
|
public void annoy() {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
14
src/testdummies/java/yooze/Class3.java
Normal file
14
src/testdummies/java/yooze/Class3.java
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
package yooze;
|
||||||
|
|
||||||
|
public class Class3 {
|
||||||
|
public static Class1 class1 = new Class1();
|
||||||
|
|
||||||
|
public static void annoyStatic() {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void dof() {
|
||||||
|
class1.rup(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
8
src/testdummies/java/yooze/Class4.java
Normal file
8
src/testdummies/java/yooze/Class4.java
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
package yooze;
|
||||||
|
|
||||||
|
public class Class4 {
|
||||||
|
|
||||||
|
public void fla() {
|
||||||
|
new Class3().dof();
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Reference in a new issue