package org.codehaus.mojo.appassembler;
/*
* The MIT License
*
* Copyright 2005-2007 The Codehaus.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is furnished to do
* so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.installer.ArtifactInstallationException;
import org.apache.maven.artifact.installer.ArtifactInstaller;
import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.artifact.repository.ArtifactRepositoryFactory;
import org.apache.maven.artifact.repository.layout.ArtifactRepositoryLayout;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.project.MavenProject;
import org.codehaus.mojo.appassembler.daemon.DaemonGenerationRequest;
import org.codehaus.mojo.appassembler.daemon.DaemonGeneratorException;
import org.codehaus.mojo.appassembler.daemon.DaemonGeneratorService;
import org.codehaus.mojo.appassembler.daemon.script.Platform;
import org.codehaus.mojo.appassembler.model.Classpath;
import org.codehaus.mojo.appassembler.model.Dependency;
import org.codehaus.mojo.appassembler.model.Directory;
import org.codehaus.mojo.appassembler.model.JvmSettings;
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.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;
//@deprecated Use the generate-daemons goal instead
/**
* Assembles the artifacts and generates bin scripts for the configured applications
*
* @author <a href="mailto:kristian.nordal@gmail.com">Kristian Nordal</a>
* @version $Id$
* @goal assemble
* @requiresDependencyResolution runtime
* @phase package
*/
public class AssembleMojo
extends AbstractMojo
{
// -----------------------------------------------------------------------
// Parameters
// -----------------------------------------------------------------------
/**
* The directory that will be used to assemble the artifacts in
* and place the bin scripts.
*
* @required
* @parameter expression="${assembleDirectory}" default-value="${project.build.directory}/appassembler"
*/
private File assembleDirectory;
/**
* The set of Programs that bin files will be generated for.
*
* @required
* @parameter
*/
private Set programs;
/**
* The name of the target directory for configuration files.
*
* @parameter default-value="etc"
*/
private String configurationDirectory;
/**
* The name of the source directory for configuration files.
*
* @parameter default-value="src/main/config"
* @since 1.1
*/
private File configurationSourceDirectory;
/**
* If the source configuration directory should be copied to the
* configured <code>configurationDirectory</code>.
*
* @parameter default-value="false"
* @since 1.1
*/
private boolean copyConfigurationDirectory;
/**
* If the <code>configurationDirectory</code> (<code>etc</code> by default) should be included
* in the beginning of the classpath in the generated bin files.
*
* @parameter default-value="true"
*/
private boolean includeConfigurationDirectoryInClasspath;
/**
* The layout of the generated Maven repository. Supported types - "default" (Maven2) | "legacy" (Maven1) | "flat"
* (flat <code>lib/</code> style).
*
* @parameter default-value="default"
*/
private String repositoryLayout;
/**
* Extra arguments that will be given to the JVM verbatim.
*
* @parameter
*/
private String extraJvmArguments;
/**
* The default platforms the plugin will generate bin files for.
* Configure with string values - "all"(default/empty) | "windows" | "unix".
*
* @parameter
*/
private Set platforms;
/**
* Setup file in $BASEDIR/bin to be called prior to execution.
*
* @parameter
*/
private String environmentSetupFileName;
/**
* Set to false to skip repository generation.
* @parameter default-value="true"
*/
private boolean generateRepository;
/**
* Path (relative to assembleDirectory) of the desired output repository.
*
* @parameter default-value="repo"
*/
private String repositoryName;
/**
* The file extensions to use for bin files.
* The file extensions are stored in a Map that uses the platform name as key.
* To change the file extension for Unix bin files to ".sh" use this configuration:
* <pre>
* <binFileExtensions>
* <unix>.sh</unix>
* </binFileExtensions>
* </pre>
*
* @parameter
* @since 1.1
*/
protected Map/*<String, String>*/ binFileExtensions;
// -----------------------------------------------------------------------
// Read-only Parameters
// -----------------------------------------------------------------------
/**
* @readonly
* @parameter expression="${project}"
*/
private MavenProject mavenProject;
/**
* @readonly
* @parameter expression="${project.runtimeArtifacts}"
*/
private List artifacts;
/**
* @readonly
* @parameter expression="${project.artifact}"
*/
private Artifact projectArtifact;
/**
* @readonly
* @parameter expression="${localRepository}"
*/
private ArtifactRepository localRepository;
/**
* Show console window when execute this application.
*
* @parameter default-value="true"
*/
private boolean showConsoleWindow;
// -----------------------------------------------------------------------
// Components
// -----------------------------------------------------------------------
/**
* @component
*/
private ArtifactRepositoryFactory artifactRepositoryFactory;
/**
* @component
*/
private ArtifactInstaller artifactInstaller;
/**
* @component
*/
private DaemonGeneratorService daemonGeneratorService;
/**
* @component role="org.apache.maven.artifact.repository.layout.ArtifactRepositoryLayout"
*/
private Map availableRepositoryLayouts;
// ----------------------------------------------------------------------
// CONSTANTS
// ----------------------------------------------------------------------
private static final Set VALID_PLATFORMS =
Collections.unmodifiableSet( new HashSet( Arrays.asList( new String[]{"unix", "windows"} ) ) );
// ----------------------------------------------------------------------
// Validate
// ----------------------------------------------------------------------
public void validate( Set defaultPlatforms )
throws MojoFailureException, MojoExecutionException
{
// ----------------------------------------------------------------------
// Validate Programs
// ----------------------------------------------------------------------
for ( Iterator i = programs.iterator(); i.hasNext(); )
{
Program program = (Program) i.next();
if ( program.getMainClass() == null || program.getMainClass().trim().equals( "" ) )
{
throw new MojoFailureException( "Missing main class in Program configuration" );
}
// platforms
program.setPlatforms( validatePlatforms( program.getPlatforms(), defaultPlatforms ) );
}
}
// ----------------------------------------------------------------------
// Execute
// ----------------------------------------------------------------------
public void execute()
throws MojoExecutionException, MojoFailureException
{
Set defaultPlatforms = validatePlatforms( platforms, VALID_PLATFORMS );
// validate input and set defaults
validate( defaultPlatforms );
// Set the extensions for bin files for the different platforms
setBinFileExtensions();
ArtifactRepositoryLayout artifactRepositoryLayout =
(ArtifactRepositoryLayout) availableRepositoryLayouts.get( repositoryLayout );
if ( artifactRepositoryLayout == null )
{
throw new MojoFailureException( "Unknown repository layout '" + repositoryLayout + "'." );
}
// ----------------------------------------------------------------------
// Install dependencies in the new repository
// ----------------------------------------------------------------------
if ( generateRepository )
{
// The repo where the jar files will be installed
ArtifactRepository artifactRepository = artifactRepositoryFactory.createDeploymentArtifactRepository(
"appassembler", "file://" + assembleDirectory.getAbsolutePath() + "/" + repositoryName,
artifactRepositoryLayout, false );
for ( Iterator it = artifacts.iterator(); it.hasNext(); )
{
Artifact artifact = (Artifact) it.next();
installArtifact( artifactRepository, artifact );
}
// install the project's artifact in the new repository
installArtifact( artifactRepository, projectArtifact );
}
// ----------------------------------------------------------------------
// Setup
// ----------------------------------------------------------------------
setUpWorkingArea();
// ----------------------------------------------------------------------
// Create bin files
// ----------------------------------------------------------------------
for ( Iterator it = programs.iterator(); it.hasNext(); )
{
Program program = (Program) it.next();
Set platforms = validatePlatforms( program.getPlatforms(), defaultPlatforms );
for ( Iterator platformIt = platforms.iterator(); platformIt.hasNext(); )
{
String platform = (String) platformIt.next();
// TODO: seems like a bug in the generator that the request is modified
org.codehaus.mojo.appassembler.model.Daemon daemon =
programToDaemon( program, artifactRepositoryLayout );
DaemonGenerationRequest request =
new DaemonGenerationRequest( daemon, mavenProject, localRepository, assembleDirectory );
request.setStubDaemon( request.getDaemon() );
request.setPlatform( platform );
try
{
daemonGeneratorService.generateDaemon( request );
}
catch ( DaemonGeneratorException e )
{
throw new MojoExecutionException( "Error while generating script for the program '"
+ program.getName() + "' for the platform '" + platform + "': " + e.getMessage(), e );
}
}
}
// ----------------------------------------------------------------------
// Copy configuration directory
// ----------------------------------------------------------------------
if ( copyConfigurationDirectory )
{
copyConfigurationDirectory();
}
}
private org.codehaus.mojo.appassembler.model.Daemon programToDaemon( Program program,
ArtifactRepositoryLayout artifactRepositoryLayout )
{
org.codehaus.mojo.appassembler.model.Daemon daemon = new org.codehaus.mojo.appassembler.model.Daemon();
daemon.setId( program.getName() );
daemon.setMainClass( program.getMainClass() );
daemon.setShowConsoleWindow( showConsoleWindow );
List directories = new ArrayList();
if ( includeConfigurationDirectoryInClasspath )
{
Directory directory = new Directory();
directory.setRelativePath( configurationDirectory );
directories.add( directory );
}
if ( daemon.getClasspath() == null )
{
daemon.setClasspath( new Classpath() );
}
daemon.getClasspath().setDirectories( directories );
daemon.setRepositoryName( repositoryName );
List dependencies = new ArrayList();
List classPathArtifacts = new ArrayList( artifacts );
classPathArtifacts.add( projectArtifact );
for ( Iterator it = classPathArtifacts.iterator(); it.hasNext(); )
{
Artifact artifact = (Artifact) it.next();
Dependency dependency = new Dependency();
dependency.setGroupId( artifact.getGroupId() );
dependency.setArtifactId( artifact.getArtifactId() );
dependency.setVersion( artifact.getVersion() );
dependency.setRelativePath( artifactRepositoryLayout.pathOf( artifact ) );
dependencies.add( dependency );
}
daemon.getClasspath().setDependencies( dependencies );
JvmSettings jvmSettings = new JvmSettings();
jvmSettings.setExtraArguments( parseTokens( this.extraJvmArguments ) );
daemon.setJvmSettings( jvmSettings );
daemon.setEnvironmentSetupFileName( this.environmentSetupFileName );
return daemon;
}
// ----------------------------------------------------------------------
// Install artifacts into the assemble repository
// ----------------------------------------------------------------------
private void installArtifact( ArtifactRepository artifactRepository, Artifact artifact )
throws MojoExecutionException
{
try
{
// Necessary for the artifact's baseVersion to be set correctly
// See: http://mail-archives.apache.org/mod_mbox/maven-dev/200511.mbox/%3c437288F4.4080003@apache.org%3e
artifact.isSnapshot();
if ( artifact.getFile() != null )
{
artifactInstaller.install( artifact.getFile(), artifact, artifactRepository );
}
}
catch ( ArtifactInstallationException e )
{
throw new MojoExecutionException( "Failed to copy artifact.", e );
}
}
// ----------------------------------------------------------------------
// Set up the assemble environment
// ----------------------------------------------------------------------
private void setUpWorkingArea()
throws MojoFailureException
{
// create (if necessary) directory for bin files
File binDir = new File( assembleDirectory.getAbsolutePath(), "bin" );
if ( !binDir.exists() )
{
boolean success = binDir.mkdirs();
if ( !success )
{
throw new MojoFailureException( "Failed to create directory for bin files." );
}
}
}
private void copyConfigurationDirectory()
throws MojoFailureException
{
if ( !configurationSourceDirectory.exists() )
{
throw new MojoFailureException( "The source directory for configuration files does not exist: "
+ configurationSourceDirectory.getAbsolutePath() );
}
File configurationTargetDirectory = new File( assembleDirectory.getAbsolutePath(), configurationDirectory );
if ( !configurationTargetDirectory.exists() )
{
// Create (if necessary) target directory for configuration files
boolean success = configurationTargetDirectory.mkdirs();
if ( !success )
{
throw new MojoFailureException( "Failed to create the target directory for configuration files: "
+ configurationTargetDirectory.getAbsolutePath() );
}
try
{
getLog().debug( "Will try to copy configuration files from "
+ configurationSourceDirectory.getAbsolutePath() + " to "
+ configurationTargetDirectory.getAbsolutePath() );
FileUtils.copyDirectory( configurationSourceDirectory, configurationTargetDirectory,
null, getDefaultExcludesAsCommaSeparatedString() );
}
catch ( IOException e )
{
throw new MojoFailureException( "Failed to copy the configuration files." );
}
}
}
private String getDefaultExcludesAsCommaSeparatedString()
{
StringBuffer defaultExcludes = new StringBuffer();
List defaultExcludesAsList = FileUtils.getDefaultExcludesAsList();
Iterator iterator = defaultExcludesAsList.iterator();
while ( iterator.hasNext() )
{
String exclude = (String) iterator.next();
defaultExcludes.append( exclude );
if ( iterator.hasNext() )
{
defaultExcludes.append( "," );
}
}
return defaultExcludes.toString();
}
private Set validatePlatforms( Set platforms, Set defaultPlatforms )
throws MojoFailureException
{
if ( platforms == null )
{
return defaultPlatforms;
}
if ( platforms.size() == 1 && platforms.iterator().next().equals( "all" ) )
{
return VALID_PLATFORMS;
}
if ( !VALID_PLATFORMS.containsAll( platforms ) )
{
throw new MojoFailureException(
"Non-valid default platform declared, supported types are: " + VALID_PLATFORMS );
}
return platforms;
}
public static List parseTokens( String arg )
{
List extraJvmArguments = new ArrayList();
if ( StringUtils.isEmpty( arg ) )
{
return extraJvmArguments;
}
StringTokenizer tokenizer = new StringTokenizer( arg );
String argument = null;
while ( tokenizer.hasMoreTokens() )
{
String token = tokenizer.nextToken();
if ( argument != null )
{
if ( token.length() == 0 )
{
// ignore it
continue;
}
int length = token.length();
if ( token.charAt( length - 1 ) == '\"' )
{
extraJvmArguments.add( argument + " " + token.substring( 0, length - 1 ) );
argument = null;
}
else
{
argument += " " + token;
}
}
else
{
// If the token starts with a ", save it
if ( token.charAt( 0 ) == '\"' )
{
argument = token.substring( 1 );
}
else
{
extraJvmArguments.add( token );
}
}
}
return extraJvmArguments;
}
public void setAvailableRepositoryLayouts( Map availableRepositoryLayouts )
{
this.availableRepositoryLayouts = availableRepositoryLayouts;
}
/**
* Set the extensions for bin files for the supported platforms.
* The values are taken from the Mojo's <code>binFileExtensions</code> parameter.
*/
protected void setBinFileExtensions()
throws MojoFailureException
{
if ( binFileExtensions != null )
{
Set keySet = binFileExtensions.keySet();
Iterator iterator = keySet.iterator();
while ( iterator.hasNext() )
{
String platformName = (String) iterator.next();
if ( !VALID_PLATFORMS.contains( platformName ) )
{
getLog().warn( "Bin file extension configured for a non-valid platform (" + platformName
+ "), supported platforms are: " + VALID_PLATFORMS );
}
else
{
try
{
Platform platform = Platform.getInstance( platformName );
platform.setBinFileExtension( (String) binFileExtensions.get( platformName ) );
}
catch ( DaemonGeneratorException e )
{
getLog().warn( "Unable to set the bin file extension for " + platformName, e );
}
}
}
}
}
}