package org.jboss.windup.exec; import java.nio.file.Path; import java.util.ArrayList; import java.util.Collection; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.function.Function; import java.util.logging.Level; import java.util.logging.Logger; import java.util.stream.Collectors; import javax.inject.Inject; import org.jboss.forge.furnace.services.Imported; import org.jboss.forge.furnace.util.Assert; import org.jboss.forge.furnace.util.Predicate; import org.jboss.windup.exec.rulefilters.NotPredicate; import org.jboss.windup.config.DefaultEvaluationContext; import org.jboss.windup.config.GraphRewrite; import org.jboss.windup.config.KeepWorkDirsOption; import org.jboss.windup.config.PreRulesetEvaluation; import org.jboss.windup.config.RuleLifecycleListener; import org.jboss.windup.config.RuleProvider; import org.jboss.windup.config.RuleSubset; import org.jboss.windup.config.SkipReportsRenderingOption; import org.jboss.windup.config.loader.RuleLoader; import org.jboss.windup.config.loader.RuleLoaderContext; import org.jboss.windup.config.metadata.RuleProviderRegistry; import org.jboss.windup.config.metadata.TechnologyReference; import org.jboss.windup.config.metadata.TechnologyReferenceTransformer; import org.jboss.windup.config.phase.PostReportGenerationPhase; import org.jboss.windup.config.phase.PostReportRenderingPhase; import org.jboss.windup.config.phase.PreReportGenerationPhase; import org.jboss.windup.config.phase.ReportGenerationPhase; import org.jboss.windup.config.phase.ReportRenderingPhase; import org.jboss.windup.exec.configuration.WindupConfiguration; import org.jboss.windup.exec.configuration.options.ExcludeTagsOption; import org.jboss.windup.exec.configuration.options.IncludeTagsOption; import org.jboss.windup.exec.configuration.options.SourceOption; import org.jboss.windup.exec.configuration.options.TargetOption; import org.jboss.windup.exec.rulefilters.AndPredicate; import org.jboss.windup.exec.rulefilters.RuleProviderPhasePredicate; import org.jboss.windup.exec.rulefilters.SourceAndTargetPredicate; import org.jboss.windup.exec.rulefilters.TaggedRuleProviderPredicate; import org.jboss.windup.graph.GraphContext; import org.jboss.windup.graph.GraphContextFactory; import org.jboss.windup.graph.model.TechnologyReferenceModel; import org.jboss.windup.graph.model.WindupConfigurationModel; import org.jboss.windup.graph.model.resource.FileModel; import org.jboss.windup.graph.service.FileService; import org.jboss.windup.graph.service.GraphService; import org.jboss.windup.graph.service.WindupConfigurationService; import org.jboss.windup.util.Checks; import org.jboss.windup.util.ExecutionStatistics; import org.jboss.windup.util.Logging; import org.jboss.windup.util.exception.WindupException; import org.ocpsoft.rewrite.config.Configuration; import org.ocpsoft.rewrite.config.RuleVisit; import org.ocpsoft.rewrite.context.EvaluationContext; import org.ocpsoft.rewrite.param.DefaultParameterValueStore; import org.ocpsoft.rewrite.param.ParameterValueStore; /** * Loads and executes the Rules from RuleProviders according to given WindupConfiguration. * * @author <a href="mailto:lincolnbaxter@gmail.com">Lincoln Baxter, III</a> * @author <a href="mailto:zizka@seznam.cz">Ondrej Zizka</a> */ public class WindupProcessorImpl implements WindupProcessor { private static final Logger LOG = Logging.get(WindupProcessorImpl.class); @Inject private RuleLoader ruleLoader; @Inject private GraphContextFactory graphContextFactory; @Inject private Imported<RuleLifecycleListener> listeners; @Override public void execute() { execute(new WindupConfiguration()); } @Override public void execute(WindupConfiguration configuration) { long startTime = System.currentTimeMillis(); validateConfig(configuration); boolean autoCloseGraph = false; if (configuration.getGraphContext() == null) { // Since we created it, we should clean it up autoCloseGraph = true; Path graphPath = configuration.getOutputDirectory().resolve(GraphContextFactory.DEFAULT_GRAPH_SUBDIRECTORY); GraphContext graphContext = this.graphContextFactory.create(graphPath); configuration.setGraphContext(graphContext); } try { printConfigInfo(configuration); GraphContext context = configuration.getGraphContext(); context.setOptions(configuration.getOptionMap()); WindupConfigurationModel configurationModel = WindupConfigurationService.getConfigurationModel(context); Set<FileModel> inputPathModels = new LinkedHashSet<>(); for (Path inputPath : configuration.getInputPaths()) { inputPathModels.add(getFileModel(context, inputPath)); } configurationModel.setInputPaths(inputPathModels); configurationModel.setOutputPath(getFileModel(context, configuration.getOutputDirectory())); configurationModel.setOnlineMode(configuration.isOnline()); configurationModel.setExportingCSV(configuration.isExportingCSV()); configurationModel.setKeepWorkDirectories(configuration.getOptionValue(KeepWorkDirsOption.NAME)); for (Path path : configuration.getAllUserRulesDirectories()) { System.out.println("Using user rules dir: " + path); if (path == null) { throw new WindupException("Null path found (all paths are: " + configuration.getAllUserRulesDirectories() + ")"); } configurationModel.addUserRulesPath(getFileModel(context, path)); } for (Path path : configuration.getAllIgnoreDirectories()) { configurationModel.addUserIgnorePath(getFileModel(context, path)); } List<RuleLifecycleListener> listeners = new ArrayList<>(); for (RuleLifecycleListener listener : this.listeners) { listeners.add(listener); } final GraphRewrite event = new GraphRewrite(listeners, context); RuleLoaderContext ruleLoaderContext = new RuleLoaderContext(event.getRewriteContext(), configuration.getAllUserRulesDirectories(), configuration.getRuleProviderFilter()); ruleLoaderContext = configureRuleProviderAndTagFilters(ruleLoaderContext, configuration); addSourceAndTargetInformation(event, configuration, configurationModel); RuleProviderRegistry providerRegistry = ruleLoader.loadConfiguration(ruleLoaderContext); Configuration rules = providerRegistry.getConfiguration(); if (configuration.getProgressMonitor() != null) listeners.add(new DefaultRuleLifecycleListener(configuration.getProgressMonitor(), rules)); event.getRewriteContext().put(RuleProviderRegistry.class, providerRegistry); RuleSubset ruleSubset = RuleSubset.create(rules); ruleSubset.setAlwaysHaltOnFailure(configuration.isAlwaysHaltOnException()); for (RuleLifecycleListener listener : listeners) { ruleSubset.addLifecycleListener(listener); } new RuleVisit(ruleSubset).accept((rule) -> { if (rule instanceof PreRulesetEvaluation) ((PreRulesetEvaluation) rule).preRulesetEvaluation(event); }); ruleSubset.perform(event, createEvaluationContext()); if (event.getWindupStopException() != null) LOG.log(Level.WARNING, "Windup stopped on request before finishing, see the exception for where.", event.getWindupStopException()); } finally { if (autoCloseGraph) { try { configuration.getGraphContext().close(); } catch (Throwable t) { LOG.log(Level.WARNING, "Failed to close graph due to: " + t.getMessage(), t); } } long endTime = System.currentTimeMillis(); long seconds = (endTime - startTime) / 1000L; LOG.info("Windup execution took " + seconds + " seconds to execute on input: " + configuration.getInputPaths() + "!"); ExecutionStatistics.get().reset(); } } private void addSourceAndTargetInformation(GraphRewrite event, WindupConfiguration configuration, WindupConfigurationModel configurationModel) { @SuppressWarnings("unchecked") Collection<String> sources = (Collection<String>) configuration.getOptionMap().get(SourceOption.NAME); @SuppressWarnings("unchecked") Collection<String> targets = (Collection<String>) configuration.getOptionMap().get(TargetOption.NAME); GraphService<TechnologyReferenceModel> technologyReferenceService = new GraphService<>(event.getGraphContext(), TechnologyReferenceModel.class); Function<String, TechnologyReferenceModel> createReferenceModel = (techID) -> { TechnologyReference reference = TechnologyReference.parseFromIDAndVersion(techID); TechnologyReferenceModel technologyReferenceModel = technologyReferenceService.create(); technologyReferenceModel.setTechnologyID(reference.getId()); technologyReferenceModel.setVersionRange(reference.getVersionRangeAsString()); return technologyReferenceModel; }; if (sources != null) { sources.forEach((sourceID) -> { configurationModel.addSourceTechnology(createReferenceModel.apply(sourceID)); }); } if (targets != null) { targets.forEach((targetID) -> { configurationModel.addTargetTechnology(createReferenceModel.apply(targetID)); }); } } @SuppressWarnings("unchecked") private RuleLoaderContext configureRuleProviderAndTagFilters(RuleLoaderContext ruleLoaderContext, WindupConfiguration config) { Collection<String> includeTags = (Collection<String>) config.getOptionMap().get(IncludeTagsOption.NAME); Collection<String> excludeTags = (Collection<String>) config.getOptionMap().get(ExcludeTagsOption.NAME); Collection<String> sources = (Collection<String>) config.getOptionMap().get(SourceOption.NAME); Collection<String> targets = (Collection<String>) config.getOptionMap().get(TargetOption.NAME); if(includeTags != null && includeTags.isEmpty()) includeTags = null; if(excludeTags != null && excludeTags.isEmpty()) excludeTags = null; if(sources != null && sources.isEmpty()) sources = null; if(targets != null && targets.isEmpty()) targets = null; if (includeTags != null || excludeTags != null || sources != null || targets != null) { Predicate<RuleProvider> configuredPredicate = config.getRuleProviderFilter(); final TaggedRuleProviderPredicate tagPredicate = new TaggedRuleProviderPredicate(includeTags, excludeTags); List<TechnologyReferenceTransformer> transformers = TechnologyReferenceTransformer.getTransformers(ruleLoaderContext); /* * Create a Map based upon the ID of the original to be transformed. */ Map<String, List<TechnologyReferenceTransformer>> transformerMap = transformers.stream() .collect(Collectors.toMap( // This is the Map key transformer -> transformer.getOriginal().getId(), // Create a List for each entry (transformer) -> { List<TechnologyReferenceTransformer> list = new ArrayList<>(); list.add(transformer); return list; }, // Merge the list if there are multiple entries for the same id (old, latest) -> { old.addAll(latest); return old; }) ); // Use the tech transformers to transform the IDs Function<String, String> transformTechFunction = (technologyID) -> { if (transformerMap.containsKey(technologyID)) { for (TechnologyReferenceTransformer transformer : transformerMap.get(TechnologyReference.parseFromIDAndVersion(technologyID).getId())) technologyID = transformer.transform(technologyID).toString(); } return technologyID; }; sources = (sources == null) ? null : sources.stream().map(transformTechFunction).collect(Collectors.toSet()); config.setOptionValue(SourceOption.NAME, sources); targets = (targets== null) ? null : targets.stream().map(transformTechFunction).collect(Collectors.toSet()); config.setOptionValue(TargetOption.NAME, targets); final SourceAndTargetPredicate sourceAndTargetPredicate = new SourceAndTargetPredicate(sources, targets); Predicate<RuleProvider> providerFilter = new AndPredicate(tagPredicate, sourceAndTargetPredicate); if (configuredPredicate != null) providerFilter = new AndPredicate(configuredPredicate, tagPredicate, sourceAndTargetPredicate); LOG.info("RuleProvider filter: " + providerFilter); config.setRuleProviderFilter(providerFilter); } Boolean skipReports = false; // if skipReportsRendering option is set filter rules in related phases if (config.getOptionMap().containsKey(SkipReportsRenderingOption.NAME)) { skipReports = (Boolean) config.getOptionMap().get(SkipReportsRenderingOption.NAME); } if (skipReports) { NotPredicate skipReportsProviderFilter = new NotPredicate( new RuleProviderPhasePredicate(PreReportGenerationPhase.class, ReportGenerationPhase.class, ReportRenderingPhase.class, PostReportGenerationPhase.class, PostReportRenderingPhase.class)); Predicate<RuleProvider> configuredProvider = config.getRuleProviderFilter(); Predicate<RuleProvider> providerFilter = new AndPredicate(skipReportsProviderFilter); if (configuredProvider != null) { providerFilter = new AndPredicate(configuredProvider, skipReportsProviderFilter); } LOG.info("Adding RuleProvider filter for skipping reports: " + providerFilter); config.setRuleProviderFilter(providerFilter); } return new RuleLoaderContext(ruleLoaderContext.getContext(), ruleLoaderContext.getRulePaths(), config.getRuleProviderFilter()); } private FileModel getFileModel(GraphContext context, Path file) { return new FileService(context).createByFilePath(file.toString()); } private EvaluationContext createEvaluationContext() { final DefaultEvaluationContext evaluationContext = new DefaultEvaluationContext(); final DefaultParameterValueStore values = new DefaultParameterValueStore(); evaluationContext.put(ParameterValueStore.class, values); return evaluationContext; } private void validateConfig(WindupConfiguration windupConfiguration) { Assert.notNull(windupConfiguration, "Windup configuration must not be null. (Call default execution if no configuration is required.)"); Collection<Path> inputPaths = windupConfiguration.getInputPaths(); Assert.notNull(inputPaths, "Path to the application must not be null!"); for (Path inputPath : inputPaths) { Assert.notNull(inputPath, "Path to the application must not be null!"); Checks.checkFileOrDirectoryToBeRead(inputPath.toFile(), "Application"); } Path outputDirectory = windupConfiguration.getOutputDirectory(); Assert.notNull(outputDirectory, "Output directory must not be null!"); Checks.checkDirectoryToBeFilled(outputDirectory.toFile(), "Output directory"); } private void printConfigInfo(WindupConfiguration windupConfiguration) { LOG.info(""); if (windupConfiguration.getInputPaths().size() == 1) { LOG.info("Input Application:" + windupConfiguration.getInputPaths().iterator().next()); } else { LOG.info("Input Applications:"); for (Path inputPath : windupConfiguration.getInputPaths()) { LOG.info("\t" + inputPath); } LOG.info(""); } LOG.info("Output Path:" + windupConfiguration.getOutputDirectory()); LOG.info(""); for (Map.Entry<String, Object> entrySet : windupConfiguration.getOptionMap().entrySet()) { LOG.info("\t" + entrySet.getKey() + ": " + entrySet.getValue()); } } }