package io.lumify.javaCodeIngest;
import io.lumify.core.ingest.graphProperty.GraphPropertyWorkData;
import io.lumify.core.ingest.graphProperty.GraphPropertyWorker;
import io.lumify.core.model.properties.LumifyProperties;
import org.apache.bcel.classfile.ClassParser;
import org.apache.bcel.classfile.Field;
import org.apache.bcel.classfile.JavaClass;
import org.apache.bcel.classfile.Method;
import org.apache.bcel.generic.*;
import org.securegraph.*;
import java.io.InputStream;
import static org.securegraph.util.IterableUtils.singleOrDefault;
public class ClassFileGraphPropertyWorker extends GraphPropertyWorker {
@Override
public void execute(InputStream in, GraphPropertyWorkData data) throws Exception {
LumifyProperties.MIME_TYPE.setProperty(data.getElement(), "application/x-java-class", data.createPropertyMetadata(), data.getVisibility(), getAuthorizations());
Vertex jarVertex = singleOrDefault(((Vertex) data.getElement()).getVertices(Direction.BOTH, Ontology.EDGE_LABEL_JAR_CONTAINS, getAuthorizations()), null);
String fileName = LumifyProperties.FILE_NAME.getPropertyValue(data.getElement());
JavaClass javaClass = new ClassParser(in, fileName).parse();
ConstantPoolGen constants = new ConstantPoolGen(javaClass.getConstantPool());
Vertex classVertex = createClassVertex(javaClass, data);
if (jarVertex != null) {
getGraph().addEdge(jarVertex, classVertex, Ontology.EDGE_LABEL_JAR_CONTAINS, data.getProperty().getVisibility(), getAuthorizations());
}
for (Method method : javaClass.getMethods()) {
createMethodVertex(method, classVertex, javaClass, constants, data);
}
for (Field field : javaClass.getFields()) {
createFieldVertex(field, classVertex, javaClass, data);
}
getGraph().flush();
}
private Vertex createClassVertex(JavaClass javaClass, GraphPropertyWorkData data) {
String className = javaClass.getClassName();
VertexBuilder classVertexBuilder = createClassVertexBuilder(className, data);
if (javaClass.isInterface()) {
LumifyProperties.CONCEPT_TYPE.setProperty(classVertexBuilder, Ontology.CONCEPT_TYPE_INTERFACE, data.getProperty().getVisibility());
} else {
LumifyProperties.CONCEPT_TYPE.setProperty(classVertexBuilder, Ontology.CONCEPT_TYPE_CLASS, data.getProperty().getVisibility());
}
Vertex classVertex = classVertexBuilder.save(getAuthorizations());
String containsClassEdgeId = JavaCodeIngestIdGenerator.createFileContainsClassEdgeId((Vertex) data.getElement(), classVertex);
getGraph().addEdge(containsClassEdgeId, (Vertex) data.getElement(), classVertex, Ontology.EDGE_LABEL_CLASS_FILE_CONTAINS_CLASS, data.getProperty().getVisibility(), getAuthorizations());
return classVertex;
}
private Vertex createClassVertex(String className, GraphPropertyWorkData data) {
VertexBuilder classVertexBuilder = createClassVertexBuilder(className, data);
return classVertexBuilder.save(getAuthorizations());
}
private VertexBuilder createClassVertexBuilder(String className, GraphPropertyWorkData data) {
int i;
while ((i = className.lastIndexOf('[')) > 0) {
className = className.substring(0, i);
}
String classId = JavaCodeIngestIdGenerator.createClassId(className);
VertexBuilder vertexBuilder = getGraph().prepareVertex(classId, data.getVisibility());
data.setVisibilityJsonOnElement(vertexBuilder);
LumifyProperties.TITLE.setProperty(vertexBuilder, classNameToTitle(className), data.createPropertyMetadata(), data.getVisibility());
Ontology.CLASS_NAME.setProperty(vertexBuilder, className, data.createPropertyMetadata(), data.getVisibility());
return vertexBuilder;
}
private String classNameToTitle(String className) {
int i = className.lastIndexOf('.');
if (i < 0) {
return className;
}
return className.substring(i + 1);
}
private void createMethodVertex(Method method, Vertex classVertex, JavaClass javaClass, ConstantPoolGen constants, GraphPropertyWorkData data) {
String methodId = JavaCodeIngestIdGenerator.createMethodId(javaClass, method);
VertexBuilder vertexBuilder = getGraph().prepareVertex(methodId, data.getVisibility());
data.setVisibilityJsonOnElement(vertexBuilder);
LumifyProperties.TITLE.setProperty(vertexBuilder, method.getName() + method.getSignature(), data.createPropertyMetadata(), data.getVisibility());
LumifyProperties.CONCEPT_TYPE.setProperty(vertexBuilder, Ontology.CONCEPT_TYPE_METHOD, data.createPropertyMetadata(), data.getVisibility());
Vertex methodVertex = vertexBuilder.save(getAuthorizations());
String classContainsMethodEdgeId = JavaCodeIngestIdGenerator.createClassContainsMethodEdgeId(classVertex, methodVertex);
Edge edge = getGraph().addEdge(classContainsMethodEdgeId, classVertex, methodVertex, Ontology.EDGE_LABEL_CLASS_CONTAINS, data.getVisibility(), getAuthorizations());
data.setVisibilityJsonOnElement(edge, getAuthorizations());
// return type
if (!method.getReturnType().toString().equals("void")) {
Vertex returnTypeVertex = createClassVertex(method.getReturnType().toString(), data);
String returnTypeEdgeId = JavaCodeIngestIdGenerator.createReturnTypeEdgeId(methodVertex, returnTypeVertex);
edge = getGraph().addEdge(returnTypeEdgeId, methodVertex, returnTypeVertex, Ontology.EDGE_LABEL_METHOD_RETURN_TYPE, data.getVisibility(), getAuthorizations());
data.setVisibilityJsonOnElement(edge, getAuthorizations());
createClassReferencesEdge(classVertex, returnTypeVertex, data);
}
// arguments
for (int i = 0; i < method.getArgumentTypes().length; i++) {
Type argumentType = method.getArgumentTypes()[i];
String argumentName = "arg" + i;
Vertex argumentTypeVertex = createClassVertex(argumentType.toString(), data);
String argumentEdgeId = JavaCodeIngestIdGenerator.createArgumentEdgeId(methodVertex, argumentTypeVertex, argumentName);
edge = getGraph().addEdge(argumentEdgeId, methodVertex, argumentTypeVertex, Ontology.EDGE_LABEL_METHOD_ARGUMENT, data.getVisibility(), getAuthorizations());
data.setVisibilityJsonOnElement(edge, getAuthorizations());
Ontology.ARGUMENT_NAME.setProperty(edge, argumentName, data.createPropertyMetadata(), data.getVisibility(), getAuthorizations());
createClassReferencesEdge(classVertex, argumentTypeVertex, data);
}
// method invokes
MethodGen mg = new MethodGen(method, javaClass.getClassName(), constants);
if (mg.isAbstract() || mg.isNative()) {
return;
}
ConstantPoolGen constantPool = mg.getConstantPool();
for (InstructionHandle ih = mg.getInstructionList().getStart(); ih != null; ih = ih.getNext()) {
Instruction i = ih.getInstruction();
if (i instanceof InvokeInstruction) {
InvokeInstruction ii = (InvokeInstruction) i;
String methodClassName = ii.getClassName(constantPool);
String methodName = ii.getMethodName(constantPool);
String methodSignature = ii.getSignature(constantPool);
String invokedMethodId = JavaCodeIngestIdGenerator.createMethodId(methodClassName, methodName, methodSignature);
VertexBuilder invokedMethodVertexBuilder = getGraph().prepareVertex(invokedMethodId, data.getVisibility());
data.setVisibilityJsonOnElement(invokedMethodVertexBuilder);
LumifyProperties.TITLE.setProperty(invokedMethodVertexBuilder, method.getSignature(), data.createPropertyMetadata(), data.getVisibility());
LumifyProperties.CONCEPT_TYPE.setProperty(invokedMethodVertexBuilder, Ontology.CONCEPT_TYPE_METHOD, data.createPropertyMetadata(), data.getVisibility());
Vertex invokedMethodVertex = invokedMethodVertexBuilder.save(getAuthorizations());
String methodInvokesMethodEdgeId = JavaCodeIngestIdGenerator.createMethodInvokesMethodEdgeId(methodVertex, invokedMethodVertex);
edge = getGraph().addEdge(methodInvokesMethodEdgeId, methodVertex, invokedMethodVertex, Ontology.EDGE_LABEL_INVOKED, data.getVisibility(), getAuthorizations());
data.setVisibilityJsonOnElement(edge, getAuthorizations());
Vertex invokeMethodClassVertex = createClassVertex(methodClassName, data);
createClassReferencesEdge(classVertex, invokeMethodClassVertex, data);
}
}
}
private void createFieldVertex(Field field, Vertex classVertex, JavaClass javaClass, GraphPropertyWorkData data) {
String fieldId = JavaCodeIngestIdGenerator.createFieldId(javaClass, field);
VertexBuilder vertexBuilder = getGraph().prepareVertex(fieldId, data.getVisibility());
data.setVisibilityJsonOnElement(vertexBuilder);
LumifyProperties.TITLE.setProperty(vertexBuilder, field.getName(), data.createPropertyMetadata(), data.getVisibility());
LumifyProperties.CONCEPT_TYPE.setProperty(vertexBuilder, Ontology.CONCEPT_TYPE_FIELD, data.createPropertyMetadata(), data.getVisibility());
Vertex fieldVertex = vertexBuilder.save(getAuthorizations());
String classContainsFieldEdgeId = JavaCodeIngestIdGenerator.createClassContainsFieldEdgeId(classVertex, fieldVertex);
Edge edge = getGraph().addEdge(classContainsFieldEdgeId, classVertex, fieldVertex, Ontology.EDGE_LABEL_CLASS_CONTAINS, data.getVisibility(), getAuthorizations());
data.setVisibilityJsonOnElement(edge, getAuthorizations());
Vertex fieldTypeVertex = createClassVertex(field.getType().toString(), data);
String fieldTypeEdgeId = JavaCodeIngestIdGenerator.createFieldTypeEdgeId(fieldVertex, fieldTypeVertex);
edge = getGraph().addEdge(fieldTypeEdgeId, fieldVertex, fieldTypeVertex, Ontology.EDGE_LABEL_FIELD_TYPE, data.getVisibility(), getAuthorizations());
data.setVisibilityJsonOnElement(edge, getAuthorizations());
createClassReferencesEdge(classVertex, fieldTypeVertex, data);
}
private void createClassReferencesEdge(Vertex classVertex, Vertex typeVertex, GraphPropertyWorkData data) {
String classReferencesEdgeId = JavaCodeIngestIdGenerator.createClassReferencesEdgeId(classVertex, typeVertex);
Edge edge = getGraph().addEdge(classReferencesEdgeId, classVertex, typeVertex, Ontology.EDGE_LABEL_CLASS_REFERENCES, data.getVisibility(), getAuthorizations());
data.setVisibilityJsonOnElement(edge, getAuthorizations());
}
@Override
public boolean isHandled(Element element, Property property) {
if (property == null) {
return false;
}
if (!property.getName().equals(LumifyProperties.RAW.getPropertyName())) {
return false;
}
String fileName = LumifyProperties.FILE_NAME.getPropertyValue(element);
if (fileName == null || !fileName.endsWith(".class")) {
return false;
}
return true;
}
}