Skip to content

Commit

Permalink
type hierarchy construction method added
Browse files Browse the repository at this point in the history
  • Loading branch information
jachiaram committed Aug 7, 2024
1 parent 7229abf commit 45c1075
Show file tree
Hide file tree
Showing 7 changed files with 416 additions and 2 deletions.
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

0 comments on commit 45c1075

Please sign in to comment.