package org.codehaus.mojo.jboss.packaging; /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ import org.apache.maven.archiver.MavenArchiveConfiguration; import org.apache.maven.archiver.MavenArchiver; import org.apache.maven.artifact.Artifact; import org.apache.maven.artifact.handler.ArtifactHandler; import org.apache.maven.artifact.handler.manager.ArtifactHandlerManager; import org.apache.maven.artifact.resolver.filter.ScopeArtifactFilter; import org.apache.maven.plugin.AbstractMojo; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.project.MavenProject; import org.apache.maven.project.MavenProjectHelper; import org.codehaus.plexus.archiver.jar.JarArchiver; import org.codehaus.plexus.util.FileUtils; import org.codehaus.plexus.util.StringUtils; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; /** * Abstract super class for all the packaging mojos. This class contains the logic for actually building the packaging * types. */ public abstract class AbstractPackagingMojo extends AbstractMojo { /** * The maven project. * * @parameter default-value="${project}" * @readonly */ private MavenProject project; /** * The directory for the generated packaging. * * @parameter default-value="${project.build.directory}" */ private File outputDirectory; /** * The directory containing generated classes. * * @parameter default-value="${project.build.outputDirectory}" * @readonly */ private File classesDirectory; /** * The directory where the JBoss packaging is built. * * @parameter default-value="${project.build.directory}/${project.build.finalName}" */ private File packagingDirectory; /** * The filename for the output deployment descriptor. By default the deployment descriptor will retain the same * filename. * * @parameter */ private String deploymentDescriptorDestName; /** * The destination of the deployment descriptor file. * * @parameter default-value="${project.build.directory}/${project.build.finalName}/META-INF" */ private File deploymentDescriptorDest; /** * The directory where to put the libs. * * @parameter default-value="${project.build.directory}/${project.build.finalName}/lib" */ private File libDirectory; /** * The name of the generated packaging archive. * * @parameter default-value="${project.build.finalName}" */ private String archiveName; /** * All artifacts are excluded. * * @parameter expression="${excludeAll}" default-value="false" */ private boolean excludeAll; /** * Dependency Artifacts excluded from packaging within the generated archive file. Use artifactId:groupId in nested * exclude tags. * * @parameter */ private Set excludes; /** * The Jar archiver. * * @component role="org.codehaus.plexus.archiver.Archiver" roleHint="jar" */ private JarArchiver jarArchiver; /** * The maven archive configuration to use. * * @parameter */ private MavenArchiveConfiguration archive = new MavenArchiveConfiguration(); /** * The manifest file for the archive. * * @parameter */ private File manifest; /** * Classifier to add to the generated artifact. If given, the artifact will not be the primary project artifact. * * @parameter */ private String classifier; /** * Whether this is the main artifact of the current project. * * @parameter default-value="true" */ private boolean primaryArtifact; /** * The project helper. * * @component */ private MavenProjectHelper projectHelper; /** * The artifact handler manager. * * @component */ private ArtifactHandlerManager artifactHandlerManager; /** * Whether to remove the version numbers from the filenames of the included dependencies. By default the included * dependencies will have the format [artifactId]-[version]-[classifier].[type] If this parameter is set to true, * the jar name will be in the format [artifactId]-[classifier].[type] * * @parameter default-value="false" */ private boolean removeDependencyVersions; /** * Whether to generate only the exploded archive format. By default both an exploded directory and a zipped file * will be created. If set to "true" only the exploded directory will be created. * * @parameter default-value="false" expression="${explodedOnly}" * @since 2.0 */ private boolean explodedOnly; /** * @return Whether only the exploded format should be created */ public boolean isExplodedOnly() { return explodedOnly; } /** * @return the maven project */ public MavenProject getProject() { return project; } /** * @return the packaging directory */ public File getPackagingDirectory() { return packagingDirectory; } /** * @return the packaging directory */ public File getClassesDirectory() { return classesDirectory; } /** * @return the lib directory */ public File getLibDirectory() { return libDirectory; } /** * Get the deployment descriptor file. Subclasses may override this method to provide a different name for their * type of archive packaging. * * @return deployment descriptor File */ public abstract File getDeploymentDescriptor(); /** * Get the type of the artifact. * * @return The type of the generated artifact */ public abstract String getArtifactType(); /** * @return The directory where to write the archive */ public File getOutputDirectory() { return outputDirectory; } /** * Build the package in an exploded format. * * @throws MojoExecutionException if an error occurred * @throws MojoFailureException if an error occurred */ public void buildExplodedPackaging() throws MojoExecutionException { buildExplodedPackaging( Collections.EMPTY_SET ); } /** * Build the package in an exploded format. * * @param excludes File patterns to exclude from the packaging. * @throws MojoExecutionException if an error occurred * @throws MojoFailureException if an error occurred */ public void buildExplodedPackaging( Set excludes ) throws MojoExecutionException { getLog().info( "Assembling JBoss packaging " + project.getArtifactId() + " in " + packagingDirectory ); if ( excludes == null ) { excludes = Collections.EMPTY_SET; } packagingDirectory.mkdirs(); libDirectory.mkdirs(); try { packageResources(); } catch ( Exception e1 ) { throw new MojoExecutionException( "Failed while packaging resources", e1 ); } if ( classesDirectory.exists() && !classesDirectory.equals( packagingDirectory ) ) { try { packageClasses(); } catch ( Exception e ) { throw new MojoExecutionException( "Unable to copy classes directory", e ); } } File deploymentDescriptorFile = this.getDeploymentDescriptor(); if ( deploymentDescriptorFile == null || !deploymentDescriptorFile.exists() ) { throw new MojoExecutionException( "Could not find descriptor file: " + deploymentDescriptorFile ); } String destName = this.getDeploymentDescriptorDestName(); if ( destName == null ) { destName = deploymentDescriptorFile.getName(); } File deploymentDescriptorTarget = new File( getDeploymentDescriptorDest(), destName ); if ( !deploymentDescriptorTarget.exists() ) { deploymentDescriptorTarget.getParentFile().mkdirs(); try { FileUtils.copyFile( deploymentDescriptorFile, deploymentDescriptorTarget ); } catch ( IOException e ) { throw new MojoExecutionException( "Could not copy deployment descriptor", e ); } } Set artifacts = project.getArtifacts(); List rejects = new ArrayList(); final Set includedArtifacts = new HashSet(); final ScopeArtifactFilter filter = new ScopeArtifactFilter( Artifact.SCOPE_RUNTIME ); getLog().debug( "" ); getLog().debug( " Including artifacts: " ); getLog().debug( " -------------------" ); for ( Iterator iter = artifacts.iterator(); iter.hasNext(); ) { Artifact artifact = (Artifact) iter.next(); if ( !artifact.isOptional() && filter.include( artifact ) ) { String descriptor = artifact.getGroupId() + ":" + artifact.getArtifactId(); if ( !excludeAll && artifact.getArtifactHandler().isAddedToClasspath() && !excludes.contains( descriptor ) ) { getLog().debug( " o " + descriptor ); String name = getArtifactName( artifact ); if ( !includedArtifacts.add( name ) ) { name = artifact.getGroupId() + "-" + name; getLog().info( "Duplicate artifact discovered, using full name: " + name ); } try { packageLib( artifact, name ); } catch ( Exception e ) { throw new MojoExecutionException( "Could not copy dependency", e ); } } else { rejects.add( artifact ); } } } if ( !excludes.isEmpty() ) { getLog().debug( "" ); getLog().debug( " Excluded artifacts: " ); getLog().debug( " ------------------" ); for ( int ii = 0; ii < rejects.size(); ii++ ) { getLog().debug( " o " + rejects.get( ii ) ); } } else { getLog().debug( "No artifacts have been excluded." ); } getLog().debug( "" ); buildSpecificPackaging( excludes ); if ( libDirectory.isDirectory() ) { String[] files = libDirectory.list(); if ( files.length == 0 ) { libDirectory.delete(); } } } /** * Perform any packaging specific to this type. * * @param excludes The exclude list. * @throws MojoExecutionException For plugin failures. * @throws MojoFailureException For unexpected plugin failures. * @throws IOException For exceptions during IO operations. */ protected void buildSpecificPackaging( final Set excludes ) throws MojoExecutionException { } /** * @return The name of the archive */ public String getArchiveName() { return archiveName; } /** * Generates the packaged archive. * * @throws MojoExecutionException if there is a problem */ protected void performPackaging() throws MojoExecutionException { ArtifactHandler artifactHandler = artifactHandlerManager.getArtifactHandler( getArtifactType() ); String extension = artifactHandler.getExtension(); String type = getArtifactType(); final File archiveFile = calculateFile( outputDirectory, archiveName, classifier, extension ); // generate archive file getLog().debug( "Generating JBoss packaging " + archiveFile.getAbsolutePath() ); MavenArchiver archiver = new MavenArchiver(); archiver.setArchiver( jarArchiver ); archiver.setOutputFile( archiveFile ); try { jarArchiver.addDirectory( getPackagingDirectory() ); if ( manifest != null ) { jarArchiver.setManifest( manifest ); } archiver.createArchive( getProject(), archive ); } catch ( Exception e ) { throw new MojoExecutionException( "Problem generating archive file.", e ); } // If there is a classifier, then this archive is not the primary project artifact. if ( classifier != null && !classifier.equals( "" ) ) { primaryArtifact = false; } if ( primaryArtifact ) { Artifact artifact = project.getArtifact(); artifact.setFile( archiveFile ); artifact.setArtifactHandler( artifactHandler ); } else { projectHelper.attachArtifact( project, type, classifier, archiveFile ); } } /** * Calculate the name of the archive file. * * @param outputDirectory The output directory. * @param archiveName The name of the artifact archive. * @param classifier The classifier of the artifact. * @param extension The artifact archive extension. * @return The archive file. */ private static File calculateFile( final File outputDirectory, final String archiveName, final String classifier, final String extension ) { final String basename; if ( StringUtils.isEmpty( classifier ) ) { basename = archiveName; } else { basename = archiveName + '-' + classifier; } return new File( outputDirectory, basename + '.' + extension ); } /** * Get the name of the artifact. * * @param artifact The current artifact. * @return The name of the artifact. */ private String getArtifactName( Artifact artifact ) { String artifactName = artifact.getArtifactId(); if ( !this.removeDependencyVersions ) { artifactName += "-" + artifact.getVersion(); } if ( !StringUtils.isEmpty( artifact.getClassifier() ) ) { artifactName += "-" + artifact.getClassifier(); } artifactName += "." + artifact.getArtifactHandler().getExtension(); return artifactName; } public String getDeploymentDescriptorDestName() { return deploymentDescriptorDestName; } public File getDeploymentDescriptorDest() { return deploymentDescriptorDest; } /** * Main execution for the goal. * * @throws MojoExecutionException if an error occurred while building the webapp */ public void execute() throws MojoExecutionException { buildExplodedPackaging( excludes ); if ( !isExplodedOnly() ) { performPackaging(); } } /** * Routine that packages resources not handled by default resource handling. */ protected void packageResources() throws Exception { // Do nothing, override to handle specific resources } /** * Routine that includes the specified artifact into the exploded packaging. * * @param artifact * @param name * @throws Exception */ protected void packageLib( Artifact artifact, String name ) throws Exception { FileUtils.copyFile( artifact.getFile(), new File( libDirectory, name ) ); } /** * Routine that includes the specified artifact into the exploded packaging. * * @throws Exception */ protected void packageClasses() throws Exception { FileUtils.copyDirectoryStructure( classesDirectory, packagingDirectory ); } }