Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BuildTypeHierarchy #8

Merged
merged 1 commit into from
Aug 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion src/main/java/org/tudo/sse/Main.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,16 @@
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.tudo.sse.model.Artifact;
import org.tudo.sse.resolution.PomResolutionException;
import org.tudo.sse.model.ArtifactIdent;
import org.tudo.sse.model.jar.ClassFileNode;
import org.tudo.sse.model.jar.FoundInfoNode;
import org.tudo.sse.resolution.*;
import org.tudo.sse.utils.GAUtils;

import java.io.IOException;
import java.net.URISyntaxException;
import java.util.List;
import java.util.Map;

public class Main {

Expand Down
146 changes: 145 additions & 1 deletion src/main/java/org/tudo/sse/model/Artifact.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,18 @@
package org.tudo.sse.model;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.tudo.sse.Main;
import org.tudo.sse.model.index.IndexInformation;
import org.tudo.sse.model.jar.JarInformation;
import org.tudo.sse.model.jar.*;
import org.tudo.sse.model.pom.PomInformation;
import org.tudo.sse.resolution.JarResolutionException;
import org.tudo.sse.resolution.JarResolver;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
* This class holds all the artifact information. For each artifact index, jar, and pom information can be defined.
Expand All @@ -13,6 +23,8 @@ public class Artifact {
* The identifier object for the artifact.
*/
public final ArtifactIdent ident;
public static final Logger log = LogManager.getLogger(Artifact.class);

/**
* A secondary identifier, for if its pom information has been moved on the maven central repository.
*/
Expand Down Expand Up @@ -75,4 +87,136 @@ public void setJarInformation(JarInformation jarInformation) {
this.jarInformation = jarInformation;
}


public Map<String, ClassFileNode> buildTypeStructure() {
Map<String, ClassFileNode> roots = new HashMap<>();
roots.put("java/lang/Object", new NotFoundNode(new ObjType(0, "java/lang/Object", "java/lang")));
if(jarInformation != null) {
Map<String, List<ClassFile>> packages = jarInformation.getPackages();
Map<String, Artifact> depArts = new HashMap<>();

if(pomInformation != null) {
JarResolver resolver = new JarResolver();
for(Artifact artifact : pomInformation.getEffectiveTransitiveDependencies()) {
try {
artifact.setJarInformation(resolver.parseJar(artifact.getIdent()).getJarInformation());
depArts.put(artifact.getIdent().getGroupID() + ":" + artifact.getIdent().getArtifactID(), artifact);
} catch (JarResolutionException e) {
log.error(e);
}
}
}

for(Map.Entry<String, List<ClassFile>> classes : packages.entrySet()) {
for(ClassFile clase : classes.getValue()) {
resolveNode(roots, clase, packages, depArts);
}
}
}
return roots;
}

private ClassFileNode resolveNode(Map<String, ClassFileNode> root, ClassFile clase, Map<String, List<ClassFile>> packages, Map<String, Artifact> depArts) {
ClassFileNode node = new FoundInfoNode(clase.getAccessFlags(), clase.getThistype(), clase.getVersion());

if(clase.getSuperType() != null) {
resolveSuperClass(root, node, clase, packages, depArts);
}

if(!clase.getInterfaceTypes().isEmpty()) {
resolveInterfaces(root, node, clase, packages, depArts);
}

return node;
}

private void resolveSuperClass(Map<String, ClassFileNode> roots, ClassFileNode node, ClassFile clase, Map<String, List<ClassFile>> packages, Map<String, Artifact> depArts) {
String packName = clase.getSuperType().getPackageName();

//Check if the superclass can be found in the root map
if(roots.containsKey(clase.getSuperType().getFqn())) {
node.setSuperClass(roots.get(clase.getSuperType().getFqn()));
roots.get(clase.getSuperType().getFqn()).addChild(node);
}
//Check if
else if(packages.containsKey(packName)) {
List<ClassFile> toLookThrough = packages.get(packName);
for(ClassFile cls : toLookThrough) {
if(cls.getThistype().getFqn().equals(clase.getSuperType().getFqn())) {
node.setSuperClass(resolveNode(roots, cls, packages, depArts));
node.getSuperClass().addChild(node);
break;
}
}
} else {
boolean found = false;

for(Map.Entry<String, Artifact> entry : depArts.entrySet()) {
if(entry.getValue().getJarInformation().getPackages().containsKey(packName)) {
for(ClassFile depClass : entry.getValue().getJarInformation().getPackages().get(packName)) {
if(depClass.getThistype().getFqn().equals(clase.getSuperType().getFqn())) {
found = true;
node.setSuperClass(resolveNode(roots, depClass, entry.getValue().getJarInformation().getPackages(), depArts));
node.getSuperClass().addChild(node);
break;
}
}
if(found) {
break;
}
}
}

//add a new root to the map
if(!found) {
node.setSuperClass(new NotFoundNode(clase.getSuperType()));
node.getSuperClass().addChild(node);
roots.put(node.getSuperClass().getThistype().getFqn(), node.getSuperClass());
}
}
}

private void resolveInterfaces(Map<String, ClassFileNode> roots, ClassFileNode node, ClassFile clase, Map<String, List<ClassFile>> packages, Map<String, Artifact> depArts) {
for(ObjType itfe : clase.getInterfaceTypes()) {
String packName = itfe.getPackageName();

if(packages.containsKey(packName)) {
List<ClassFile> toLookThrough = packages.get(packName);
for(ClassFile cls : toLookThrough) {
if(cls.getThistype().getFqn().equals(itfe.getFqn())) {
ClassFileNode resolved = resolveNode(roots, cls, packages, depArts);
resolved.addChild(node);
((FoundInfoNode) node).addInterfaceNode(resolved);
break;
}
}
} else {
boolean found = false;

for(Map.Entry<String, Artifact> entry : depArts.entrySet()) {
if(entry.getValue().getJarInformation().getPackages().containsKey(packName)) {
for(ClassFile depClass : entry.getValue().getJarInformation().getPackages().get(packName)) {
if(depClass.getThistype().getFqn().equals(itfe.getFqn())) {
found = true;
ClassFileNode resolved = resolveNode(roots, depClass, entry.getValue().getJarInformation().getPackages(), depArts);
resolved.addChild(node);
((FoundInfoNode) node).addInterfaceNode(resolved);
break;
}
}
if(found) {
break;
}
}
}

if(!found) {
ClassFileNode notFound = new NotFoundNode(itfe);
((FoundInfoNode) node).addInterfaceNode(notFound);
notFound.addChild(node);
}
}
}
}

}
35 changes: 35 additions & 0 deletions src/main/java/org/tudo/sse/model/jar/ClassFileNode.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package org.tudo.sse.model.jar;

import java.util.ArrayList;
import java.util.List;

public class ClassFileNode {
private final ObjType thistype;
private ClassFileNode superclass;
private List<ClassFileNode> children;

public ClassFileNode(ObjType thistype) {
this.thistype = thistype;
children = new ArrayList<>();
}

public ClassFileNode getSuperClass() {
return superclass;
}

public void setSuperClass(ClassFileNode superclass) {
this.superclass = superclass;
}

public ObjType getThistype() {
return thistype;
}

public List<ClassFileNode> getChildren() {
return children;
}

public void addChild(ClassFileNode child) {
children.add(child);
}
}
34 changes: 34 additions & 0 deletions src/main/java/org/tudo/sse/model/jar/FoundInfoNode.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package org.tudo.sse.model.jar;

import java.util.ArrayList;
import java.util.List;

public class FoundInfoNode extends ClassFileNode {
private final int accessFlags;
private final long version;
private List<ClassFileNode> interfaceNodes;


public FoundInfoNode(int accessFlags, ObjType thisType, long version) {
super(thisType);
this.accessFlags = accessFlags;
this.version = version;
interfaceNodes = new ArrayList<>();
}

public int getAccessFlags() {
return accessFlags;
}

public long getVersion() {
return version;
}

public List<ClassFileNode> getInterfaceNodes() {
return interfaceNodes;
}

public void addInterfaceNode(ClassFileNode interfaceNode) {
interfaceNodes.add(interfaceNode);
}
}
8 changes: 8 additions & 0 deletions src/main/java/org/tudo/sse/model/jar/NotFoundNode.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package org.tudo.sse.model.jar;

public class NotFoundNode extends ClassFileNode {

public NotFoundNode(ObjType thistype) {
super(thistype);
}
}
122 changes: 122 additions & 0 deletions src/test/java/org/tudo/sse/model/TypeStructureTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
package org.tudo.sse.model;

import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.junit.jupiter.api.Test;
import org.tudo.sse.ArtifactFactory;
import org.tudo.sse.model.jar.ClassFileNode;
import org.tudo.sse.model.jar.FoundInfoNode;
import org.tudo.sse.resolution.*;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.List;
import java.util.Map;

import static org.junit.jupiter.api.Assertions.assertEquals;


class TypeStructureTest {

JarResolver resolver = new JarResolver();
PomResolver pomResolver = new PomResolver(true);
Map<String, Object> json;
Gson gson = new Gson();

private static final Logger log = LogManager.getLogger(TypeStructureTest.class);

{
InputStream resource = this.getClass().getClassLoader().getResourceAsStream("TypeStructure.json");
assert resource != null;
Reader targetReader = new InputStreamReader(resource);
json = gson.fromJson(targetReader, new TypeToken<Map<String, Object>>() {}.getType());
}

@Test
void buildTypeStructure() {

Artifact jarArt1;
ArtifactIdent ident = new ArtifactIdent("org.springframework", "spring-web", "6.1.11");
Artifact jarArt2;
jarArt2 = ArtifactFactory.getArtifact(ident);
try {
jarArt1 = resolver.parseJar(new ArtifactIdent("org.bouncycastle", "bcpg-lts8on", "2.73.6"));
jarArt2 = resolver.parseJar(ident);
pomResolver.resolveArtifact(ident);
} catch (JarResolutionException | PomResolutionException | FileNotFoundException | IOException e) {
throw new RuntimeException(e);
}

ClassFileNode results1 = jarArt1.buildTypeStructure().get("java/lang/Object");
Map<String, Object> expected1 = (Map<String, Object>) json.get("artifact1");

singleChild(results1, (Map<String, Object>) expected1.get("test1"));
interfacesCheck(results1, (Map<String, Object>) expected1.get("test2"));
interfacesCheck(results1, (Map<String, Object>) expected1.get("test3"));

Map<String, ClassFileNode> results2 = jarArt2.buildTypeStructure();
Map<String, Object> expected2 = (Map<String, Object>) json.get("artifact2");


multipleChildren(results2.get("reactor/core/observability/DefaultSignalListener"), (Map<String, Object>) expected2.get("test1"));
multiLevelChild(results2.get("java/lang/RuntimeException"), (Map<String, Object>) expected2.get("test2"));
interfacesCheck(results2.get("java/lang/Object"), (Map<String, Object>) expected2.get("test3"));

}

ClassFileNode findNode(ClassFileNode root, String toFind) {

for(ClassFileNode cur : root.getChildren()) {
if(cur.getThistype().getFqn().equals(toFind)) {
return cur;
}
}

throw new RuntimeException("Didn't find expected node");
}

void singleChild(ClassFileNode root, Map<String, Object> expected) {
ClassFileNode toTest = findNode(root, (String) expected.get("name"));
Map<String, Object> child = (Map<String, Object>) expected.get("child");
assert(toTest.getChildren().get(0).getThistype().getFqn().equals((String) child.get("name")));
}

void interfacesCheck(ClassFileNode root, Map<String, Object> expected) {
ClassFileNode toTest = findNode(root, (String) expected.get("name"));

List<Map<String, String>> expectedInterfaces = (List<Map<String, String>>) expected.get("interfaces");
List<ClassFileNode> interfaces = ((FoundInfoNode) toTest).getInterfaceNodes();

assertEquals(interfaces.size(), expectedInterfaces.size());

for(int i = 0; i < interfaces.size(); i++) {
assertEquals(interfaces.get(i).getThistype().getFqn(), expectedInterfaces.get(i).get("name"));
assertEquals(((FoundInfoNode) interfaces.get(i)).getSuperClass().getThistype().getFqn(), expectedInterfaces.get(i).get("super"));
}
}

void multipleChildren(ClassFileNode root, Map<String, Object> expected) {
assertEquals(root.getThistype().getFqn(), expected.get("name"));

List<Map<String, String>> children = (List<Map<String, String>>) expected.get("children");
assertEquals(root.getChildren().size(), children.size());

for(int i = 0; i < root.getChildren().size(); i++) {
assertEquals(children.get(i).get("name"), root.getChildren().get(i).getThistype().getFqn());
}
log.info("Got here");
}

void multiLevelChild(ClassFileNode root, Map<String, Object> expected) {
assertEquals(root.getThistype().getFqn(), expected.get("name"));
List<Map<String, Object>> children = (List<Map<String, Object>>) expected.get("children");
assertEquals(root.getChildren().get(0).getThistype().getFqn(), children.get(0).get("name"));
List<Map<String, String>> secondLevel = (List<Map<String, String>>) children.get(0).get("children");
assertEquals(root.getChildren().get(0).getChildren().get(0).getThistype().getFqn(), secondLevel.get(0).get("name"));
}

}
Loading
Loading