package org.codehaus.mojo.gae;
/*
* 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 java.io.File;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.DependencyResolutionRequiredException;
import org.apache.maven.artifact.factory.ArtifactFactory;
import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.artifact.resolver.ArtifactResolver;
import org.apache.maven.model.Dependency;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.project.MavenProject;
import org.codehaus.plexus.PlexusConstants;
import org.codehaus.plexus.PlexusContainer;
import org.codehaus.plexus.archiver.UnArchiver;
import org.codehaus.plexus.archiver.manager.ArchiverManager;
import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
import org.codehaus.plexus.context.Context;
import org.codehaus.plexus.context.ContextException;
import org.codehaus.plexus.util.DirectoryScanner;
import org.codehaus.plexus.util.StringUtils;
import org.codehaus.plexus.util.cli.CommandLineUtils;
import org.codehaus.plexus.util.cli.Commandline;
import org.codehaus.plexus.util.cli.StreamConsumer;
/**
* Base class for GAE related Mojos
*
* @author <a href="mailto:nicolas@apache.org">Nicolas De Loof</a>
* @requireDepedencyResolution compile
*/
public abstract class AbstractGoogleAppEngineMojo
extends AbstractMojo
{
public static final String GAE_GROUPID = "com.google.appegine";
public static final String GAE_ARTIFACTID = "appengine-api-1.0-sdk";
/**
* Location of a local AppEngine SDK
*
* @parameter
*/
private File sdkHome;
/**
* AppEngine version to resolve and use within project
*
* @parameter default-value="1.2.0"
*/
private String sdkVersion;
/**
* The maven project descriptor
*
* @parameter expression="${project}"
* @required
* @readonly
*/
private MavenProject project;
/**
* @parameter default-value="${basedir}/war"
*/
private File webappDirectory;
/**
* @component
*/
protected ArtifactResolver resolver;
/**
* @component
*/
protected ArtifactFactory artifactFactory;
/**
* @component
*/
protected ArchiverManager archiverManager;
/**
* @parameter expression="${localRepository}"
* @required
* @readonly
*/
protected ArtifactRepository localRepository;
/**
* @parameter expression="${project.remoteArtifactRepositories}"
* @required
* @readonly
*/
protected List<ArtifactRepository> remoteRepositories;
protected void executeSDKClass( String className, String[] args, boolean includORM )
throws MojoExecutionException
{
// Use a Set to avoid duplicates in classpath
// i.e. DataNucleus loading error with "Plugin (Bundle) is already registered"
Set<String> classpath = new LinkedHashSet<String>();
File sdk = resolveSDK();
// Include all SDK libs in classpath
// ugly, but SDK has no POM :'(
DirectoryScanner scanner = new DirectoryScanner();
scanner.setBasedir( sdk );
if ( includORM )
{
scanner.setIncludes( new String[] { "lib/tools/orm/*.jar", "lib/appengine-tools-api.jar" } );
}
else
{
scanner.setIncludes( new String[] { "lib/appengine-tools-api.jar" } );
}
scanner.scan();
for ( String path : scanner.getIncludedFiles() )
{
classpath.add( new File( sdk, path ).getAbsolutePath() );
}
List<String> artifacts;
try
{
artifacts = project.getCompileClasspathElements();
}
catch ( DependencyResolutionRequiredException e )
{
throw new MojoExecutionException( "Failed to resolve project dependencies", e );
}
classpath.addAll( artifacts );
String cp = StringUtils.join( classpath.iterator(), File.pathSeparator );
Commandline cmd = new Commandline();
cmd.setExecutable( getJavaCommand() );
cmd.createArg().setValue( "-cp" );
cmd.createArg().setValue( cp );
cmd.createArg().setValue( className );
for ( String arg : args )
{
cmd.createArg().setValue( arg );
}
try
{
getLog().debug( "Execute \n" + cmd );
CommandLineUtils.executeCommandLine( cmd, System.in, out, err );
}
catch ( Exception e )
{
getLog().error( "Failed to execute SDK tool " + className, e );
throw new MojoExecutionException( "Google App Engine SDK tool failed", e );
}
}
private String getJavaCommand()
throws MojoExecutionException
{
String jvm = System.getProperty( "java.home" );
// does-it exists ? is-it a directory or a path to a java executable ?
File jvmFile = new File( jvm );
if ( !jvmFile.exists() )
{
throw new MojoExecutionException( "the configured jvm " + jvm
+ " doesn't exists please check your environnement" );
}
if ( jvmFile.isDirectory() )
{
// it's a directory we construct the path to the java executable
return jvmFile.getAbsolutePath() + File.separator + "bin" + File.separator + "java";
}
return jvm;
}
protected File resolveSDK()
throws MojoExecutionException
{
if ( sdkHome != null )
{
return sdkHome;
}
getSDKVersion();
Artifact appEngineSDK =
artifactFactory.createArtifactWithClassifier( "com.google.appengine", "appengine-java-sdk", sdkVersion,
"zip", null );
File repoLocation = new File( localRepository.getBasedir() + "/" + localRepository.pathOf( appEngineSDK ) );
sdkHome = new File( repoLocation.getParentFile(), "appengine-java-sdk-" + sdkVersion );
if ( sdkHome.exists() )
{
getLog().info( "SDK " + sdkVersion + " allready available in local repository" );
return sdkHome;
}
try
{
getLog().info( "Resolve dependency for Google App Engine SDK version " + sdkVersion );
resolver.resolve( appEngineSDK, remoteRepositories, localRepository );
getLog().debug( "Unpack SDK in " + sdkHome );
unpackSDK( appEngineSDK.getFile() );
}
catch ( Exception e )
{
getLog().error( "Failed to resolve AppEngine SDK for version " + sdkVersion, e );
throw new MojoExecutionException( "Failed to resolve SDK" );
}
return sdkHome;
}
public String getSDKVersion()
throws MojoExecutionException
{
if ( sdkHome != null )
{
// TODO detect SDK version ...
}
if ( sdkVersion == null )
{
detectVersionFromDependencies();
}
return sdkVersion;
}
private void detectVersionFromDependencies()
throws MojoExecutionException
{
// detect form dependencies
Collection<Artifact> artifacts = project.getArtifacts();
for ( Artifact artifact : artifacts )
{
if ( GAE_GROUPID.equals( artifact.getGroupId() ) && GAE_ARTIFACTID.equals( artifact.getArtifactId() ) )
{
sdkVersion = artifact.getVersion();
break;
}
}
if ( sdkVersion == null )
{
if ( project.getDependencyManagement() != null
&& project.getDependencyManagement().getDependencies() != null )
{
Collection<Dependency> dependencyManagement = project.getDependencyManagement().getDependencies();
for ( Dependency dependency : dependencyManagement )
{
if ( GAE_GROUPID.equals( dependency.getGroupId() )
&& GAE_ARTIFACTID.equals( dependency.getArtifactId() ) )
{
sdkVersion = dependency.getVersion();
break;
}
}
}
}
if ( sdkVersion == null )
{
throw new MojoExecutionException( "Cannot detect the Google App Engine SDK version to use" );
}
}
private void unpackSDK( File zip )
throws MojoExecutionException
{
try
{
UnArchiver unArchiver = archiverManager.getUnArchiver( zip );
unArchiver.setSourceFile( zip );
unArchiver.setDestDirectory( zip.getParentFile() );
unArchiver.extract();
unArchiver.setOverwrite( false );
getLog().info( "Unpack Google App Engine SDK" );
}
catch ( Exception e )
{
getLog().error( "Failed to unpack Google App Engine SDK", e );
throw new MojoExecutionException( "SDK setup failed" );
}
}
public final void contextualize( Context context )
throws ContextException
{
PlexusContainer plexusContainer = (PlexusContainer) context.get( PlexusConstants.PLEXUS_KEY );
try
{
archiverManager = (ArchiverManager) plexusContainer.lookup( ArchiverManager.ROLE );
}
catch ( ComponentLookupException e )
{
throw new ContextException( e.getMessage(), e );
}
}
public MavenProject getProject()
{
return project;
}
/**
* A plexus-util StreamConsumer to redirect messages to plugin log
*/
protected StreamConsumer out = new StreamConsumer()
{
public void consumeLine( String line )
{
getLog().info( line );
}
};
/**
* A plexus-util StreamConsumer to redirect errors to plugin log
*/
protected StreamConsumer err = new StreamConsumer()
{
public void consumeLine( String line )
{
getLog().error( line );
}
};
public String getWebappDirectory()
{
return webappDirectory.getAbsolutePath();
}
public File getWebappDirectoryFile()
{
return webappDirectory;
}
}