diff --git a/plugin/src/main/java/org/wildfly/plugin/common/Utils.java b/plugin/src/main/java/org/wildfly/plugin/common/Utils.java index 75dd9bf6..50a0dac9 100644 --- a/plugin/src/main/java/org/wildfly/plugin/common/Utils.java +++ b/plugin/src/main/java/org/wildfly/plugin/common/Utils.java @@ -107,7 +107,7 @@ public static ScanResults scanDeployment(GlowConfig discoverProvisioningInfo, List featurePacks, boolean dryRun, Log log, - Path deploymentContent, + List deploymentContents, MavenRepoManager artifactResolver, Path outputFolder, GalleonBuilder pm, @@ -119,7 +119,7 @@ public static ScanResults scanDeployment(GlowConfig discoverProvisioningInfo, if (!excludedLayers.isEmpty()) { throw new MojoExecutionException("excluded layers must be empty when enabling glow"); } - if (!Files.exists(deploymentContent)) { + if (deploymentContents.isEmpty()) { throw new MojoExecutionException("A deployment is expected when enabling glow layer discovery"); } Path inProvisioningFile = null; @@ -134,7 +134,7 @@ public static ScanResults scanDeployment(GlowConfig discoverProvisioningInfo, p.storeProvisioningConfig(in, inProvisioningFile); } } - Arguments arguments = discoverProvisioningInfo.toArguments(deploymentContent, inProvisioningFile, + Arguments arguments = discoverProvisioningInfo.toArguments(deploymentContents, inProvisioningFile, layersConfigurationFileName); log.info("Glow is scanning... "); ScanResults results; diff --git a/plugin/src/main/java/org/wildfly/plugin/dev/DevMojo.java b/plugin/src/main/java/org/wildfly/plugin/dev/DevMojo.java index 24db5e39..8276f66e 100644 --- a/plugin/src/main/java/org/wildfly/plugin/dev/DevMojo.java +++ b/plugin/src/main/java/org/wildfly/plugin/dev/DevMojo.java @@ -661,10 +661,12 @@ protected Path provisionIfRequired(final Path installDir) throws MojoFailureExce } private ScanResults scanDeployment(GalleonBuilder pm) throws Exception { + List lst = new ArrayList<>(); + lst.add(resolveWarLocation()); return Utils.scanDeployment(discoverProvisioningInfo, layers, excludedLayers, featurePacks, false, getLog(), - resolveWarLocation(), + lst, mavenRepoManager, Paths.get(project.getBuild().getDirectory()), pm, diff --git a/plugin/src/main/java/org/wildfly/plugin/provision/DeploymentConfiguration.java b/plugin/src/main/java/org/wildfly/plugin/provision/DeploymentConfiguration.java new file mode 100644 index 00000000..aec8f7d6 --- /dev/null +++ b/plugin/src/main/java/org/wildfly/plugin/provision/DeploymentConfiguration.java @@ -0,0 +1,79 @@ +/* + * Copyright The WildFly Authors + * SPDX-License-Identifier: Apache-2.0 + */ +package org.wildfly.plugin.provision; + +/** + * + * @author jdenise + */ +public class DeploymentConfiguration { + + private String groupId; + private String artifactId; + private String classifier; + private String type = "jar"; + private String name; + + public String getName() { + return name; + } + + public String getGroupId() { + return groupId; + } + + public String getArtifactId() { + return artifactId; + } + + public String getType() { + return type; + } + + public String getClassifier() { + return classifier; + } + + /** + * @param groupId the groupId to set + */ + public void setGroupId(String groupId) { + this.groupId = groupId; + } + + /** + * @param artifactId the artifactId to set + */ + public void setArtifactId(String artifactId) { + this.artifactId = artifactId; + } + + /** + * @param classifier the classifier to set + */ + public void setClassifier(String classifier) { + this.classifier = classifier; + } + + /** + * @param type the type to set + */ + public void setType(String type) { + this.type = type; + } + + /** + * @param name the name to set + */ + public void setName(String name) { + this.name = name; + } + + @Override + public String toString() { + return getGroupId() + ":" + getArtifactId() + + (getClassifier() == null ? "" : ":" + getClassifier()) + ":" + getType(); + } +} diff --git a/plugin/src/main/java/org/wildfly/plugin/provision/DeploymentResolution.java b/plugin/src/main/java/org/wildfly/plugin/provision/DeploymentResolution.java new file mode 100644 index 00000000..2ca0e335 --- /dev/null +++ b/plugin/src/main/java/org/wildfly/plugin/provision/DeploymentResolution.java @@ -0,0 +1,63 @@ +/* + * Copyright The WildFly Authors + * SPDX-License-Identifier: Apache-2.0 + */ +package org.wildfly.plugin.provision; + +import java.io.File; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import org.apache.maven.artifact.Artifact; +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.project.MavenProject; + +/** + * Resolve possible deployments from the Maven project dependencies. + */ +class DeploymentResolution { + + private static final String WAR = "war"; + private static final String EAR = "ear"; + private static final String RAR = "rar"; + private static final String JAR = "jar"; + private static final Set SUPPORTED_DEPLOYMENT_TYPES = Set.of(EAR, JAR, RAR, WAR); + + static DeploymentResolution getInstance(MavenProject project) throws MojoExecutionException { + return new DeploymentResolution(project); + } + + private final Map files = new HashMap<>(); + + private DeploymentResolution(MavenProject project) throws MojoExecutionException { + for (Artifact artifact : project.getArtifacts()) { + if (SUPPORTED_DEPLOYMENT_TYPES.contains(artifact.getType())) { + files.put(buildKey(artifact.getGroupId(), artifact.getArtifactId(), + artifact.getClassifier(), artifact.getType()), artifact.getFile()); + } + } + } + + File getFile(final String groupId, final String artifactId, final String classifier, + final String type) throws MojoExecutionException { + return files.get(buildKey(groupId, artifactId, classifier, type)); + } + + private String buildKey(String groupId, String artifactId, String classifier, String type) throws MojoExecutionException { + if (groupId == null) { + throw new MojoExecutionException("Deployment groupId can't be null"); + } + if (artifactId == null) { + throw new MojoExecutionException("Deployment artifactId can't be null"); + } + if (type == null) { + throw new MojoExecutionException("Deployment type can't be null"); + } + if (!SUPPORTED_DEPLOYMENT_TYPES.contains(type)) { + throw new MojoExecutionException( + "Deployment type " + type + " is not supported. Supported types are " + SUPPORTED_DEPLOYMENT_TYPES); + } + return groupId + ":" + artifactId + ":" + (classifier == null ? "" : classifier) + ":" + type; + } +} diff --git a/plugin/src/main/java/org/wildfly/plugin/provision/GlowConfig.java b/plugin/src/main/java/org/wildfly/plugin/provision/GlowConfig.java index 0ac31a1a..2d987f62 100644 --- a/plugin/src/main/java/org/wildfly/plugin/provision/GlowConfig.java +++ b/plugin/src/main/java/org/wildfly/plugin/provision/GlowConfig.java @@ -33,9 +33,8 @@ public class GlowConfig { public GlowConfig() { } - public Arguments toArguments(Path deployment, Path inProvisioning, String layersConfigurationFileName) { + public Arguments toArguments(List lst, Path inProvisioning, String layersConfigurationFileName) { final Set profiles = profile != null ? Set.of(profile) : Set.of(); - List lst = List.of(deployment); Builder builder = Arguments.scanBuilder().setExecutionContext(context).setExecutionProfiles(profiles) .setUserEnabledAddOns(addOns).setBinaries(lst).setSuggest(suggest).setJndiLayers(getLayersForJndi()) .setVersion(version) diff --git a/plugin/src/main/java/org/wildfly/plugin/provision/PackageServerMojo.java b/plugin/src/main/java/org/wildfly/plugin/provision/PackageServerMojo.java index 47b9a656..bdcb0858 100644 --- a/plugin/src/main/java/org/wildfly/plugin/provision/PackageServerMojo.java +++ b/plugin/src/main/java/org/wildfly/plugin/provision/PackageServerMojo.java @@ -17,7 +17,10 @@ import java.nio.file.StandardCopyOption; import java.util.ArrayList; import java.util.Collections; +import java.util.LinkedHashMap; import java.util.List; +import java.util.Map; +import java.util.Map.Entry; import javax.inject.Inject; @@ -31,6 +34,7 @@ import org.jboss.galleon.api.GalleonBuilder; import org.jboss.galleon.api.config.GalleonProvisioningConfig; import org.jboss.galleon.maven.plugin.util.MvnMessageWriter; +import org.jboss.galleon.universe.maven.MavenUniverseException; import org.jboss.galleon.util.IoUtils; import org.wildfly.glow.ScanResults; import org.wildfly.plugin.cli.BaseCommandConfiguration; @@ -170,7 +174,7 @@ public class PackageServerMojo extends AbstractProvisionServerMojo { private boolean skip; /** - * Skip deploying the deployment after the server is provisioned ({@code false} by default). + * Skip deploying the deployments after the server is provisioned ({@code false} by default). */ @Parameter(defaultValue = "false", property = PropertyNames.SKIP_PACKAGE_DEPLOYMENT) protected boolean skipDeployment; @@ -256,10 +260,34 @@ public class PackageServerMojo extends AbstractProvisionServerMojo { @Parameter(alias = "bootable-jar-install-artifact-classifier", property = PropertyNames.BOOTABLE_JAR_INSTALL_CLASSIFIER, defaultValue = BootableJarSupport.BOOTABLE_SUFFIX) private String bootableJarInstallArtifactClassifier; + /** + * A list of deployments to deploy. + * A deployment is expected to be a Maven project dependency. The dependency type must be one of the following types: + * {@code ear}, {@code jar}, {@code rar} or {@code war}. + * If the deployment is not found or if the type is not supported, an exception is thrown. + * If no deployment name is specified, the name of the resolved artifact file is used. + * + *
+     *   <deployments>
+     *     <deployment>
+     *       <groupId>deployment groupId</groupId>
+     *       <artifactId>deployment artifactId</artifactId>
+     *       <type>ear|jar|rar|war</type>
+     *       <classifier>Optional classifier</classifier>
+     *       <name>Optional deployment name</name>
+     *     </deployment>
+     *   </deployments>
+     * 
+ */ + @Parameter(alias = "deployments", required = false) + private List deployments = new ArrayList<>(); + @Inject private OfflineCommandExecutor commandExecutor; private GalleonProvisioningConfig config; + private Map deploymentPaths; + private DeploymentResolution deploymentResolution; @Override protected GalleonProvisioningConfig getDefaultConfig() throws ProvisioningException { @@ -274,13 +302,22 @@ protected GalleonProvisioningConfig buildGalleonConfig(GalleonBuilder pm) return config; } try { + List allDeployments = new ArrayList<>(); + Path primaryDeployment = getDeploymentContent(); + if (primaryDeployment != null) { + allDeployments.add(primaryDeployment); + } + Map extraDeps = getDeployments(); + if (!extraDeps.isEmpty()) { + allDeployments.addAll(extraDeps.values()); + } try (ScanResults results = Utils.scanDeployment(discoverProvisioningInfo, layers, excludedLayers, featurePacks, dryRun, getLog(), - getDeploymentContent(), + allDeployments, artifactResolver, Paths.get(project.getBuild().getDirectory()), pm, @@ -305,9 +342,46 @@ public void execute() throws MojoExecutionException, MojoFailureException { getLog().debug(String.format("Skipping " + getGoal() + " of %s:%s", project.getGroupId(), project.getArtifactId())); return; } + deploymentResolution = DeploymentResolution.getInstance(project); super.execute(); } + private void deploy(Path deploymentContent, String targetName) throws MojoDeploymentException { + if (Files.exists(deploymentContent)) { + Path standaloneDeploymentDir = Path.of(provisioningDir, "standalone", "deployments"); + if (!standaloneDeploymentDir.isAbsolute()) { + standaloneDeploymentDir = Path.of(project.getBuild().getDirectory()).resolve(standaloneDeploymentDir); + } + try { + Path deploymentTarget = standaloneDeploymentDir.resolve(targetName); + getLog().info("Copy deployment " + deploymentContent + " to " + deploymentTarget); + Files.copy(deploymentContent, deploymentTarget, StandardCopyOption.REPLACE_EXISTING); + } catch (IOException e) { + throw new MojoDeploymentException("Could not copy deployment in provisioned server", e); + } + } else { + getLog().warn("The file " + deploymentContent + " doesn't exist, it will be not deployed."); + } + } + + private Map getDeployments() throws MavenUniverseException, MojoExecutionException { + if (deploymentPaths == null) { + deploymentPaths = new LinkedHashMap<>(); + for (DeploymentConfiguration c : deployments) { + Path p; + File f = deploymentResolution.getFile(c.getGroupId(), c.getArtifactId(), c.getClassifier(), + c.getType()); + if (f == null) { + throw new MojoExecutionException("Deployment not found " + c); + } + p = f.toPath(); + String deploymentName = c.getName() == null ? p.getFileName().toString() : c.getName(); + deploymentPaths.put(deploymentName, p); + } + } + return deploymentPaths; + } + @Override protected void serverProvisioned(Path jbossHome) throws MojoExecutionException, MojoFailureException { try { @@ -325,19 +399,18 @@ protected void serverProvisioned(Path jbossHome) throws MojoExecutionException, } if (!skipDeployment) { - final Path deploymentContent = getDeploymentContent(); - if (Files.exists(deploymentContent)) { - Path standaloneDeploymentDir = Path.of(provisioningDir, "standalone", "deployments"); - if (!standaloneDeploymentDir.isAbsolute()) { - standaloneDeploymentDir = Path.of(project.getBuild().getDirectory()).resolve(standaloneDeploymentDir); - } - try { - Path deploymentTarget = standaloneDeploymentDir.resolve(getDeploymentTargetName()); - getLog().info("Copy deployment " + deploymentContent + " to " + deploymentTarget); - Files.copy(deploymentContent, deploymentTarget, StandardCopyOption.REPLACE_EXISTING); - } catch (IOException e) { - throw new MojoDeploymentException("Could not copy deployment in provisioned server", e); + Path primaryDeployment = getDeploymentContent(); + if (primaryDeployment != null) { + deploy(primaryDeployment, getDeploymentTargetName()); + } + // Handle extra deployments + try { + Map extraPaths = getDeployments(); + for (Entry p : extraPaths.entrySet()) { + deploy(p.getValue(), p.getKey()); } + } catch (Exception ex) { + throw new MojoExecutionException(ex.getLocalizedMessage(), ex); } } @@ -492,6 +565,9 @@ private void warnExtraConfig(Path extraContentDir) { protected Path getDeploymentContent() throws MojoExecutionException { final PackageType packageType = PackageType.resolve(project); + if (packageType.getPackaging().equals("pom")) { + return null; + } final String filename; if (this.filename == null) { filename = String.format("%s.%s", project.getBuild().getFinalName(), packageType.getFileExtension()); @@ -522,4 +598,4 @@ private static void cleanupServer(Path jbossHome) throws IOException { IoUtils.recursiveDelete(log); } -} \ No newline at end of file +} diff --git a/plugin/src/site/markdown/package-example.md.vm b/plugin/src/site/markdown/package-example.md.vm index 7e7ef295..e41244ec 100644 --- a/plugin/src/site/markdown/package-example.md.vm +++ b/plugin/src/site/markdown/package-example.md.vm @@ -49,6 +49,94 @@ The example below shows how to produce the latest released ${appServerName} serv ``` +#[[##]]# [WildFly Glow](https://github.com/wildfly/wildfly-glow) integration + +You can configure the plugin to discover the Galleon configuration. Galleon feature-packs and layers required by your deployment(s) +are discovered from the deployment(s) binary file(s). + +This [documentation](https://docs.wildfly.org/wildfly-glow/) contains more information on WildFly Glow and the plugin configuration. + +Provisioning of a server with discovery enabled. +In this example the primary deployment is analyzed to produce the server: + +```xml + + ... + + ... + + ... + + ${project.groupId} + ${project.artifactId} + ${project.version} + + + + + + + package + + + + + ... + + ... + +... + +``` + +In this example the primary deployment and an additional deployment are analyzed to produce the server: + +```xml + + ... + + + org.example + example + 1.0.0.Final + war + + + ... + + ... + + ... + + ${project.groupId} + ${project.artifactId} + ${project.version} + + + + org.example + example + war + + + + + + + + package + + + + + ... + + ... + +... + +``` + #[[##]]# Galleon options You have the ability to set some optional Galleon options when provisioning a WildFly Server. @@ -183,7 +271,66 @@ In this example we are using the special 'ROOT.war' runtime-name to reference th jaxrs-server - ROOT.war + ROOT.war + + + + + package + + + + + ... + + ... + +... + +``` + +#[[##]]# Deploying multiple deployments + +By default a single deployment is deployed to the provisioned server. You can add additional deployments by adding them to +the project dependencies and configure them in the plugin configuration. + +```xml + + ... + + + org.example + example + 1.0.0.Final + war + + + ... + + ... + + ... + + ${project.groupId} + ${project.artifactId} + ${project.version} + + + + org.example + example + war + + + + + wildfly@maven(org.jboss.universe:community-universe) + + + + jaxrs-server + + ROOT.war diff --git a/tests/standalone-tests/src/test/java/org/wildfly/plugin/provision/PackageTest.java b/tests/standalone-tests/src/test/java/org/wildfly/plugin/provision/PackageTest.java index f35a602d..481f8d99 100644 --- a/tests/standalone-tests/src/test/java/org/wildfly/plugin/provision/PackageTest.java +++ b/tests/standalone-tests/src/test/java/org/wildfly/plugin/provision/PackageTest.java @@ -97,4 +97,27 @@ public void testInvalidDeployment2() throws Exception { + "A runtime-name has been set that indicates that a deployment is expected. ")); } } + + @Test + public void testMultipleDeploymentsPackage() throws Exception { + final Mojo packageMojo = lookupConfiguredMojo( + AbstractWildFlyMojoTest.getPomFile("package-multiple-deployments-pom.xml").toFile(), "package"); + String[] layers = { "jaxrs-server" }; + packageMojo.execute(); + Path jbossHome = AbstractWildFlyMojoTest.getBaseDir().resolve("target").resolve("packaged-multiple-deployments-server"); + checkStandaloneWildFlyHome(jbossHome, 2, layers, null, true); + } + + @Test + public void testMultipleDeploymentsInvalidPackage() throws Exception { + final Mojo packageMojo = lookupConfiguredMojo( + AbstractWildFlyMojoTest.getPomFile("package-multiple-deployments-invalid-pom.xml").toFile(), "package"); + try { + packageMojo.execute(); + throw new Exception("Execution should have failed"); + } catch (MojoExecutionException ex) { + // XXX OK, expected. + Assert.assertTrue(ex.getLocalizedMessage().contains("Deployment not found org.foo:bar:war")); + } + } } diff --git a/tests/standalone-tests/src/test/resources/test-project/package-multiple-deployments-invalid-pom.xml b/tests/standalone-tests/src/test/resources/test-project/package-multiple-deployments-invalid-pom.xml new file mode 100644 index 00000000..5ec95f56 --- /dev/null +++ b/tests/standalone-tests/src/test/resources/test-project/package-multiple-deployments-invalid-pom.xml @@ -0,0 +1,42 @@ + + + + 4.0.0 + testing + testing + 0.1.0-SNAPSHOT + + + + + org.wildfly.plugins + wildfly-maven-plugin + + test.war + true + packaged-multiple-deployments-invalid-server + + + org.foo + bar + war + + + + + wildfly@maven(org.jboss.universe:community-universe)#WF_VERSION + + + + jaxrs-server + + + + + + + \ No newline at end of file diff --git a/tests/standalone-tests/src/test/resources/test-project/package-multiple-deployments-pom.xml b/tests/standalone-tests/src/test/resources/test-project/package-multiple-deployments-pom.xml new file mode 100644 index 00000000..1f1af20a --- /dev/null +++ b/tests/standalone-tests/src/test/resources/test-project/package-multiple-deployments-pom.xml @@ -0,0 +1,50 @@ + + + + 4.0.0 + testing + testing + 0.1.0-SNAPSHOT + + + testing + dummy + 1.0 + system + ${basedir}/dummy.jar + + + + + + org.wildfly.plugins + wildfly-maven-plugin + + test.war + true + packaged-multiple-deployments-server + + + testing + dummy + jar + + + + + wildfly@maven(org.jboss.universe:community-universe)#WF_VERSION + + + + jaxrs-server + + + + + + + \ No newline at end of file