/* * Copyright (c) MuleSoft, Inc. All rights reserved. http://www.mulesoft.com * The software in this package is published under the terms of the CPAL v1.0 * license, a copy of which has been included with this distribution in the * LICENSE.txt file. */ package org.mule.runtime.module.deployment.impl.internal.maven; import static java.io.File.separator; import static java.lang.String.format; import static org.apache.commons.io.filefilter.DirectoryFileFilter.DIRECTORY; import static org.mule.runtime.api.util.Preconditions.checkState; import static org.mule.runtime.core.util.FileUtils.createFile; import static org.mule.runtime.core.util.JarUtils.getUrlWithinJar; import static org.mule.runtime.core.util.JarUtils.getUrlsWithinJar; import static org.mule.runtime.core.util.JarUtils.loadFileContentFrom; import static org.mule.runtime.deployment.model.api.plugin.ArtifactPluginDescriptor.MULE_ARTIFACT_PATH_INSIDE_JAR; import static org.mule.runtime.deployment.model.api.plugin.ArtifactPluginDescriptor.MULE_PLUGIN_POM; import static org.mule.runtime.deployment.model.api.policy.PolicyTemplateDescriptor.META_INF; import static org.mule.runtime.module.artifact.classloader.MuleMavenPlugin.MULE_MAVEN_PLUGIN_ARTIFACT_ID; import static org.mule.runtime.module.artifact.classloader.MuleMavenPlugin.MULE_MAVEN_PLUGIN_GROUP_ID; import org.mule.runtime.api.exception.MuleRuntimeException; import org.mule.runtime.deployment.model.api.plugin.ArtifactPluginDescriptor; import org.mule.runtime.module.artifact.descriptor.ArtifactDescriptorCreateException; import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileFilter; import java.io.FileOutputStream; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; import java.util.Optional; import org.apache.maven.model.Build; import org.apache.maven.model.Dependency; import org.apache.maven.model.Model; import org.apache.maven.model.Plugin; import org.apache.maven.model.io.xpp3.MavenXpp3Reader; import org.apache.maven.model.io.xpp3.MavenXpp3Writer; import org.codehaus.plexus.util.xml.Xpp3Dom; import org.codehaus.plexus.util.xml.pull.XmlPullParserException; /** * Provides utility methods to wrk with Maven */ public class MavenUtils { private static final String SHARED_LIBRARIES_ELEMENT = "sharedLibraries"; /** * Returns the {@link Model} from a given artifact folder * * @param artifactFile file containing the artifact content. * @return the {@link Model} from the {@value ArtifactPluginDescriptor#MULE_PLUGIN_POM} file if available * @throws ArtifactDescriptorCreateException if the artifact jar does not contain a * {@value ArtifactPluginDescriptor#MULE_PLUGIN_POM} file or the file can' be loaded */ public static Model getPomModelFromJar(File artifactFile) { String pomFilePath = MULE_ARTIFACT_PATH_INSIDE_JAR + "/" + MULE_PLUGIN_POM; try { MavenXpp3Reader reader = new MavenXpp3Reader(); return reader.read(new ByteArrayInputStream(loadFileContentFrom(getPomUrlFromJar(artifactFile)).get())); } catch (IOException | XmlPullParserException e) { throw new ArtifactDescriptorCreateException(format("There was an issue reading '%s' for the plugin '%s'", pomFilePath, artifactFile.getAbsolutePath()), e); } } /** * Finds the URL of the pom file within the artifact file. * * @param artifactFile the artifact file to search for the pom file. * @return the URL to the pom file. */ public static URL getPomUrlFromJar(File artifactFile) { String pomFilePath = MULE_ARTIFACT_PATH_INSIDE_JAR + "/" + MULE_PLUGIN_POM; URL possibleUrl; try { possibleUrl = getUrlWithinJar(artifactFile, pomFilePath); try (InputStream ignored = possibleUrl.openStream()) { return possibleUrl; } catch (Exception e) { List<URL> jarMavenUrls = getUrlsWithinJar(artifactFile, META_INF + "/" + "maven"); Optional<URL> pomUrl = jarMavenUrls.stream().filter(url -> url.toString().endsWith("pom.xml")).findAny(); if (!pomUrl.isPresent()) { throw new ArtifactDescriptorCreateException(format("The identifier '%s' requires the file '%s' within the artifact(error found while reading plugin '%s')", artifactFile.getName(), "pom.xml", artifactFile.getAbsolutePath())); } return pomUrl.get(); } } catch (IOException e) { throw new MuleRuntimeException(e); } } /** * Returns the {@link Model} from a given artifact folder * * @param artifactFolder folder containing the exploded artifact file. * @return the {@link Model} from the {@value ArtifactPluginDescriptor#MULE_PLUGIN_POM} file if available * @throws ArtifactDescriptorCreateException if the folder does not contain a {@value ArtifactPluginDescriptor#MULE_PLUGIN_POM} * file or the file can' be loaded */ public static Model getPomModelFolder(File artifactFolder) { final File mulePluginPom = lookupPomFromMavenLocation(artifactFolder); MavenXpp3Reader reader = new MavenXpp3Reader(); Model model; try { model = reader.read(new FileReader(mulePluginPom)); } catch (IOException | XmlPullParserException e) { throw new ArtifactDescriptorCreateException(format("There was an issue reading '%s' for the plugin '%s'", mulePluginPom.getName(), artifactFolder.getAbsolutePath()), e); } return model; } /** * Updates the pom file from an artifact. * * @param artifactFolder the artifact folder * @param model the new pom model */ public static void updateArtifactPom(File artifactFolder, Model model) { final File mulePluginPom = lookupPomFromMavenLocation(artifactFolder); MavenXpp3Writer writer = new MavenXpp3Writer(); try (FileOutputStream outputStream = new FileOutputStream(mulePluginPom)) { writer.write(outputStream, model); } catch (IOException e) { throw new MuleRuntimeException(e); } } /** * Creates the pom file for a deployable artifact inside the artifact exploded folder * * @param artifactFolder the deployable artifact folder * @param model the pom model */ public static void createDeployablePomFile(File artifactFolder, Model model) { File pomFileLocation = new File(artifactFolder, Paths.get("META-INF", "maven", model.getGroupId(), model.getArtifactId(), "pom.xml").toString()); try { createFile(pomFileLocation.getAbsolutePath()); } catch (IOException e) { throw new MuleRuntimeException(e); } try (FileWriter fileWriter = new FileWriter(pomFileLocation)) { new MavenXpp3Writer().write(fileWriter, model); } catch (IOException e) { throw new MuleRuntimeException(e); } } private static File lookupPomFromMavenLocation(File artifactFolder) { File mulePluginPom = null; File lookupFolder = new File(artifactFolder, "META-INF" + separator + "maven"); while (lookupFolder != null && lookupFolder.exists()) { File possiblePomLocation = new File(lookupFolder, MULE_PLUGIN_POM); if (possiblePomLocation.exists()) { mulePluginPom = possiblePomLocation; break; } File[] directories = lookupFolder.listFiles((FileFilter) DIRECTORY); checkState(directories != null || directories.length == 0, format("No directories under %s so pom.xml file for artifact in folder %s could not be found", lookupFolder.getAbsolutePath(), artifactFolder.getAbsolutePath())); checkState(directories.length == 1, format("More than one directory under %s so pom.xml file for artifact in folder %s could not be found", lookupFolder.getAbsolutePath(), artifactFolder.getAbsolutePath())); lookupFolder = directories[0]; } // final File mulePluginPom = new File(artifactFolder, MULE_ARTIFACT_FOLDER + separator + MULE_PLUGIN_POM); if (mulePluginPom == null || !mulePluginPom.exists()) { throw new ArtifactDescriptorCreateException(format("The maven bundle loader requires the file pom.xml (error found while reading plugin '%s')", artifactFolder.getName())); } return mulePluginPom; } /** * Adds a shared library to the pom model. If the plugin does not exists yet in the model then it will create it. * * @param model the pom model * @param dependency the descriptor of the dependency */ public static void addSharedLibraryDependency(Model model, Dependency dependency) { Build build = model.getBuild(); if (build == null) { build = new Build(); model.setBuild(build); } List<Plugin> plugins = build.getPlugins(); if (plugins == null) { plugins = new ArrayList<>(); build.setPlugins(plugins); } Optional<Plugin> pluginOptional = plugins.stream().filter(plugin -> plugin.getGroupId().equals(MULE_MAVEN_PLUGIN_GROUP_ID) && plugin.getArtifactId().equals(MULE_MAVEN_PLUGIN_ARTIFACT_ID)).findFirst(); List<Plugin> finalPlugins = plugins; Plugin plugin = pluginOptional.orElseGet(() -> { Plugin muleMavenPlugin = new Plugin(); muleMavenPlugin.setGroupId(MULE_MAVEN_PLUGIN_GROUP_ID); muleMavenPlugin.setArtifactId(MULE_MAVEN_PLUGIN_ARTIFACT_ID); finalPlugins.add(muleMavenPlugin); return muleMavenPlugin; }); Xpp3Dom configuration = (Xpp3Dom) plugin.getConfiguration(); if (configuration == null) { configuration = new Xpp3Dom("configuration"); plugin.setConfiguration(configuration); } Xpp3Dom sharedLibrariesDom = configuration.getChild(SHARED_LIBRARIES_ELEMENT); if (sharedLibrariesDom == null) { sharedLibrariesDom = new Xpp3Dom(SHARED_LIBRARIES_ELEMENT); configuration.addChild(sharedLibrariesDom); } Xpp3Dom sharedLibraryDom = new Xpp3Dom("sharedLibrary"); sharedLibrariesDom.addChild(sharedLibraryDom); Xpp3Dom groupIdDom = new Xpp3Dom("groupId"); groupIdDom.setValue(dependency.getGroupId()); sharedLibraryDom.addChild(groupIdDom); Xpp3Dom artifactIdDom = new Xpp3Dom("artifactId"); artifactIdDom.setValue(dependency.getArtifactId()); sharedLibraryDom.addChild(artifactIdDom); } }