package org.jboss.windup.rules.apps.java.decompiler; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.List; import org.jboss.windup.config.GraphRewrite; import org.jboss.windup.config.operation.GraphOperation; import org.jboss.windup.graph.GraphContext; import org.jboss.windup.graph.model.ProjectModel; import org.jboss.windup.rules.apps.java.model.JavaSourceFileModel; import org.ocpsoft.rewrite.context.EvaluationContext; import com.tinkerpop.blueprints.Vertex; import com.tinkerpop.gremlin.java.GremlinPipeline; import com.tinkerpop.pipes.PipeFunction; /** * Removes all the duplicates of .java file within a projectModel. There may be multiple especially in cases where .class is bundled with .java files. * Non-decompiled .java files have higher priority of being deleted than decompiled. */ public class CleanFromMultipleSourceFiles extends GraphOperation { @Override public void perform(GraphRewrite event, EvaluationContext context) { GremlinPipeline<Vertex, Vertex> pipeline = new GremlinPipeline<>( event.getGraphContext().getQuery().type(JavaSourceFileModel.class).vertices()); final GraphContext gContext = event.getGraphContext(); pipeline.groupBy(groupByProjectModelFunction(gContext), valueAsFramedVertex(gContext), returnVerticesToDelete(gContext)).cap(); HashMap<?, List<JavaSourceFileModel>> m = (HashMap<?, List<JavaSourceFileModel>>) pipeline.next(); for (List<JavaSourceFileModel> toBeDeleted : m.values()) { for (JavaSourceFileModel javaSourceFileModel : toBeDeleted) { gContext.getGraph().removeVertex(javaSourceFileModel.asVertex()); } } } // helping methods private PipeFunction groupByProjectModelFunction(final GraphContext context) { return new PipeFunction<Vertex, String>() { @Override public String compute(Vertex vertex) { JavaSourceFileModel javaModel = context.getFramed().frame(vertex, JavaSourceFileModel.class); // String that identifies 3 properties - projectModel + packageName + className that must be the same for vertices ProjectModel projectModel = javaModel.getProjectModel(); String projectModelID = projectModel == null ? "" : projectModel.asVertex().getId().toString(); String packageName = javaModel.getPackageName() == null ? "" : javaModel.getPackageName(); return projectModelID + "_" + packageName + "_" + javaModel.getFileName(); } }; } private PipeFunction valueAsFramedVertex(final GraphContext context) { return new PipeFunction<Vertex, JavaSourceFileModel>() { @Override public JavaSourceFileModel compute(Vertex vertex) { return context.getFramed().frame(vertex, JavaSourceFileModel.class); } }; } private PipeFunction returnVerticesToDelete(final GraphContext context) { return new PipeFunction<Collection<JavaSourceFileModel>, List<JavaSourceFileModel>>() { @Override public List<JavaSourceFileModel> compute(Collection<JavaSourceFileModel> javaClassFileModels) { boolean uniqueClassFound = false; List<JavaSourceFileModel> verticesToBeDeleted = new ArrayList<>(); if (javaClassFileModels.isEmpty()) { return null; } Iterator<JavaSourceFileModel> iterator = javaClassFileModels.iterator(); while (iterator.hasNext()) { JavaSourceFileModel javaModel = iterator.next(); if (javaModel.isWindupGenerated() != null && javaModel.isWindupGenerated() && !uniqueClassFound) { uniqueClassFound = true; } else if (!iterator.hasNext() && !uniqueClassFound) { uniqueClassFound = true; } else { verticesToBeDeleted.add(javaModel); } } return verticesToBeDeleted; } }; } }