blob: 98ea86b55fcad4605879a4703e2c689b141fc0dc [file] [log] [blame]
package org.apache.maven.plugin.ear;
/*
* 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.execution.MavenSession;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugin.ear.util.EarMavenArchiver;
import org.apache.maven.project.MavenProjectHelper;
import org.apache.maven.shared.filtering.MavenFileFilter;
import org.apache.maven.shared.filtering.MavenFilteringException;
import org.apache.maven.shared.filtering.MavenResourcesExecution;
import org.apache.maven.shared.filtering.MavenResourcesFiltering;
import org.codehaus.plexus.archiver.ArchiverException;
import org.codehaus.plexus.archiver.UnArchiver;
import org.codehaus.plexus.archiver.jar.JarArchiver;
import org.codehaus.plexus.archiver.manager.ArchiverManager;
import org.codehaus.plexus.archiver.manager.NoSuchArchiverException;
import org.codehaus.plexus.util.DirectoryScanner;
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.Arrays;
import java.util.Iterator;
import java.util.List;
/**
* Builds J2EE Enteprise Archive (EAR) files.
*
* @author <a href="snicoll@apache.org">Stephane Nicoll</a>
* @version $Id$
* @goal ear
* @phase package
* @requiresDependencyResolution test
*/
public class EarMojo
extends AbstractEarMojo
{
private static final String[] EMPTY_STRING_ARRAY = {};
/**
* Single directory for extra files to include in the EAR.
*
* @parameter expression="${basedir}/src/main/application"
* @required
*/
private File earSourceDirectory;
/**
* The comma separated list of tokens to include in the EAR.
*
* @parameter alias="includes" default-value="**"
*/
private String earSourceIncludes;
/**
* The comma separated list of tokens to exclude from the EAR.
*
* @parameter alias="excludes"
*/
private String earSourceExcludes;
/**
* Specify that the ear sources should be filtered.
*
* @parameter default-value="false"
* @since 2.3.2
*/
private boolean filtering;
/**
* Filters (property files) to include during the interpolation of the pom.xml.
*
* @parameter
* @since 2.3.2
*/
private List filters;
/**
* A list of file extensions that should not be filtered if
* filtering is actived.
*
* @parameter
* @since 2.3.2
*/
private List nonFilteredFileExtensions;
/**
* To escape interpolated value with windows path
* c:\foo\bar will be replaced with c:\\foo\\bar
*
* @parameter expression="${maven.ear.escapedBackslashesInFilePath}" default-value="false"
* @since 2.3.2
*/
private boolean escapedBackslashesInFilePath;
/**
* Expression preceded with the String won't be interpolated
* \${foo} will be replaced with ${foo}
*
* @parameter expression="${maven.ear.escapeString}"
* @since 2.3.2
*/
protected String escapeString;
/**
* The location of the manifest file to be used within the ear file. If
* not value if specified, the default location in the workDirectory is
* taken. If the file does not exist, a manifest will be generated
* automatically.
*
* @parameter
*/
private File manifestFile;
/**
* The location of a custom application.xml file to be used
* within the ear file.
*
* @parameter
*/
private String applicationXml;
/**
* The directory for the generated EAR.
*
* @parameter expression="${project.build.directory}"
* @required
*/
private String outputDirectory;
/**
* The name of the EAR file to generate.
*
* @parameter alias="earName" expression="${project.build.finalName}"
* @required
*/
private String finalName;
/**
* The comma separated list of artifact's type(s) to unpack
* by default.
*
* @parameter
*/
private String unpackTypes;
/**
* Classifier to add to the artifact generated. If given, the artifact will
* be an attachment instead.
*
* @parameter
*/
private String classifier;
/**
* The directory to get the resources from.
*
* @parameter
* @deprecated please use earSourcesDirectory instead
*/
private File resourcesDir;
/**
* The Jar archiver.
*
* @component role="org.codehaus.plexus.archiver.Archiver" role-hint="jar"
*/
private JarArchiver jarArchiver;
/**
* The archive configuration to use.
* See <a href="http://maven.apache.org/shared/maven-archiver/index.html">Maven Archiver Reference</a>.
*
* @parameter
*/
private MavenArchiveConfiguration archive = new MavenArchiveConfiguration();
/**
* @component
*/
private MavenProjectHelper projectHelper;
/**
* The archive manager.
*
* @component
*/
private ArchiverManager archiverManager;
/**
*
* @component role="org.apache.maven.shared.filtering.MavenFileFilter" role-hint="default"
* @required
*/
private MavenFileFilter mavenFileFilter;
/**
*
* @component role="org.apache.maven.shared.filtering.MavenResourcesFiltering" role-hint="default"
* @required
*/
private MavenResourcesFiltering mavenResourcesFiltering;
/**
* @parameter expression="${session}"
* @readonly
* @required
* @since 2.3.2
*/
private MavenSession session;
private List filterWrappers;
public void execute()
throws MojoExecutionException, MojoFailureException
{
// Initializes ear modules
super.execute();
// Initializes unpack types
List unpackTypesList = new ArrayList();
if ( unpackTypes != null )
{
unpackTypesList = Arrays.asList( unpackTypes.split( "," ) );
final Iterator it = unpackTypesList.iterator();
while ( it.hasNext() )
{
String type = (String) it.next();
if ( !EarModuleFactory.standardArtifactTypes.contains( type ) )
{
throw new MojoExecutionException(
"Invalid type[" + type + "] supported types are " + EarModuleFactory.standardArtifactTypes );
}
}
getLog().debug( "Initialized unpack types " + unpackTypesList );
}
// Copy modules
try
{
for ( Iterator iter = getModules().iterator(); iter.hasNext(); )
{
EarModule module = (EarModule) iter.next();
if ( module instanceof JavaModule )
{
getLog().warn( "JavaModule is deprecated (" + module + "), please use JarModule instead." );
}
if ( module instanceof Ejb3Module )
{
getLog().warn( "Ejb3Module is deprecated (" + module + "), please use EjbModule instead." );
}
final File sourceFile = module.getArtifact().getFile();
final File destinationFile = buildDestinationFile( getWorkDirectory(), module.getUri() );
if ( !sourceFile.isFile() )
{
throw new MojoExecutionException( "Cannot copy a directory: " + sourceFile.getAbsolutePath() +
"; Did you package/install " + module.getArtifact() + "?" );
}
if ( destinationFile.getCanonicalPath().equals( sourceFile.getCanonicalPath() ) )
{
getLog().info(
"Skipping artifact[" + module + "], as it already exists at[" + module.getUri() + "]" );
continue;
}
// If the module is within the unpack list, make sure that no unpack wasn't forced (null or true)
// If the module is not in the unpack list, it should be true
if ( ( unpackTypesList.contains( module.getType() ) &&
( module.shouldUnpack() == null || module.shouldUnpack().booleanValue() ) ) ||
( module.shouldUnpack() != null && module.shouldUnpack().booleanValue() ) )
{
getLog().info( "Copying artifact[" + module + "] to[" + module.getUri() + "] (unpacked)" );
// Make sure that the destination is a directory to avoid plexus nasty stuff :)
destinationFile.mkdirs();
unpack( sourceFile, destinationFile );
}
else
{
if ( sourceFile.lastModified() > destinationFile.lastModified() )
{
getLog().info( "Copying artifact[" + module + "] to[" + module.getUri() + "]" );
FileUtils.copyFile( sourceFile, destinationFile );
}
else
{
getLog().debug( "Skipping artifact[" + module + "], as it is already up to date at[" +
module.getUri() + "]" );
}
}
}
}
catch ( IOException e )
{
throw new MojoExecutionException( "Error copying EAR modules", e );
}
catch ( ArchiverException e )
{
throw new MojoExecutionException( "Error unpacking EAR modules", e );
}
catch ( NoSuchArchiverException e )
{
throw new MojoExecutionException( "No Archiver found for EAR modules", e );
}
// Copy source files
try
{
File earSourceDir = earSourceDirectory;
if ( earSourceDir.exists() )
{
getLog().info( "Copy ear sources to " + getWorkDirectory().getAbsolutePath() );
String[] fileNames = getEarFiles( earSourceDir );
for ( int i = 0; i < fileNames.length; i++ )
{
copyFile( new File( earSourceDir, fileNames[i] ),
new File( getWorkDirectory(), fileNames[i] ) );
}
}
if ( applicationXml != null && !"".equals( applicationXml ) )
{
//rename to application.xml
getLog().info( "Including custom application.xml[" + applicationXml + "]" );
File metaInfDir = new File( getWorkDirectory(), META_INF );
copyFile( new File( applicationXml ), new File( metaInfDir, "/application.xml" ) );
}
}
catch ( IOException e )
{
throw new MojoExecutionException( "Error copying EAR sources", e );
}
catch ( MavenFilteringException e )
{
throw new MojoExecutionException( "Error filetering EAR sources", e );
}
// Copy resources files
try
{
if ( resourcesDir != null && resourcesDir.exists() )
{
getLog().warn( "resourcesDir is deprecated. Please use the earSourceDirectory property instead.");
getLog().info( "Copy ear resources to " + getWorkDirectory().getAbsolutePath() );
String[] fileNames = getEarFiles( resourcesDir );
for ( int i = 0; i < fileNames.length; i++ )
{
FileUtils.copyFile( new File( resourcesDir, fileNames[i] ),
new File( getWorkDirectory(), fileNames[i] ) );
}
}
}
catch ( IOException e )
{
throw new MojoExecutionException( "Error copying EAR resources", e );
}
// Check if deployment descriptor is there
File ddFile = new File( getWorkDirectory(), APPLICATION_XML_URI );
if ( !ddFile.exists() && !version.equals(VERSION_5 ) )
{
throw new MojoExecutionException(
"Deployment descriptor: " + ddFile.getAbsolutePath() + " does not exist." );
}
try
{
File earFile = getEarFile( outputDirectory, finalName, classifier );
final MavenArchiver archiver = new EarMavenArchiver(getModules());
final JarArchiver jarArchiver = getJarArchiver();
getLog().debug( "Jar archiver implementation[" + jarArchiver.getClass().getName() + "]" );
archiver.setArchiver( jarArchiver );
archiver.setOutputFile( earFile );
// Include custom manifest if necessary
includeCustomManifestFile();
archiver.getArchiver().addDirectory( getWorkDirectory() );
archiver.createArchive( getProject(), archive );
if ( classifier != null )
{
projectHelper.attachArtifact( getProject(), "ear", classifier, earFile );
}
else
{
getProject().getArtifact().setFile( earFile );
}
}
catch ( Exception e )
{
throw new MojoExecutionException( "Error assembling EAR", e );
}
}
public String getApplicationXml()
{
return applicationXml;
}
public void setApplicationXml( String applicationXml )
{
this.applicationXml = applicationXml;
}
/**
* Returns a string array of the excludes to be used
* when assembling/copying the ear.
*
* @return an array of tokens to exclude
*/
protected String[] getExcludes()
{
List excludeList = new ArrayList( FileUtils.getDefaultExcludesAsList() );
if ( earSourceExcludes != null && !"".equals( earSourceExcludes ) )
{
excludeList.addAll( Arrays.asList( StringUtils.split( earSourceExcludes, "," ) ) );
}
// if applicationXml is specified, omit the one in the source directory
if ( getApplicationXml() != null && !"".equals( getApplicationXml() ) )
{
excludeList.add( "**/" + META_INF + "/application.xml" );
}
return (String[]) excludeList.toArray( EMPTY_STRING_ARRAY );
}
/**
* Returns a string array of the includes to be used
* when assembling/copying the ear.
*
* @return an array of tokens to include
*/
protected String[] getIncludes()
{
return StringUtils.split( StringUtils.defaultString( earSourceIncludes ), "," );
}
private static File buildDestinationFile( File buildDir, String uri )
{
return new File( buildDir, uri );
}
private void includeCustomManifestFile()
{
if ( manifestFile == null )
{
manifestFile = new File( getWorkDirectory(), "META-INF/MANIFEST.MF" );
}
if ( !manifestFile.exists() )
{
getLog().info( "Could not find manifest file: " + manifestFile + " - Generating one" );
}
else
{
getLog().info( "Including custom manifest file[" + manifestFile + "]" );
archive.setManifestFile( manifestFile );
}
}
/**
* Returns the EAR file to generate, based on an optional classifier.
*
* @param basedir the output directory
* @param finalName the name of the ear file
* @param classifier an optional classifier
* @return the EAR file to generate
*/
private static File getEarFile( String basedir, String finalName, String classifier )
{
if ( classifier == null )
{
classifier = "";
}
else if ( classifier.trim().length() > 0 && !classifier.startsWith( "-" ) )
{
classifier = "-" + classifier;
}
return new File( basedir, finalName + classifier + ".ear" );
}
/**
* Returns a list of filenames that should be copied
* over to the destination directory.
*
* @param sourceDir the directory to be scanned
* @return the array of filenames, relative to the sourceDir
*/
private String[] getEarFiles( File sourceDir )
{
DirectoryScanner scanner = new DirectoryScanner();
scanner.setBasedir( sourceDir );
scanner.setExcludes( getExcludes() );
scanner.addDefaultExcludes();
scanner.setIncludes( getIncludes() );
scanner.scan();
return scanner.getIncludedFiles();
}
/**
* Unpacks the module into the EAR structure.
*
* @param source File to be unpacked.
* @param destDir Location where to put the unpacked files.
*/
public void unpack( File source, File destDir )
throws NoSuchArchiverException, IOException, ArchiverException
{
UnArchiver unArchiver = archiverManager.getUnArchiver( "zip" );
unArchiver.setSourceFile( source );
unArchiver.setDestDirectory( destDir );
// Extract the module
unArchiver.extract();
}
/**
* Returns the {@link JarArchiver} implementation used
* to package the EAR file.
* <p/>
* By default the archiver is obtained from the Plexus container.
*
* @return the archiver
*/
protected JarArchiver getJarArchiver()
{
return jarArchiver;
}
private void copyFile(File source, File target)
throws MavenFilteringException, IOException, MojoExecutionException {
if ( filtering && !isNonFilteredExtension( source.getName() ) )
{
mavenFileFilter.copyFile( source, target, true, getFilterWrappers(), null );
}
else
{
FileUtils.copyFile(source,target);
}
}
public boolean isNonFilteredExtension( String fileName )
{
return !mavenResourcesFiltering.filteredFileExtension( fileName, nonFilteredFileExtensions );
}
private List getFilterWrappers() throws MojoExecutionException {
if (filterWrappers == null)
{
try
{
MavenResourcesExecution mavenResourcesExecution = new MavenResourcesExecution();
mavenResourcesExecution.setEscapeString( escapeString );
filterWrappers = mavenFileFilter.getDefaultFilterWrappers( project, filters,
escapedBackslashesInFilePath, this.session, mavenResourcesExecution );
}
catch ( MavenFilteringException e )
{
getLog().error( "fail to build filering wrappers " + e.getMessage() );
throw new MojoExecutionException( e.getMessage(), e );
}
}
return filterWrappers;
}
}