package org.jboss.windup.reporting.freemarker; import java.io.FileWriter; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.concurrent.Callable; import java.util.logging.Level; import java.util.logging.Logger; import org.jboss.forge.furnace.Furnace; import org.jboss.forge.furnace.lock.LockMode; import org.jboss.windup.config.GraphRewrite; import org.jboss.windup.config.Variables; import org.jboss.windup.config.operation.Iteration; import org.jboss.windup.config.operation.iteration.AbstractIterationOperation; import org.jboss.windup.reporting.model.ReportModel; import org.jboss.windup.reporting.service.ReportService; import org.jboss.windup.util.ExecutionStatistics; import org.ocpsoft.rewrite.context.EvaluationContext; import freemarker.template.Configuration; import freemarker.template.Template; import freemarker.template.TemplateException; /** * This class is used to produce a freemarker report from inside of a Windup {@link Iteration}. * * @author <a href="mailto:jesse.sightler@gmail.com">Jesse Sightler</a> <jesse.sightler@gmail.com) * */ public class FreeMarkerIterationOperation extends AbstractIterationOperation<ReportModel> { private static final String DEFAULT_ITERATION_PAYLOAD_NAME = "reportModel"; private static final Logger LOG = Logger.getLogger(FreeMarkerIterationOperation.class.getName()); private final Furnace furnace; private final Set<String> variableNames = new HashSet<>(); private final boolean useDefaultPayloadVariableName; protected FreeMarkerIterationOperation(Furnace furnace, String... varNames) { super(); this.furnace = furnace; useDefaultPayloadVariableName = true; if (varNames != null) { variableNames.addAll(Arrays.asList(varNames)); } } protected FreeMarkerIterationOperation(Furnace furnace, String iterationVarName, String... varNames) { super(iterationVarName); this.furnace = furnace; useDefaultPayloadVariableName = false; variableNames.add(iterationVarName); if (varNames != null) { variableNames.addAll(Arrays.asList(varNames)); } } /** * Create a FreeMarkerIterationOperation with the provided furnace instance, the provided iteration var, as well as any other associated variables * (based upon variables in the Variables object). */ public static FreeMarkerIterationOperation create(Furnace furnace, String... varNames) { return new FreeMarkerIterationOperation(furnace, varNames); } @Override public void perform(final GraphRewrite event, final EvaluationContext context, final ReportModel payload) { String templatePath = payload.getTemplatePath().replace('\\', '/'); String outputFilename = payload.getReportFilename(); ExecutionStatistics.get().begin("FreeMarkerIterationOperation.render(" + templatePath + ", " + outputFilename + ")"); try { ReportService reportService = new ReportService(event.getGraphContext()); Path outputDir = reportService.getReportDirectory(); if (!Files.isDirectory(outputDir)) { Files.createDirectories(outputDir); } Path outputPath = outputDir.resolve(outputFilename); LOG.info("Reporting: Writing template \"" + templatePath + "\" to output file \"" + outputPath.toAbsolutePath().toString() + "\""); Configuration freemarkerConfig = FreeMarkerUtil.getDefaultFreemarkerConfiguration(); Template template = freemarkerConfig.getTemplate(templatePath); Variables variables = Variables.instance(event); // just the variables Map<String, Object> vars = FreeMarkerUtil.findFreeMarkerContextVariables(variables, variableNames.toArray(new String[variableNames .size()])); if (useDefaultPayloadVariableName) { vars.put(DEFAULT_ITERATION_PAYLOAD_NAME, payload); } vars.put("event", event); // also, extension functions (these are kept separate from vars in order to prevent them // from being stored in the associated data with the reportmodel) final Map<String, Object> freeMarkerExtensions; freeMarkerExtensions = furnace.getLockManager().performLocked(LockMode.WRITE, new Callable<Map<String, Object>>() { @Override public Map<String, Object> call() throws Exception { return FreeMarkerUtil.findFreeMarkerExtensions(furnace, event); } }); Map<String, Object> objects = new HashMap<>(vars); objects.putAll(freeMarkerExtensions); try (FileWriter fw = new FileWriter(outputPath.toFile())) { template.process(objects, fw); } } catch (IOException | TemplateException e) { LOG.log(Level.WARNING, "\n Failed to write template: " + templatePath + "\n To: " + outputFilename + "\n Due to: " + e.getMessage(), e); } finally { ExecutionStatistics.get().end("FreeMarkerIterationOperation.render(" + templatePath + ", " + outputFilename + ")"); } } @Override public String toString() { return "RenderFreeMarkerTemplate"; } }