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_COMPILE; import static org.apache.maven.artifact.Artifact.SCOPE_RUNTIME; import org.apache.commons.io.IOUtils; import org.apache.maven.artifact.Artifact; import org.apache.maven.artifact.ArtifactUtils; import org.apache.maven.artifact.factory.ArtifactFactory; import org.apache.maven.artifact.metadata.ArtifactMetadataSource; 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.ArtifactResolutionResult; 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.Dependency; import org.apache.maven.model.Resource; import org.apache.maven.plugin.AbstractMojo; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugins.annotations.Component; import org.apache.maven.plugins.annotations.Parameter; import org.apache.maven.project.MavenProject; import org.apache.maven.project.MavenProjectBuilder; import org.apache.maven.project.artifact.MavenMetadataSource; import org.codehaus.plexus.util.StringUtils; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Set; /** * 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 { protected static final String GWT_USER = "com.google.gwt:gwt-user"; protected static final String GWT_DEV = "com.google.gwt:gwt-dev"; /** GWT artifacts groupId */ public static final String GWT_GROUP_ID = "com.google.gwt"; // --- Some Maven tools ---------------------------------------------------- @Parameter(defaultValue = "${plugin.artifactMap}", required = true, readonly = true) private Map<String, Artifact> pluginArtifactMap; @Component private MavenProjectBuilder projectBuilder; @Component protected ArtifactResolver resolver; @Component protected ArtifactFactory artifactFactory; @Component protected ClasspathBuilder classpathBuilder; // --- Some MavenSession related structures -------------------------------- @Parameter(defaultValue = "${localRepository}", required = true, readonly = true) protected ArtifactRepository localRepository; @Parameter(defaultValue = "${project.pluginArtifactRepositories}", required = true, readonly = true) protected List<ArtifactRepository> remoteRepositories; @Component protected ArtifactMetadataSource artifactMetadataSource; /** * The maven project descriptor */ @Parameter(defaultValue = "${project}", required = true, readonly = true) private MavenProject project; // --- Plugin parameters --------------------------------------------------- /** * Folder where generated-source will be created (automatically added to compile classpath). */ @Parameter(defaultValue = "${project.build.directory}/generated-sources/gwt", required = true) private File generateDirectory; /** * Location on filesystem where GWT will write output files (-out option to GWTCompiler). */ @Parameter(property = "gwt.war", defaultValue="${project.build.directory}/${project.build.finalName}", alias = "outputDirectory") private File webappDirectory; /** * Prefix to prepend to module names inside {@code webappDirectory} or in URLs in DevMode. * <p> * Could also be seen as a suffix to {@code webappDirectory}. */ @Parameter(property = "gwt.modulePathPrefix") protected String modulePathPrefix; /** * Location of the web application static resources (same as maven-war-plugin parameter) */ @Parameter(defaultValue="${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(defaultValue = "false", property = "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 * * @since 2.1.0-1 * @deprecated tweak your dependencies and/or split your project with a client-only module */ @Deprecated @Parameter(defaultValue = "false", property = "gwt.gwtSdkFirstInClasspath") protected boolean gwtSdkFirstInClasspath; public File getOutputDirectory() { File out = inplace ? warSourceDirectory : webappDirectory; if ( !StringUtils.isBlank( modulePathPrefix ) ) { out = new File(out, modulePathPrefix); } return out; } /** * 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(), isGenerator() ); 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 ); } } /** * Whether to use processed resources and compiled classes ({@code false}), or raw resources ({@code true }). */ protected boolean isGenerator() { return false; } protected Collection<File> getGwtDevJar() throws MojoExecutionException { return getJarFiles( GWT_DEV, true ); } protected Collection<File> getGwtUserJar() throws MojoExecutionException { return getJarFiles( GWT_USER, true ); } protected Collection<File> getJarFiles(String artifactId, boolean detectProjectDependencies) throws MojoExecutionException { checkGwtUserVersion(); if (detectProjectDependencies) for (Artifact artifact : project.getArtifacts()) { String dependencyKey = ArtifactUtils.versionlessKey(artifact.getGroupId(), artifact.getArtifactId()); // if the project contains this GWT lib do not returns any jar, maven resolution should do that if (dependencyKey.equals(artifactId)) return Collections.emptyList(); } Artifact rootArtifact = pluginArtifactMap.get( artifactId ); ArtifactResolutionResult result; try { // Code shamelessly copied from exec-maven-plugin. MavenProject rootProject = this.projectBuilder.buildFromRepository( rootArtifact, this.remoteRepositories, this.localRepository ); List<Dependency> dependencies = rootProject.getDependencies(); Set<Artifact> dependencyArtifacts = MavenMetadataSource.createArtifacts( artifactFactory, dependencies, null, null, null ); dependencyArtifacts.add( rootProject.getArtifact() ); result = resolver.resolveTransitively( dependencyArtifacts, rootArtifact, Collections.EMPTY_MAP, localRepository, remoteRepositories, artifactMetadataSource, null, Collections.EMPTY_LIST); } catch (Exception e) { throw new MojoExecutionException( "Failed to resolve artifact", e); } Collection<Artifact> resolved = result.getArtifacts(); Collection<File> files = new ArrayList<File>(resolved.size() + 1 ); files.add( rootArtifact.getFile() ); for ( Artifact artifact : resolved ) { files.add( artifact.getFile() ); } return files; } /** * Check gwt-user dependency matches plugin version */ private void checkGwtUserVersion() throws MojoExecutionException { InputStream inputStream = Thread.currentThread().getContextClassLoader() .getResourceAsStream( "org/codehaus/mojo/gwt/mojoGwtVersion.properties" ); Properties properties = new Properties(); try { properties.load( inputStream ); } catch (IOException e) { throw new MojoExecutionException( "Failed to load plugin properties", e ); } finally { IOUtils.closeQuietly( inputStream ); } Artifact gwtUser = project.getArtifactMap().get( GWT_USER ); if (gwtUser != null) { String mojoGwtVersion = properties.getProperty( "gwt.version" ); //ComparableVersion with an up2date maven version ArtifactVersion mojoGwtArtifactVersion = new DefaultArtifactVersion( mojoGwtVersion ); ArtifactVersion userGwtArtifactVersion = new DefaultArtifactVersion( gwtUser.getVersion() ); if ( userGwtArtifactVersion.compareTo( mojoGwtArtifactVersion ) < 0 ) { getLog().warn( "Your project declares dependency on gwt-user " + gwtUser.getVersion() + ". This plugin is designed for at least gwt version " + mojoGwtVersion ); } } } 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; } protected File setupGenerateDirectory() { if ( !generateDirectory.exists() ) { getLog().debug( "Creating target directory " + generateDirectory.getAbsolutePath() ); generateDirectory.mkdirs(); } getLog().debug( "Add compile source root " + generateDirectory.getAbsolutePath() ); addCompileSourceRoot( generateDirectory ); return generateDirectory; } public File getGenerateDirectory() { if ( !generateDirectory.exists() ) { getLog().debug( "Creating target directory " + generateDirectory.getAbsolutePath() ); generateDirectory.mkdirs(); } return generateDirectory; } public Set<Artifact> getProjectArtifacts() { return project.getArtifacts(); } public Set<Artifact> getProjectRuntimeArtifacts() { Set<Artifact> artifacts = new HashSet<Artifact>(); for (Artifact projectArtifact : project.getArtifacts() ) { String scope = projectArtifact.getScope(); if ( SCOPE_RUNTIME.equals( scope ) || SCOPE_COMPILE.equals( scope ) ) { artifacts.add( projectArtifact ); } } return artifacts; } }