package org.jboss.windup.rules.apps.mavenize; import java.io.FileWriter; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.logging.Logger; import org.apache.commons.lang3.exception.ExceptionUtils; import org.jboss.windup.graph.model.WindupConfigurationModel; import org.jboss.windup.reporting.freemarker.FurnaceFreeMarkerTemplateLoader; import org.jboss.windup.util.Logging; import org.jboss.windup.util.exception.WindupException; import freemarker.core.ParseException; import freemarker.template.DefaultObjectWrapperBuilder; import freemarker.template.Template; import freemarker.template.TemplateException; /** * Recursively renders the previously created Maven project structure into pom.xml's in a directory tree. * * @author <a href="http://ondra.zizka.cz/">Ondrej Zizka, ozizka at seznam.cz</a> */ public class MavenStructureRenderer { private static final Logger LOG = Logging.get(MavenStructureRenderer.class); private static final String TEMPLATE_POM_XML = "/org/jboss/windup/rules/apps/mavenize/pom.xml.ftl"; private static final String TEMPLATE_BOM_XML = "/org/jboss/windup/rules/apps/mavenize/bom.xml.ftl"; private MavenizationService.MavenizationContext mavCtx; MavenStructureRenderer(MavenizationService.MavenizationContext mavCtx) { this.mavCtx = mavCtx; } void createMavenProjectDirectoryTree() { try { Path mavenizedAppPath = mavCtx.getMavenizedBaseDir().resolve(mavCtx.getUnifiedAppName()); // Root POM renderPomXml(mavCtx, mavCtx.getRootPom(), mavenizedAppPath.resolve("pom.xml")); List<Throwable> exceptions = new ArrayList<>(); for (Map.Entry<String, Pom> entry : mavCtx.getRootPom().submodules.entrySet()) { try { String subDir = entry.getKey(); Path resultPomXmlPath = mavenizedAppPath.resolve(subDir).resolve("pom.xml"); LOG.info("Writing " + subDir + "/pom.xml" + "\n > " + entry.getValue()); renderPomXml(mavCtx, entry.getValue(), resultPomXmlPath); } catch (Throwable ex) { exceptions.add(ex); } } throwIfErrors(exceptions); } catch (Exception ex) { throw new WindupException("Failed creating the Maven project structure: " + ex.getMessage(), ex); } } private static void renderPomXml(MavenizationService.MavenizationContext mavCtx, Pom pom, Path pomXmlPath) { Map vars = new HashMap(); vars.put("pom", pom); vars.put("config", mavCtx.getGraphContext().getUnique(WindupConfigurationModel.class)); Path template = chooseTemplate(pom); try { LOG.info("Rendering template: " + template + " into " + pomXmlPath + "\n - " + pom); Files.createDirectories(pomXmlPath.getParent()); renderFreemarkerTemplate(template, vars, pomXmlPath); } catch (ParseException ex) { throw new WindupException("Could not parse pom.xml template: " + template + "\nReason: " + ex.getMessage(), ex); } catch (IOException | TemplateException ex) { throw new WindupException("Error rendering pom.xml template: " + template + "\nReason: " + ex.getMessage(), ex); } } private static Path chooseTemplate(Pom pom) { Path template; switch(pom.role) { case BOM: template = Paths.get(TEMPLATE_BOM_XML); break; default: switch(pom.coord.getPackaging()){ case "pom": case "jar": case "war": case "ear": default: template = Paths.get(TEMPLATE_POM_XML); break; case "bom": template = Paths.get(TEMPLATE_BOM_XML); break; // Not a standard Maven packaging. } break; } return template; } /** * Renders the given FreeMarker template to given directory, using given variables. */ private static void renderFreemarkerTemplate(Path templatePath, Map vars, Path outputPath) throws IOException, TemplateException { if(templatePath == null) throw new WindupException("templatePath is null"); freemarker.template.Configuration freemarkerConfig = new freemarker.template.Configuration(freemarker.template.Configuration.VERSION_2_3_23); DefaultObjectWrapperBuilder objectWrapperBuilder = new DefaultObjectWrapperBuilder(freemarker.template.Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS); objectWrapperBuilder.setUseAdaptersForContainers(true); freemarkerConfig.setObjectWrapper(objectWrapperBuilder.build()); freemarkerConfig.setTemplateLoader(new FurnaceFreeMarkerTemplateLoader()); Template template = freemarkerConfig.getTemplate(templatePath.toString().replace('\\', '/')); try (FileWriter fw = new FileWriter(outputPath.toFile())) { template.process(vars, fw); } } private void throwIfErrors(List<Throwable> exceptions) throws WindupException { if (exceptions.isEmpty()) return; StringBuilder sb = new StringBuilder("Errors when creating the Maven project directory tree:\n"); for (Throwable ex : exceptions) { sb.append(" ").append(ex.getMessage()).append("\n"); } sb.append("The first error's stack trace:\n "); sb.append(ExceptionUtils.getStackTrace(exceptions.get(0))); throw new WindupException(sb.toString()); } }