package org.jboss.windup.rules.apps.java.dependencyreport; import java.util.HashMap; import java.util.Map; import org.apache.commons.lang3.StringUtils; import org.jboss.windup.config.AbstractRuleProvider; import org.jboss.windup.config.GraphRewrite; import org.jboss.windup.config.loader.RuleLoaderContext; import org.jboss.windup.config.metadata.RuleMetadata; import org.jboss.windup.config.operation.GraphOperation; import org.jboss.windup.config.phase.ReportGenerationPhase; import org.jboss.windup.graph.GraphContext; import org.jboss.windup.graph.model.ArchiveModel; import org.jboss.windup.graph.model.DuplicateArchiveModel; import org.jboss.windup.graph.model.ProjectModel; import org.jboss.windup.graph.model.WindupConfigurationModel; import org.jboss.windup.graph.model.resource.FileModel; import org.jboss.windup.graph.service.ProjectService; import org.jboss.windup.graph.service.WindupConfigurationService; import org.jboss.windup.graph.traversal.ProjectModelTraversal; import org.jboss.windup.reporting.model.TemplateType; import org.jboss.windup.reporting.service.ApplicationReportService; import org.jboss.windup.reporting.service.ReportService; import org.ocpsoft.rewrite.config.Configuration; import org.ocpsoft.rewrite.config.ConfigurationBuilder; import org.ocpsoft.rewrite.context.EvaluationContext; /** * Creates a report of JAR dependencies. * * @author <a href="mailto:jesse.sightler@gmail.com">Jesse Sightler</a> */ @RuleMetadata(phase = ReportGenerationPhase.class, id = "Create Java Dependency Report") public class CreateDependencyReportRuleProvider extends AbstractRuleProvider { public static final String REPORT_NAME = "Dependencies"; public static final String TEMPLATE = "/reports/templates/dependency_report.ftl"; public static final String REPORT_DESCRIPTION = "This report displays all Java packaged dependencies found within the application."; @Override public Configuration getConfiguration(RuleLoaderContext ruleLoaderContext) { // @formatter:off return ConfigurationBuilder.begin() .addRule() .perform(new GraphOperation() { @Override public void perform(GraphRewrite event, EvaluationContext context) { // configuration of current execution WindupConfigurationModel configurationModel = WindupConfigurationService.getConfigurationModel(event.getGraphContext()); int count = 0; for (FileModel inputPath : configurationModel.getInputPaths()) { ProjectModel projectModel = inputPath.getProjectModel(); createReport(event.getGraphContext(), projectModel); count++; } // only create a global report if there is more than one application if (count > 1) createGlobalReport(event.getGraphContext(), configurationModel); } @Override public String toString() { return "CreateDependencyReport"; } }); // @formatter:on } private void addAll(GraphContext context, DependenciesReportModel reportModel, ProjectModelTraversal traversal, Map<String, DependencyReportDependencyGroupModel> groupsBySHA1) { FileModel rootFileModel = traversal.getCurrent().getRootFileModel(); // Don't create a dependency entry for the entire application (root project) boolean isRootProject = traversal.getCurrent().getParentProject() == null; if (!isRootProject && rootFileModel instanceof ArchiveModel) { ArchiveModel archiveModel = (ArchiveModel) rootFileModel; ArchiveModel canonicalArchive; if (archiveModel instanceof DuplicateArchiveModel) canonicalArchive = ((DuplicateArchiveModel) archiveModel).getCanonicalArchive(); else canonicalArchive = archiveModel; // 1. Get SHA1 String sha1 = archiveModel.getSHA1Hash(); // 2. Get the group model for this sha1 DependencyReportDependencyGroupModel groupModel = groupsBySHA1.get(sha1); if (groupModel == null) { groupModel = context.service(DependencyReportDependencyGroupModel.class).create(); groupModel.setSHA1(sha1); groupModel.setCanonicalProject(canonicalArchive.getProjectModel()); reportModel.addArchiveGroup(groupModel); groupsBySHA1.put(sha1, groupModel); } // 3. If the group already has this archive, don't do anything String path = traversal.getFilePath(rootFileModel); boolean archiveAlreadyLinked = false; for (DependencyReportToArchiveEdgeModel groupEdge : groupModel.getArchives()) { if (StringUtils.equals(groupEdge.getFullPath(), path)) { archiveAlreadyLinked = true; break; } } // Don't add projects that have already been added if (!archiveAlreadyLinked) { DependencyReportToArchiveEdgeModel edge = groupModel.addArchiveModel(archiveModel); edge.setFullPath(path); } } for (ProjectModelTraversal child : traversal.getChildren()) addAll(context, reportModel, child, groupsBySHA1); } private void createGlobalReport(GraphContext context, WindupConfigurationModel configuration) { ReportService reportService = new ReportService(context); DependenciesReportModel reportModel = createReportModel(context); Map<String, DependencyReportDependencyGroupModel> sha1ToGroup = new HashMap<>(); for (FileModel inputApplication : configuration.getInputPaths()) { ProjectModel projectModel = inputApplication.getProjectModel(); // Do not include shared libs in the global report as this is not really a user app if (StringUtils.equals(projectModel.getUniqueID(), ProjectService.SHARED_LIBS_UNIQUE_ID)) continue; ProjectModelTraversal traversal = new ProjectModelTraversal(inputApplication.getProjectModel()); addAll(context, reportModel, traversal, sha1ToGroup); } reportModel.setDisplayInGlobalApplicationIndex(true); reportService.setUniqueFilename(reportModel, "dependency_report_global", "html"); } private void createReport(GraphContext context, ProjectModel application) { ReportService reportService = new ReportService(context); DependenciesReportModel reportModel = createReportModel(context); addAll(context, reportModel, new ProjectModelTraversal(application), new HashMap<String, DependencyReportDependencyGroupModel>()); reportModel.setProjectModel(application); reportService.setUniqueFilename(reportModel, "dependency_report_" + application.getName(), "html"); } private DependenciesReportModel createReportModel(GraphContext context) { ApplicationReportService service = new ApplicationReportService(context); DependenciesReportModel applicationReportModel = context .service(DependenciesReportModel.class) .addTypeToModel(service.create()); applicationReportModel.setDisplayInApplicationReportIndex(true); applicationReportModel.setReportPriority(120); applicationReportModel.setReportName(REPORT_NAME); applicationReportModel.setDescription(REPORT_DESCRIPTION); applicationReportModel.setReportIconClass("glyphicon glyphicon-compressed"); applicationReportModel.setTemplatePath(TEMPLATE); applicationReportModel.setTemplateType(TemplateType.FREEMARKER); return applicationReportModel; } }