diff --git a/pom.xml b/pom.xml index 54a6976..7d364f9 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.inteligr8.wildfly wildfly-module-plugin - 1.0-SNAPSHOT + 2.0-SNAPSHOT maven-plugin A Maven plugin for Wildfly Module handling diff --git a/src/main/java/com/inteligr8/wildfly/maven/DependencyAwareComponent.java b/src/main/java/com/inteligr8/wildfly/maven/DependencyAwareComponent.java index 1365bd5..5ae21ac 100644 --- a/src/main/java/com/inteligr8/wildfly/maven/DependencyAwareComponent.java +++ b/src/main/java/com/inteligr8/wildfly/maven/DependencyAwareComponent.java @@ -19,6 +19,7 @@ import org.apache.maven.model.building.ModelBuilder; import org.apache.maven.plugin.logging.Log; import org.apache.maven.project.MavenProject; import org.apache.maven.project.ProjectModelResolver; +import org.eclipse.aether.impl.ArtifactResolver; /** * @author brian@inteligr8.com @@ -33,6 +34,8 @@ public interface DependencyAwareComponent { ProjectModelResolver getProjectModelResolver(); + ArtifactResolver getArtifactResolver(); + ModelBuilder getModelBuilder(); } diff --git a/src/main/java/com/inteligr8/wildfly/maven/DependencyIndex.java b/src/main/java/com/inteligr8/wildfly/maven/DependencyIndex.java index 0677ca0..4acd9f0 100644 --- a/src/main/java/com/inteligr8/wildfly/maven/DependencyIndex.java +++ b/src/main/java/com/inteligr8/wildfly/maven/DependencyIndex.java @@ -25,6 +25,12 @@ import org.eclipse.aether.graph.DependencyNode; import com.inteligr8.wildfly.maven.model.Module; +/** + * This class indexes dependencies by their ID (sans version). It also stores + * other metadata determined by other executions within this library. + * + * @author brian@inteligr8.com + */ public class DependencyIndex { public enum DependencyType { @@ -36,27 +42,40 @@ public class DependencyIndex { Other } - private final Map id2node = new HashMap<>(); + private final Map id2node = new HashMap<>(); private final Map id2type = new HashMap<>(); private final Map id2module = new HashMap<>(); private final Map id2accept = new HashMap<>(); private final Set id2topModule = new HashSet<>(); public String index(DependencyNode node) { - String id = this.toId(node); - this.id2node.put(id, node); + return this.index(node.getArtifact()); + } + + public String index(Artifact artifact) { + String id = this.toId(artifact); + if (!this.id2node.containsKey(id)) + this.id2node.put(id, artifact); return id; } public void indexAcceptance(String id, boolean accept) { - this.id2accept.put(id, accept); + this.id2accept.put(id, accept && Boolean.TRUE.equals(this.id2accept.get(id))); } public void indexType(String id, DependencyType dtype) { - this.id2type.put(id, dtype); + DependencyType existing = this.id2type.get(id); + if (existing == null) { + this.id2type.put(id, dtype); + } else if (dtype.compareTo(existing) < 0) { + this.id2type.put(id, dtype); + } } public void indexModule(String id, Module module) { + Module existing = this.id2module.get(id); + if (existing != null && !existing.equals(module)) + throw new IllegalStateException(); this.id2module.put(id, module); } diff --git a/src/main/java/com/inteligr8/wildfly/maven/IndexingDependencyGraphTransformer.java b/src/main/java/com/inteligr8/wildfly/maven/IndexingDependencyGraphTransformer.java index e01b632..4f36804 100644 --- a/src/main/java/com/inteligr8/wildfly/maven/IndexingDependencyGraphTransformer.java +++ b/src/main/java/com/inteligr8/wildfly/maven/IndexingDependencyGraphTransformer.java @@ -16,21 +16,34 @@ package com.inteligr8.wildfly.maven; import java.util.Collections; import java.util.List; +import java.util.Set; import java.util.Stack; +import org.apache.maven.artifact.Artifact; import org.apache.maven.model.building.ModelBuildingException; import org.apache.maven.model.resolution.UnresolvableModelException; import org.eclipse.aether.RepositoryException; +import org.eclipse.aether.artifact.DefaultArtifact; import org.eclipse.aether.collection.DependencyGraphTransformationContext; import org.eclipse.aether.collection.DependencyGraphTransformer; +import org.eclipse.aether.graph.DependencyFilter; import org.eclipse.aether.graph.DependencyNode; +import org.eclipse.aether.resolution.ArtifactRequest; +import org.eclipse.aether.resolution.ArtifactResolutionException; +import org.eclipse.aether.resolution.ArtifactResult; import org.eclipse.aether.util.artifact.JavaScopes; +import org.eclipse.aether.util.filter.DependencyFilterUtils; +import org.eclipse.aether.util.filter.ScopeDependencyFilter; import com.inteligr8.wildfly.maven.DependencyIndex.DependencyType; import com.inteligr8.wildfly.maven.model.Module; public class IndexingDependencyGraphTransformer implements DependencyGraphTransformer { + private final DependencyFilter filter = DependencyFilterUtils.andFilter( + new ScopeDependencyFilter("test") + ); + private final DependencyAwareComponent dac; private final DependencyGraphTransformer transfomer; private final DependencyIndex dindex; @@ -64,6 +77,9 @@ public class IndexingDependencyGraphTransformer implements DependencyGraphTransf * @param ancestors A stack of ancestral artifacts; parent on top; root on bottom; empty if root. */ private void crawl(DependencyNode node, Stack ancestors) { + if (!this.filter.accept(node, ancestors)) + return; + this.index(node, Collections.unmodifiableList(ancestors)); ancestors.push(node); @@ -83,12 +99,8 @@ public class IndexingDependencyGraphTransformer implements DependencyGraphTransf */ public void index(DependencyNode node, List parents) { String nodeId = this.dindex.toId(node); - DependencyType type = this.dindex.getType(nodeId); - if (type != null) { - if (this.dac.getLog().isDebugEnabled()) - this.dac.getLog().debug(nodeId + ": already determined type: " + type); - return; - } + if (this.dac.getLog().isDebugEnabled()) + this.dac.getLog().debug("Indexing: " + nodeId); this.dindex.index(node); @@ -101,7 +113,7 @@ public class IndexingDependencyGraphTransformer implements DependencyGraphTransf for (DependencyNode ancestor : parents) { String ancestorId = this.dindex.toId(ancestor); - type = this.dindex.getType(ancestorId); + DependencyType type = this.dindex.getType(ancestorId); if (type == null) throw new IllegalStateException("The dependency parents are expected to be processed before the children"); @@ -134,10 +146,17 @@ public class IndexingDependencyGraphTransformer implements DependencyGraphTransf this.dindex.indexType(nodeId, module.isSystem ? DependencyType.SystemModule : DependencyType.Module); this.dindex.indexModule(nodeId, module); this.dindex.indexTopLevelModule(nodeId); + + if (node.getArtifact().getClassifier().length() > 0) { + String shadowedNodeId = node.getArtifact().getGroupId() + ":" + node.getArtifact().getArtifactId() + ":jar"; + if (this.dac.getLog().isDebugEnabled()) + this.dac.getLog().debug("Indexing shadowed node: " + shadowedNodeId); + this.dindex.indexType(shadowedNodeId, DependencyType.InModule); + } } else { this.dindex.indexType(nodeId, DependencyType.Other); } - } catch (UnresolvableModelException | ModelBuildingException e) { + } catch (UnresolvableModelException | ModelBuildingException | ArtifactResolutionException e) { this.dac.getLog().warn("Filtering out dependency '" + node.getDependency() + "' due to exception", e); } } diff --git a/src/main/java/com/inteligr8/wildfly/maven/ModuleArtifactExtractor.java b/src/main/java/com/inteligr8/wildfly/maven/ModuleArtifactExtractor.java index 02383db..3d00201 100644 --- a/src/main/java/com/inteligr8/wildfly/maven/ModuleArtifactExtractor.java +++ b/src/main/java/com/inteligr8/wildfly/maven/ModuleArtifactExtractor.java @@ -24,10 +24,14 @@ import org.apache.maven.model.building.DefaultModelBuildingRequest; import org.apache.maven.model.building.ModelBuildingException; import org.apache.maven.model.building.ModelBuildingRequest; import org.apache.maven.model.building.ModelBuildingResult; -import org.apache.maven.model.building.ModelSource; import org.apache.maven.model.resolution.UnresolvableModelException; import org.apache.maven.plugin.logging.Log; import org.eclipse.aether.artifact.Artifact; +import org.eclipse.aether.artifact.ArtifactType; +import org.eclipse.aether.artifact.DefaultArtifact; +import org.eclipse.aether.resolution.ArtifactRequest; +import org.eclipse.aether.resolution.ArtifactResolutionException; +import org.eclipse.aether.resolution.ArtifactResult; import com.inteligr8.wildfly.maven.model.Module; @@ -47,7 +51,7 @@ public class ModuleArtifactExtractor { } public Module extract(Artifact artifact) - throws UnresolvableModelException, ModelBuildingException { + throws UnresolvableModelException, ModelBuildingException, ArtifactResolutionException { if (this.getLog().isDebugEnabled()) this.getLog().debug("Inspecting artifact POM: " + artifact); @@ -61,13 +65,16 @@ public class ModuleArtifactExtractor { module.isSystem = Boolean.parseBoolean(artifact.getProperty("isSystem", Boolean.FALSE.toString())); return module; } - - ModelSource source = this.dac.getProjectModelResolver().resolveModel(artifact.getGroupId(), artifact.getArtifactId(), artifact.getVersion()); + + // need to go after the artifact as there could be a classifier + Artifact pomArtifact = new DefaultArtifact(artifact.getGroupId(), artifact.getArtifactId(), artifact.getClassifier(), "pom", artifact.getVersion()); + ArtifactRequest artifactRequest = new ArtifactRequest(pomArtifact, this.dac.getMavenProject().getRemoteProjectRepositories(), null); + ArtifactResult artifactResult = this.dac.getArtifactResolver().resolveArtifact(this.dac.getMavenSession().getRepositorySession(), artifactRequest); if (this.getLog().isDebugEnabled()) - this.getLog().debug("Found artifact POM [" + artifact + "]: " + source.getLocation()); + this.getLog().debug("Found artifact POM [" + artifact + "]: " + artifactResult.getArtifact().getFile()); DefaultModelBuildingRequest modelBuildRequest = new DefaultModelBuildingRequest(this.modelBuildRequestTemplate) - .setModelSource(source); + .setPomFile(artifactResult.getArtifact().getFile()); ModelBuildingResult result = this.dac.getModelBuilder().build(modelBuildRequest); if (this.getLog().isDebugEnabled()) this.getLog().debug("Parsed artifact POM [" + artifact + "]: " + result.getModelIds()); diff --git a/src/main/java/com/inteligr8/wildfly/maven/ModuleExclusionDependencyFilter.java b/src/main/java/com/inteligr8/wildfly/maven/ModuleExclusionDependencyFilter.java index b059315..ab6d394 100644 --- a/src/main/java/com/inteligr8/wildfly/maven/ModuleExclusionDependencyFilter.java +++ b/src/main/java/com/inteligr8/wildfly/maven/ModuleExclusionDependencyFilter.java @@ -68,6 +68,11 @@ public class ModuleExclusionDependencyFilter implements DependencyFilter { return false; } + if (this.dindex.getType(nodeId) == null) { + this.dac.getLog().warn(nodeId + ": missing from index"); + return false; + } + switch (this.dindex.getType(nodeId)) { case SystemModule: case Module: diff --git a/src/main/java/com/inteligr8/wildfly/maven/ValidationDependencyFilter.java b/src/main/java/com/inteligr8/wildfly/maven/ValidationDependencyFilter.java index 7744d6d..cb196ed 100644 --- a/src/main/java/com/inteligr8/wildfly/maven/ValidationDependencyFilter.java +++ b/src/main/java/com/inteligr8/wildfly/maven/ValidationDependencyFilter.java @@ -14,9 +14,7 @@ */ package com.inteligr8.wildfly.maven; -import java.util.HashSet; import java.util.List; -import java.util.Set; import org.eclipse.aether.graph.DependencyFilter; import org.eclipse.aether.graph.DependencyNode; @@ -27,7 +25,6 @@ public class ValidationDependencyFilter implements DependencyFilter { private final DependencyAwareComponent dac; private final DependencyIndex dindex; - private final Set moduleHasNonPom = new HashSet<>(); public ValidationDependencyFilter(DependencyAwareComponent dac, DependencyIndex dindex) { this.dac = dac; @@ -41,45 +38,34 @@ public class ValidationDependencyFilter implements DependencyFilter { return true; } - String parentId = null; - if (parents.size() == 1) { - parentId = this.dindex.toId(parents.iterator().next()); - } else { - DependencyNode parent = parents.iterator().next(); - parentId = this.dindex.toId(parent); - + for (DependencyNode parent : parents) { + String parentId = this.dindex.toId(parent); + DependencyType type = this.dindex.getType(parentId); - if (type == null) - throw new IllegalStateException("The dependency parent is expected to be processed before its children"); + if (type == null) { + switch (parent.getDependency().getScope()) { + case "test": + this.dac.getLog().debug("The dependency parent was excluded as a test artifact: " + parent); + default: + } + + continue; + } switch (type) { case Module: case SystemModule: if (this.dac.getLog().isDebugEnabled()) this.dac.getLog().debug(parentId + " is a module"); - break; + return true; default: // ignore if the node isn't a module return true; } } - - this.validateDependencyOrder(node, parentId); - return true; - } - - private void validateDependencyOrder(DependencyNode node, String parentId) { - String ext = node.getArtifact().getExtension(); - if (this.moduleHasNonPom.contains(parentId)) { - if ("pom".equalsIgnoreCase(ext)) { - this.dac.getLog().warn("Wildfly module dependency found after non-module dependency: " + node.getArtifact()); - this.dac.getLog().info("Dependency order impacts library exclusion from packaging"); - } - } else if (!"pom".equalsIgnoreCase(ext)) { - if (this.dac.getLog().isDebugEnabled()) - this.dac.getLog().debug("The project itself or module has a non-pom: " + node.getArtifact()); - this.moduleHasNonPom.add(parentId); - } + + this.dac.getLog().error("None of the dependency parents were processed before the artifact: " + node.getDependency()); + return false; } } diff --git a/src/main/java/com/inteligr8/wildfly/maven/goal/AbstractDeploymentGoal.java b/src/main/java/com/inteligr8/wildfly/maven/goal/AbstractDeploymentGoal.java index e4e34a0..91d0ab2 100644 --- a/src/main/java/com/inteligr8/wildfly/maven/goal/AbstractDeploymentGoal.java +++ b/src/main/java/com/inteligr8/wildfly/maven/goal/AbstractDeploymentGoal.java @@ -14,19 +14,8 @@ */ package com.inteligr8.wildfly.maven.goal; -import java.io.BufferedOutputStream; import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.nio.file.FileVisitResult; -import java.nio.file.FileVisitor; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.attribute.BasicFileAttributes; -import java.util.zip.ZipEntry; -import java.util.zip.ZipOutputStream; -import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugins.annotations.Parameter; /** @@ -37,81 +26,15 @@ public abstract class AbstractDeploymentGoal extends AbstractGoal { @Parameter( required = true, defaultValue = "1.3" ) protected String deploymentSchemaVersion; - @Parameter( property = "wildfly.deployment.outputDirectory", required = true, defaultValue = "${project.build.directory}/${project.build.finalName}" ) - protected File outputDirectory; - + @Parameter( property = "wildfly.deployment.packaging", required = true, defaultValue = "${project.packaging}" ) + protected String packaging; + protected File validateAndInitializeDirectory(String extraPath) { - File directory = this.validateAndInitializeDirectory(this.outputDirectory); - - File extraDirectory = new File(directory, extraPath); - if (extraDirectory.exists() && !extraDirectory.isDirectory()) - throw new IllegalStateException("The formulated directory is a file: " + extraDirectory); - - extraDirectory.mkdirs(); - return extraDirectory; + return this.directoryAccessor.validateAndInitializeDirectory(this.outputDirectory, extraPath); } - - protected void writePackage(String ext) throws MojoExecutionException { - File zipfile = new File(this.project.getBuild().getDirectory(), this.project.getBuild().getFinalName() + "." + ext); - try { - FileOutputStream fostream = new FileOutputStream(zipfile); - try { - BufferedOutputStream bostream = new BufferedOutputStream(fostream); - ZipOutputStream zostream = new ZipOutputStream(bostream); - try { - this.zipModule(zostream); - } finally { - zostream.close(); - } - } finally { - fostream.close(); - } - } catch (IOException ie) { - throw new MojoExecutionException("An I/O issue occurred", ie); - } - - this.project.getArtifact().setFile(zipfile); - } - - private void zipModule(ZipOutputStream zostream) throws IOException { - Path path = this.outputDirectory.toPath(); - if (getLog().isDebugEnabled()) - getLog().debug("Zipping files in: " + path); - - Files.walkFileTree(path, new FileVisitor() { - @Override - public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) { - return FileVisitResult.CONTINUE; - } - - @Override - public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException { - if (exc == null) return FileVisitResult.CONTINUE; - throw exc; - } - - @Override - public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { - Path zippath = path.relativize(file); - if (getLog().isDebugEnabled()) - getLog().debug("Zipping file: " + zippath); - - ZipEntry zentry = new ZipEntry(zippath.toString().replace('\\', '/')); - zostream.putNextEntry(zentry); - try { - Files.copy(file, zostream); - } finally { - zostream.closeEntry(); - } - - return FileVisitResult.CONTINUE; - } - - @Override - public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException { - throw exc; - } - }); + + protected boolean isWebApp() { + return "war".equals(this.packaging); } } diff --git a/src/main/java/com/inteligr8/wildfly/maven/goal/AbstractGoal.java b/src/main/java/com/inteligr8/wildfly/maven/goal/AbstractGoal.java index 3decb26..8b37787 100644 --- a/src/main/java/com/inteligr8/wildfly/maven/goal/AbstractGoal.java +++ b/src/main/java/com/inteligr8/wildfly/maven/goal/AbstractGoal.java @@ -17,9 +17,12 @@ package com.inteligr8.wildfly.maven.goal; import java.io.File; import java.util.Arrays; import java.util.Collection; +import java.util.Collections; import java.util.HashSet; import java.util.Set; +import javax.inject.Inject; + import org.apache.maven.execution.MavenSession; import org.apache.maven.model.building.ModelBuilder; import org.apache.maven.plugin.MojoExecutionException; @@ -43,13 +46,17 @@ import org.eclipse.aether.impl.ArtifactResolver; import org.eclipse.aether.impl.RemoteRepositoryManager; import org.eclipse.aether.util.artifact.JavaScopes; import org.eclipse.aether.util.filter.DependencyFilterUtils; +import org.eclipse.aether.util.filter.ScopeDependencyFilter; import com.inteligr8.wildfly.maven.DependencyAwareComponent; import com.inteligr8.wildfly.maven.DependencyIndex; import com.inteligr8.wildfly.maven.IndexingDependencyGraphTransformer; +import com.inteligr8.wildfly.maven.ModuleExclusionDependencyFilter; import com.inteligr8.wildfly.maven.ModuleProvidedDependencyFilter; import com.inteligr8.wildfly.maven.ValidationDependencyFilter; +import com.inteligr8.wildfly.maven.ModuleExclusionDependencyFilter.Option; import com.inteligr8.wildfly.maven.model.Module; +import com.inteligr8.wildfly.maven.util.DirectoryAccessor; /** * @author brian@inteligr8.com @@ -61,6 +68,9 @@ public abstract class AbstractGoal extends DisablableGoal implements DependencyA @Parameter( defaultValue = "${project}", readonly = true ) protected MavenProject project; + + @Parameter( property = "wildfly.build.outputDirectory", required = true, defaultValue = "${project.build.directory}/wildfly" ) + protected File outputDirectory; @Requirement private RemoteRepositoryManager rrm; @@ -76,6 +86,9 @@ public abstract class AbstractGoal extends DisablableGoal implements DependencyA @Requirement private ProjectDependenciesResolver depResolver; + + @Inject + protected DirectoryAccessor directoryAccessor; protected ProjectModelResolver pomResolver; protected Set excludeScopes = new HashSet(Arrays.asList(JavaScopes.PROVIDED, JavaScopes.TEST)); @@ -126,6 +139,7 @@ public abstract class AbstractGoal extends DisablableGoal implements DependencyA DependencyIndex dindex) throws MojoFailureException, MojoExecutionException { return this.crawlDependencies(session, Arrays.asList( + new ScopeDependencyFilter("test"), new ValidationDependencyFilter(this, dindex), new ModuleProvidedDependencyFilter(this, dindex))); } @@ -169,12 +183,18 @@ public abstract class AbstractGoal extends DisablableGoal implements DependencyA this.handleModuleDependency(dependency, dindex.getModule(id)); break; default: - this.handleDependency(dependency); + if (!"pom".equals(dependency.getArtifact().getExtension())) + this.handleDependency(dependency); } } } - protected abstract Collection getDependencyFilters(DependencyIndex dindex); + protected Collection getDependencyFilters(DependencyIndex dindex) { + return Arrays.asList( + new ScopeDependencyFilter("test", "provided"), + // this filter will remove all Wildfly Module dependencies, recursively + new ModuleExclusionDependencyFilter(this, dindex, Option.FilterTopLevelModuleChildren)); + } protected abstract void executePre() throws MojoExecutionException, MojoFailureException; @@ -203,13 +223,10 @@ public abstract class AbstractGoal extends DisablableGoal implements DependencyA public ModelBuilder getModelBuilder() { return this.pomBuilder; } - - protected File validateAndInitializeDirectory(File directory) { - if (directory.exists() && !directory.isDirectory()) - throw new IllegalArgumentException("A directory was expected: " + directory); - - directory.mkdirs(); - return directory; + + @Override + public ArtifactResolver getArtifactResolver() { + return artifactResolver; } } diff --git a/src/main/java/com/inteligr8/wildfly/maven/goal/AbstractModuleGoal.java b/src/main/java/com/inteligr8/wildfly/maven/goal/AbstractModuleGoal.java index 9ddd265..e1df351 100644 --- a/src/main/java/com/inteligr8/wildfly/maven/goal/AbstractModuleGoal.java +++ b/src/main/java/com/inteligr8/wildfly/maven/goal/AbstractModuleGoal.java @@ -32,24 +32,8 @@ public abstract class AbstractModuleGoal extends AbstractGoal { @Parameter( property = "wildfly.module.version", required = true, defaultValue = "main" ) protected String moduleVersion; - @Parameter( property = "wildfly.module.outputDirectory", required = true, defaultValue = "${project.build.directory}/wildfly-module" ) - protected File outputDirectory; - protected File validateAndInitializeDirectory() { - File directory = this.validateAndInitializeDirectory(this.outputDirectory); - - for (String dir : this.moduleId.split("\\.")) { - directory = new File(directory, dir); - if (directory.exists() && !directory.isDirectory()) - throw new IllegalStateException("The formulated directory contains a file: " + directory); - } - - File versionDirectory = new File(directory, this.moduleVersion); - if (versionDirectory.exists() && !versionDirectory.isDirectory()) - throw new IllegalStateException("The formulated directory contains a file: " + directory); - - versionDirectory.mkdirs(); - return versionDirectory; + return this.directoryAccessor.validateAndInitializeDirectory(this.outputDirectory, this.moduleId, this.moduleVersion); } } diff --git a/src/main/java/com/inteligr8/wildfly/maven/goal/WarGoal.java b/src/main/java/com/inteligr8/wildfly/maven/goal/CopyDeploymentResourcesGoal.java similarity index 53% rename from src/main/java/com/inteligr8/wildfly/maven/goal/WarGoal.java rename to src/main/java/com/inteligr8/wildfly/maven/goal/CopyDeploymentResourcesGoal.java index ba5a9bf..e23a969 100644 --- a/src/main/java/com/inteligr8/wildfly/maven/goal/WarGoal.java +++ b/src/main/java/com/inteligr8/wildfly/maven/goal/CopyDeploymentResourcesGoal.java @@ -16,14 +16,9 @@ package com.inteligr8.wildfly.maven.goal; import java.io.File; import java.io.IOException; -import java.util.Arrays; -import java.util.Collection; import java.util.Collections; import java.util.List; -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.transform.TransformerException; - import org.apache.maven.model.Resource; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugins.annotations.LifecyclePhase; @@ -36,54 +31,42 @@ import org.codehaus.plexus.component.annotations.Component; import org.codehaus.plexus.component.annotations.Requirement; import org.codehaus.plexus.util.FileUtils; import org.eclipse.aether.graph.Dependency; -import org.eclipse.aether.graph.DependencyFilter; -import com.inteligr8.wildfly.maven.DependencyIndex; -import com.inteligr8.wildfly.maven.ModuleExclusionDependencyFilter; -import com.inteligr8.wildfly.maven.ModuleExclusionDependencyFilter.Option; import com.inteligr8.wildfly.maven.model.Module; -import com.inteligr8.wildfly.maven.xml.DeploymentXmlBuilder; /** * @author brian@inteligr8.com */ -@Mojo( name = "war", threadSafe = false, defaultPhase = LifecyclePhase.PACKAGE ) +@Mojo( name = "deployment-resources", threadSafe = false, defaultPhase = LifecyclePhase.PREPARE_PACKAGE ) @Component( role = org.apache.maven.plugin.Mojo.class ) -public class WarGoal extends AbstractDeploymentGoal { +public class CopyDeploymentResourcesGoal extends AbstractDeploymentGoal { - @Parameter( property = "wildfly.webapp.directory", required = true, defaultValue = "${basedir}/src/main/webapp" ) - protected File webappDirectory; + @Parameter( property = "wildfly.deployment.directory", required = false ) + protected File appDirectory; @Parameter protected List resources; @Requirement private MavenResourcesFiltering filterer; - - private DeploymentXmlBuilder deploymentXmlBuilder; - private File webinfDirectory; + private File libDirectory; + private File classesDirectory; @Override protected void executePre() throws MojoExecutionException { - try { - this.deploymentXmlBuilder = new DeploymentXmlBuilder(this.deploymentSchemaVersion); - } catch (ParserConfigurationException pce) { - throw new MojoExecutionException("This should never happen", pce); + if (this.isWebApp()) { + File webinfDirectory = this.directoryAccessor.validateAndInitializeDirectory(this.outputDirectory, "WEB-INF"); + this.libDirectory = this.directoryAccessor.validateAndInitializeDirectory(webinfDirectory, "lib"); + this.classesDirectory = this.directoryAccessor.validateAndInitializeDirectory(webinfDirectory, "classes"); + if (this.appDirectory == null) + this.appDirectory = this.directoryAccessor.validateAndInitializeDirectory(this.project.getBasedir(), "src/main/webapp"); + } else { + this.libDirectory = this.directoryAccessor.validateAndInitializeDirectory(this.outputDirectory); + this.classesDirectory = this.libDirectory; + if (this.appDirectory == null) + this.appDirectory = this.directoryAccessor.validateAndInitializeDirectory(this.project.getBasedir(), "src/main/app"); } - - this.webinfDirectory = this.validateAndInitializeDirectory("WEB-INF"); - this.libDirectory = new File(this.webinfDirectory, "lib"); - if (this.libDirectory.exists() && !this.libDirectory.isDirectory()) - throw new IllegalStateException("The formulated directory is a file: " + this.libDirectory); - this.libDirectory.mkdirs(); - } - - @Override - protected Collection getDependencyFilters(DependencyIndex dindex) { - return Arrays.asList( - // this filter will remove all Wildfly Module dependencies, recursively - new ModuleExclusionDependencyFilter(this, dindex, Option.FilterTopLevelModuleChildren)); } @Override @@ -100,36 +83,14 @@ public class WarGoal extends AbstractDeploymentGoal { @Override protected void handleModuleDependency(Dependency dependency, Module module) { - if (this.getLog().isInfoEnabled()) - this.getLog().info("Detected module dependency; adding reference to deployment: " + dependency.getArtifact() + " => " + module.id); - this.deploymentXmlBuilder.addDependency(module, true); } @Override public void executePost() throws MojoExecutionException { - this.writeDeploymentXml(); - this.copyResources(); - this.writePackage("war"); - } - - private void writeDeploymentXml() throws MojoExecutionException { - try { - this.deploymentXmlBuilder.writeTo(this.webinfDirectory); - } catch (TransformerException te) { - throw new MojoExecutionException("An XML to file transformation issue occurred", te); - } catch (IOException ie) { - throw new MojoExecutionException("An I/O issue occurred", ie); - } - } - - private void copyResources() throws MojoExecutionException { try { File classesSourceDirectory = new File(this.project.getBuild().getOutputDirectory()); - if (classesSourceDirectory.exists()) { - File classesTargetDirectory = new File(this.webinfDirectory, "classes"); - classesTargetDirectory.mkdirs(); - FileUtils.copyDirectoryStructure(classesSourceDirectory, classesTargetDirectory); - } + if (classesSourceDirectory.exists()) + FileUtils.copyDirectoryStructure(classesSourceDirectory, this.classesDirectory); if (this.resources != null) { MavenResourcesExecution execution = new MavenResourcesExecution( @@ -143,8 +104,8 @@ public class WarGoal extends AbstractDeploymentGoal { this.filterer.filterResources(execution); } - if (this.webappDirectory.exists()) - FileUtils.copyDirectoryStructure(this.webappDirectory, this.outputDirectory); + if (this.appDirectory.exists()) + FileUtils.copyDirectoryStructure(this.appDirectory, this.outputDirectory); } catch (MavenFilteringException mfe) { throw new MojoExecutionException("A filtering issue occurred", mfe); } catch (IOException ie) { diff --git a/src/main/java/com/inteligr8/wildfly/maven/goal/CopyModuleResourcesGoal.java b/src/main/java/com/inteligr8/wildfly/maven/goal/CopyModuleResourcesGoal.java index a2d233e..821c75a 100644 --- a/src/main/java/com/inteligr8/wildfly/maven/goal/CopyModuleResourcesGoal.java +++ b/src/main/java/com/inteligr8/wildfly/maven/goal/CopyModuleResourcesGoal.java @@ -26,6 +26,7 @@ import org.codehaus.plexus.component.annotations.Component; import org.codehaus.plexus.util.FileUtils; import org.eclipse.aether.graph.Dependency; import org.eclipse.aether.graph.DependencyFilter; +import org.eclipse.aether.util.filter.ScopeDependencyFilter; import com.inteligr8.wildfly.maven.DependencyIndex; import com.inteligr8.wildfly.maven.ModuleExclusionDependencyFilter; @@ -37,26 +38,18 @@ import com.inteligr8.wildfly.maven.model.Module; @Mojo( name = "module-resources", threadSafe = false, defaultPhase = LifecyclePhase.PREPARE_PACKAGE ) @Component( role = org.apache.maven.plugin.Mojo.class ) public class CopyModuleResourcesGoal extends AbstractModuleGoal { - - @Override - protected Collection getDependencyFilters(DependencyIndex dindex) { - return Arrays.asList( - // this filter will remove all Wildfly Module dependencies, recursively - new ModuleExclusionDependencyFilter(this, dindex)); - } + + private File moduleDirectory; @Override protected void executePre() { + this.moduleDirectory = this.validateAndInitializeDirectory(); } @Override protected void handleDependency(Dependency dependency) throws MojoExecutionException { - File directory = this.validateAndInitializeDirectory(); - if (!directory.isDirectory()) - throw new IllegalArgumentException(); - try { - FileUtils.copyFileToDirectory(dependency.getArtifact().getFile(), directory); + FileUtils.copyFileToDirectory(dependency.getArtifact().getFile(), this.moduleDirectory); } catch (IOException ie) { throw new MojoExecutionException("An I/O related issue occurred", ie); } @@ -70,7 +63,7 @@ public class CopyModuleResourcesGoal extends AbstractModuleGoal { } @Override - protected void executePost() { + protected void executePost() throws MojoExecutionException { } } diff --git a/src/main/java/com/inteligr8/wildfly/maven/goal/EarGoal.java b/src/main/java/com/inteligr8/wildfly/maven/goal/GenerateDeploymentXmlGoal.java similarity index 67% rename from src/main/java/com/inteligr8/wildfly/maven/goal/EarGoal.java rename to src/main/java/com/inteligr8/wildfly/maven/goal/GenerateDeploymentXmlGoal.java index dbac265..8e6ab92 100644 --- a/src/main/java/com/inteligr8/wildfly/maven/goal/EarGoal.java +++ b/src/main/java/com/inteligr8/wildfly/maven/goal/GenerateDeploymentXmlGoal.java @@ -16,8 +16,6 @@ package com.inteligr8.wildfly.maven.goal; import java.io.File; import java.io.IOException; -import java.util.Arrays; -import java.util.Collection; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.TransformerException; @@ -26,22 +24,16 @@ import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugins.annotations.LifecyclePhase; import org.apache.maven.plugins.annotations.Mojo; import org.codehaus.plexus.component.annotations.Component; -import org.codehaus.plexus.util.FileUtils; import org.eclipse.aether.graph.Dependency; -import org.eclipse.aether.graph.DependencyFilter; - -import com.inteligr8.wildfly.maven.DependencyIndex; -import com.inteligr8.wildfly.maven.ModuleExclusionDependencyFilter; -import com.inteligr8.wildfly.maven.ModuleExclusionDependencyFilter.Option; import com.inteligr8.wildfly.maven.model.Module; import com.inteligr8.wildfly.maven.xml.DeploymentXmlBuilder; /** * @author brian@inteligr8.com */ -@Mojo( name = "ear", threadSafe = false, defaultPhase = LifecyclePhase.PACKAGE ) +@Mojo( name = "deployment-generate-xml", threadSafe = false, defaultPhase = LifecyclePhase.GENERATE_RESOURCES ) @Component( role = org.apache.maven.plugin.Mojo.class ) -public class EarGoal extends AbstractDeploymentGoal { +public class GenerateDeploymentXmlGoal extends AbstractDeploymentGoal { private DeploymentXmlBuilder deploymentXmlBuilder; @@ -54,23 +46,8 @@ public class EarGoal extends AbstractDeploymentGoal { } } - @Override - protected Collection getDependencyFilters(DependencyIndex dindex) { - return Arrays.asList( - // this filter will remove all Wildfly Module dependencies, recursively - new ModuleExclusionDependencyFilter(this, dindex, Option.FilterTopLevelModuleChildren)); - } - @Override protected void handleDependency(Dependency dependency) throws MojoExecutionException { - try { - FileUtils.copyFileToDirectory(dependency.getArtifact().getFile(), this.outputDirectory); - } catch (IOException ie) { - throw new MojoExecutionException("An I/O related issue occurred", ie); - } - - if (this.getLog().isInfoEnabled()) - this.getLog().info("Copied resource artifact: " + dependency.getArtifact()); } @Override @@ -83,11 +60,10 @@ public class EarGoal extends AbstractDeploymentGoal { @Override public void executePost() throws MojoExecutionException { this.writeDeploymentXml(); - this.writePackage("ear"); } private void writeDeploymentXml() throws MojoExecutionException { - File directory = this.validateAndInitializeDirectory("META-INF"); + File directory = this.validateAndInitializeDirectory(this.isWebApp() ? "WEB-INF" : "META-INF"); try { this.deploymentXmlBuilder.writeTo(directory); diff --git a/src/main/java/com/inteligr8/wildfly/maven/goal/GenerateModuleXmlGoal.java b/src/main/java/com/inteligr8/wildfly/maven/goal/GenerateModuleXmlGoal.java index 9375ed7..9473a67 100644 --- a/src/main/java/com/inteligr8/wildfly/maven/goal/GenerateModuleXmlGoal.java +++ b/src/main/java/com/inteligr8/wildfly/maven/goal/GenerateModuleXmlGoal.java @@ -26,8 +26,11 @@ import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugins.annotations.LifecyclePhase; import org.apache.maven.plugins.annotations.Mojo; import org.codehaus.plexus.component.annotations.Component; +import org.eclipse.aether.artifact.Artifact; +import org.eclipse.aether.artifact.DefaultArtifact; import org.eclipse.aether.graph.Dependency; import org.eclipse.aether.graph.DependencyFilter; +import org.eclipse.aether.util.filter.ScopeDependencyFilter; import com.inteligr8.wildfly.maven.DependencyIndex; import com.inteligr8.wildfly.maven.ModuleExclusionDependencyFilter; @@ -38,7 +41,7 @@ import com.inteligr8.wildfly.maven.xml.ModuleXmlBuilder; /** * @author brian@inteligr8.com */ -@Mojo( name = "module-generate", threadSafe = false, defaultPhase = LifecyclePhase.GENERATE_RESOURCES ) +@Mojo( name = "module-generate-xml", threadSafe = false, defaultPhase = LifecyclePhase.GENERATE_RESOURCES ) @Component( role = org.apache.maven.plugin.Mojo.class ) public class GenerateModuleXmlGoal extends AbstractModuleGoal { @@ -51,11 +54,9 @@ public class GenerateModuleXmlGoal extends AbstractModuleGoal { } catch (ParserConfigurationException pce) { throw new MojoExecutionException("This should never happen", pce); } - } - - @Override - protected Collection getDependencyFilters(DependencyIndex dindex) { - return Arrays.asList(new ModuleExclusionDependencyFilter(this, dindex, Option.FilterTopLevelModuleChildren)); + + if (!"pom".equals(this.project.getPackaging())) + this.moduleXmlBuilder.addResource(new DefaultArtifact(this.project.getArtifact().getId())); } @Override diff --git a/src/main/java/com/inteligr8/wildfly/maven/goal/PackageGoal.java b/src/main/java/com/inteligr8/wildfly/maven/goal/PackageGoal.java index 4b4e422..ea93841 100644 --- a/src/main/java/com/inteligr8/wildfly/maven/goal/PackageGoal.java +++ b/src/main/java/com/inteligr8/wildfly/maven/goal/PackageGoal.java @@ -23,10 +23,24 @@ import java.nio.file.FileVisitor; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.attribute.BasicFileAttributes; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; +import javax.inject.Inject; + import org.apache.maven.execution.MavenSession; +import org.apache.maven.model.Dependency; +import org.apache.maven.model.Model; +import org.apache.maven.model.Profile; +import org.apache.maven.model.building.DefaultModelBuildingRequest; +import org.apache.maven.model.building.ModelBuilder; +import org.apache.maven.model.building.ModelBuildingException; +import org.apache.maven.model.building.ModelBuildingRequest; +import org.apache.maven.model.building.ModelBuildingResult; +import org.apache.maven.model.io.ModelWriter; import org.apache.maven.plugin.AbstractMojo; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.MojoFailureException; @@ -34,12 +48,17 @@ import org.apache.maven.plugins.annotations.LifecyclePhase; import org.apache.maven.plugins.annotations.Mojo; import org.apache.maven.plugins.annotations.Parameter; import org.apache.maven.project.MavenProject; +import org.apache.maven.project.MavenProjectHelper; +import org.apache.maven.project.ProjectModelResolver; import org.codehaus.plexus.component.annotations.Component; +import org.codehaus.plexus.util.FileUtils; + +import com.inteligr8.wildfly.maven.util.DirectoryAccessor; /** * @author brian@inteligr8.com */ -@Mojo( name = "module-package", threadSafe = false, defaultPhase = LifecyclePhase.PACKAGE ) +@Mojo( name = "package", threadSafe = false, defaultPhase = LifecyclePhase.PACKAGE ) @Component( role = org.apache.maven.plugin.Mojo.class ) public class PackageGoal extends AbstractMojo { @@ -49,16 +68,87 @@ public class PackageGoal extends AbstractMojo { @Parameter( defaultValue = "${project}", readonly = true ) protected MavenProject project; - @Parameter( property = "wildfly.module.outputDirectory", required = true, defaultValue = "${project.build.directory}/wildfly-module" ) - protected File moduleDirectory; + @Parameter( property = "wildfly.module.classifier", required = true, defaultValue = "wildfly-module" ) + protected String moduleClassifier; + + @Parameter( property = "wildfly.module.id" ) + protected String moduleId; + + @Parameter( property = "wildfly.module.version", defaultValue = "main" ) + protected String moduleVersion; + + @Parameter( property = "wildfly.deployment.packaging", required = true, defaultValue = "${project.packaging}" ) + protected String packaging; + + @Parameter( property = "wildfly.build.outputDirectory", required = true, defaultValue = "${project.build.directory}/wildfly" ) + protected File packageDirectory; + + @Inject + protected DirectoryAccessor directoryAccessor; + + @Inject + protected MavenProjectHelper helper; + + @Inject + protected ModelBuilder modelBuilder; + + @Inject + protected ModelWriter modelWriter; @Override public void execute() throws MojoExecutionException, MojoFailureException { - File buildDirectory = new File(this.project.getBuild().getDirectory()); - if (!buildDirectory.exists()) - buildDirectory.mkdirs(); - - File zipfile = new File(buildDirectory, this.project.getBuild().getFinalName() + ".zip"); + boolean isWebApp = "war".equals(this.packaging); + boolean isEntApp = !isWebApp && "ear".equals(this.packaging); + boolean isModule = !isWebApp && !isEntApp; + boolean isModuleOnly = "pom".equals(this.packaging); + + File buildDirectory = this.directoryAccessor.validateAndInitializeDirectory(new File(this.project.getBuild().getDirectory())); + if (isModule && !isModuleOnly) { + if (this.moduleId == null) + throw new MojoExecutionException("A 'moduleId' configuration or 'wildfly.module.id' property is required"); + this.addThisArtifactToModule(buildDirectory); + } + + String ext = isModule ? "zip": this.packaging; + + if (isModule && !isModuleOnly) { + File zipFile = this.createZip(buildDirectory, this.moduleClassifier, ext); + this.helper.attachArtifact(project, ext, this.moduleClassifier, zipFile); + + File file = this.createModulePom(buildDirectory); + this.helper.attachArtifact(project, "pom", this.moduleClassifier, file); + } else { + this.createZip(buildDirectory, ext); + } + } + + private void addThisArtifactToModule(File buildDirectory) throws MojoExecutionException { + File packageDirectory = this.directoryAccessor.validateAndInitializeDirectory(this.packageDirectory, this.moduleId, this.moduleVersion); + File file = new File(buildDirectory, this.project.getBuild().getFinalName() + "." + this.project.getPackaging()); + + try { + FileUtils.copyFileToDirectory(file, packageDirectory); + } catch (IOException ie) { + throw new MojoExecutionException("An I/O related issue occurred", ie); + } + + if (this.getLog().isInfoEnabled()) + this.getLog().info("Copied artifact: " + this.project.getArtifact().getId()); + } + + private File createZip(File buildDirectory, String ext) throws MojoExecutionException { + File zipfile = new File(buildDirectory, this.project.getBuild().getFinalName() + "." + ext); + this.createZip(buildDirectory, zipfile); + return zipfile; + } + + private File createZip(File buildDirectory, String classifier, String ext) throws MojoExecutionException { + File zipfile = new File(buildDirectory, this.project.getBuild().getFinalName() + "-" + classifier + "." + ext); + this.createZip(buildDirectory, zipfile); + return zipfile; + } + + private void createZip(File buildDirectory, File zipfile) throws MojoExecutionException { try { FileOutputStream fostream = new FileOutputStream(zipfile); try { @@ -77,8 +167,8 @@ public class PackageGoal extends AbstractMojo { } } - public void zipModule(ZipOutputStream zostream) throws IOException { - Path path = this.moduleDirectory.toPath(); + private void zipModule(ZipOutputStream zostream) throws IOException { + Path path = this.packageDirectory.toPath(); if (getLog().isDebugEnabled()) getLog().debug("Zipping files in: " + path); @@ -118,4 +208,30 @@ public class PackageGoal extends AbstractMojo { }); } + private File createModulePom(File buildDirectory) throws MojoExecutionException { + ModelBuildingRequest request = new DefaultModelBuildingRequest() + .setPomFile(this.project.getFile()) + .setActiveProfileIds(this.getProfileIds(this.project.getActiveProfiles())); + try { + ModelBuildingResult result = this.modelBuilder.build(request); + Model model = result.getEffectiveModel(); + model.setPackaging("pom"); + + File modulePomFile = new File(buildDirectory, this.project.getBuild().getFinalName() + "-" + moduleClassifier + ".xml"); + this.modelWriter.write(modulePomFile, null, model); + return modulePomFile; + } catch (ModelBuildingException mbe) { + throw new MojoExecutionException("The module POM failed to generate", mbe); + } catch (IOException io) { + throw new MojoExecutionException("An I/O issue occurred", io); + } + } + + private List getProfileIds(Collection profiles) { + List ids = new ArrayList<>(profiles.size()); + for (Profile profile : profiles) + ids.add(profile.getId()); + return ids; + } + } diff --git a/src/main/java/com/inteligr8/wildfly/maven/model/Module.java b/src/main/java/com/inteligr8/wildfly/maven/model/Module.java index 85eab22..1217e03 100644 --- a/src/main/java/com/inteligr8/wildfly/maven/model/Module.java +++ b/src/main/java/com/inteligr8/wildfly/maven/model/Module.java @@ -24,5 +24,13 @@ public class Module { public boolean exportAnnotations; public boolean exportOptional; public boolean isSystem; + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof Module)) + return false; + Module module = (Module) obj; + return this.id.equals(module.id); + } } diff --git a/src/main/java/com/inteligr8/wildfly/maven/util/DirectoryAccessor.java b/src/main/java/com/inteligr8/wildfly/maven/util/DirectoryAccessor.java new file mode 100644 index 0000000..aa82126 --- /dev/null +++ b/src/main/java/com/inteligr8/wildfly/maven/util/DirectoryAccessor.java @@ -0,0 +1,46 @@ +package com.inteligr8.wildfly.maven.util; + +import java.io.File; + +import javax.inject.Singleton; + +@Singleton +public class DirectoryAccessor { + + public File validateAndInitializeDirectory(File directory) { + if (directory.exists() && !directory.isDirectory()) + throw new IllegalArgumentException("A directory was expected: " + directory); + + directory.mkdirs(); + return directory; + } + + public File validateAndInitializeDirectory(File directory, String extraPath) { + directory = this.validateAndInitializeDirectory(directory); + + File extraDirectory = new File(directory, extraPath); + if (extraDirectory.exists() && !extraDirectory.isDirectory()) + throw new IllegalStateException("The formulated directory is a file: " + extraDirectory); + + extraDirectory.mkdirs(); + return extraDirectory; + } + + public File validateAndInitializeDirectory(File directory, String moduleId, String moduleVersion) { + directory = this.validateAndInitializeDirectory(directory); + + for (String dir : moduleId.split("\\.")) { + directory = new File(directory, dir); + if (directory.exists() && !directory.isDirectory()) + throw new IllegalStateException("The formulated directory contains a file: " + directory); + } + + File versionDirectory = new File(directory, moduleVersion); + if (versionDirectory.exists() && !versionDirectory.isDirectory()) + throw new IllegalStateException("The formulated directory contains a file: " + directory); + + versionDirectory.mkdirs(); + return versionDirectory; + } + +} \ No newline at end of file