package org.codehaus.mojo.gwt;
/*
* 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 static org.apache.maven.artifact.Artifact.SCOPE_TEST;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import org.apache.commons.io.IOUtils;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.factory.ArtifactFactory;
import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
import org.apache.maven.artifact.resolver.ArtifactResolutionException;
import org.apache.maven.artifact.resolver.ArtifactResolver;
import org.apache.maven.artifact.versioning.ArtifactVersion;
import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
import org.apache.maven.model.Resource;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.project.MavenProject;
/**
* Abstract Support class for all GWT-related operations.
* <p>
* Provide methods to build classpath for GWT SDK tools.
*
* @author <a href="mailto:nicolas@apache.org">Nicolas De Loof</a>
* @version $Id$
*/
public abstract class AbstractGwtMojo
extends AbstractMojo
{
/** GWT artifacts groupId */
public static final String GWT_GROUP_ID = "com.google.gwt";
// --- Some Maven tools ----------------------------------------------------
/**
* @parameter expression="${plugin.version}"
* @required
* @readonly
*/
private String version;
/**
* @parameter expression="${plugin.artifactMap}"
*/
private Map<String, Artifact> pluginArtifacts;
/**
* @component
*/
protected ArtifactResolver resolver;
/**
* @component
*/
protected ArtifactFactory artifactFactory;
/**
* @required
* @readonly
* @component
*/
protected ClasspathBuilder classpathBuilder;
// --- Some MavenSession related structures --------------------------------
/**
* @parameter expression="${localRepository}"
* @required
* @readonly
*/
protected ArtifactRepository localRepository;
/**
* @parameter expression="${project.remoteArtifactRepositories}"
* @required
* @readonly
*/
protected List<ArtifactRepository> remoteRepositories;
/**
* The maven project descriptor
*
* @parameter expression="${project}"
* @required
* @readonly
*/
private MavenProject project;
// --- Plugin parameters ---------------------------------------------------
/**
* Folder where generated-source will be created (automatically added to compile classpath).
*
* @parameter default-value="${project.build.directory}/generated-sources/gwt"
* @required
*/
private File generateDirectory;
/**
* Location on filesystem where GWT will write output files (-out option to GWTCompiler).
*
* @parameter expression="${gwt.war}" default-value="${project.build.directory}/${project.build.finalName}"
* @alias outputDirectory
*/
private File webappDirectory;
/**
* Location of the web application static resources (same as maven-war-plugin parameter)
*
* @parameter default-value="${basedir}/src/main/webapp"
*/
protected File warSourceDirectory;
/**
* Select the place where GWT application is built. In <code>inplace</code> mode, the warSourceDirectory is used to
* match the same use case of the {@link war:inplace
* http://maven.apache.org/plugins/maven-war-plugin/inplace-mojo.html} goal.
*
* @parameter default-value="false" expression="${gwt.inplace}"
*/
private boolean inplace;
/**
* The forked command line will use gwt sdk jars first in classpath.
* see issue http://code.google.com/p/google-web-toolkit/issues/detail?id=5290
*
* @parameter default-value="false" expression="${gwt.gwtSdkFirstInClasspath}"
* @since 2.1.0-1
*/
protected boolean gwtSdkFirstInClasspath;
public File getOutputDirectory()
{
return inplace ? warSourceDirectory : webappDirectory;
}
/**
* Add classpath elements to a classpath URL set
*
* @param elements the initial URL set
* @param urls the urls to add
* @param startPosition the position to insert URLS
* @return full classpath URL set
* @throws MojoExecutionException some error occured
*/
protected int addClasspathElements( Collection<?> elements, URL[] urls, int startPosition )
throws MojoExecutionException
{
for ( Object object : elements )
{
try
{
if ( object instanceof Artifact )
{
urls[startPosition] = ( (Artifact) object ).getFile().toURI().toURL();
}
else if ( object instanceof Resource )
{
urls[startPosition] = new File( ( (Resource) object ).getDirectory() ).toURI().toURL();
}
else
{
urls[startPosition] = new File( (String) object ).toURI().toURL();
}
}
catch ( MalformedURLException e )
{
throw new MojoExecutionException(
"Failed to convert original classpath element " + object + " to URL.",
e );
}
startPosition++;
}
return startPosition;
}
/**
* Build the GWT classpath for the specified scope
*
* @param scope Artifact.SCOPE_COMPILE or Artifact.SCOPE_TEST
* @return a collection of dependencies as Files for the specified scope.
* @throws MojoExecutionException if classPath building failed
*/
public Collection<File> getClasspath( String scope )
throws MojoExecutionException
{
try
{
Collection<File> files = classpathBuilder.buildClasspathList( getProject(), scope, getProjectArtifacts() );
if ( getLog().isDebugEnabled() )
{
getLog().debug( "GWT SDK execution classpath :" );
for ( File f : files )
{
getLog().debug( " " + f.getAbsolutePath() );
}
}
return files;
}
catch ( ClasspathBuilderException e )
{
throw new MojoExecutionException( e.getMessage(), e );
}
}
// FIXME move to GwtDevHelper stuff to avoid duplicates
protected File getGwtDevJar()
throws IOException
{
checkGwtDevAsDependency();
checkGwtUserVersion();
return pluginArtifacts.get( "com.google.gwt:gwt-dev" ).getFile();
}
protected File getGwtUserJar()
throws IOException
{
checkGwtUserVersion();
return pluginArtifacts.get( "com.google.gwt:gwt-user" ).getFile();
}
/**
* TODO remove !
* Check that gwt-dev is not define in dependencies : this can produce version conflicts with other dependencies, as
* gwt-dev is a "uber-jar" with some commons-* and jetty libs inside.
*/
private void checkGwtDevAsDependency()
{
for ( Iterator iterator = getProject().getArtifacts().iterator(); iterator.hasNext(); )
{
Artifact artifact = (Artifact) iterator.next();
if ( GWT_GROUP_ID.equals( artifact.getGroupId() )
&& "gwt-dev".equals( artifact.getArtifactId() )
&& !SCOPE_TEST.equals( artifact.getScope() ) )
{
getLog().warn( "Don't declare gwt-dev as a project dependency. This may introduce complex dependency conflicts" );
}
}
}
/**
* Check gwt-user dependency matches plugin version
*/
private void checkGwtUserVersion() throws IOException
{
InputStream inputStream = Thread.currentThread().getContextClassLoader()
.getResourceAsStream( "org/codehaus/mojo/gwt/mojoGwtVersion.properties" );
Properties properties = new Properties();
try
{
properties.load( inputStream );
}
finally
{
IOUtils.closeQuietly( inputStream );
}
for ( Iterator iterator = getProject().getCompileArtifacts().iterator(); iterator.hasNext(); )
{
Artifact artifact = (Artifact) iterator.next();
if ( GWT_GROUP_ID.equals( artifact.getGroupId() )
&& "gwt-user".equals( artifact.getArtifactId() ) )
{
String mojoGwtVersion = properties.getProperty( "gwt.version" );
//ComparableVersion with an up2date maven version
ArtifactVersion mojoGwtArtifactVersion = new DefaultArtifactVersion( mojoGwtVersion );
ArtifactVersion userGwtArtifactVersion = new DefaultArtifactVersion( artifact.getVersion() );
if ( userGwtArtifactVersion.compareTo( mojoGwtArtifactVersion ) < 0 )
{
getLog().warn( "You're project declares dependency on gwt-user " + artifact.getVersion()
+ ". This plugin is designed for at least gwt version " + mojoGwtVersion );
}
break;
}
}
}
protected Artifact resolve( String groupId, String artifactId, String version, String type, String classifier )
throws MojoExecutionException
{
// return project.getArtifactMap().get( groupId + ":" + artifactId );
Artifact artifact = artifactFactory.createArtifactWithClassifier( groupId, artifactId, version, type, classifier );
try
{
resolver.resolve( artifact, remoteRepositories, localRepository );
}
catch ( ArtifactNotFoundException e )
{
throw new MojoExecutionException( "artifact not found - " + e.getMessage(), e );
}
catch ( ArtifactResolutionException e )
{
throw new MojoExecutionException( "artifact resolver problem - " + e.getMessage(), e );
}
return artifact;
}
/**
* @param path file to add to the project compile directories
*/
protected void addCompileSourceRoot( File path )
{
getProject().addCompileSourceRoot( path.getAbsolutePath() );
}
/**
* @return the project
*/
public MavenProject getProject()
{
return project;
}
public ArtifactRepository getLocalRepository()
{
return this.localRepository;
}
public List<ArtifactRepository> getRemoteRepositories()
{
return this.remoteRepositories;
}
public File getGenerateDirectory()
{
if ( !generateDirectory.exists() )
{
getLog().debug( "Creating target directory " + generateDirectory.getAbsolutePath() );
generateDirectory.mkdirs();
}
return generateDirectory;
}
@SuppressWarnings( "unchecked" )
public Set<Artifact> getProjectArtifacts()
{
return project.getArtifacts();
}
}