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 java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.apache.commons.lang.ArrayUtils;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.model.Resource;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugins.annotations.Parameter;
import org.codehaus.mojo.gwt.utils.DefaultGwtModuleReader;
import org.codehaus.mojo.gwt.utils.GwtModuleReaderException;
import org.codehaus.plexus.util.DirectoryScanner;
import org.codehaus.plexus.util.ReaderFactory;
import org.codehaus.plexus.util.xml.Xpp3Dom;
import org.codehaus.plexus.util.xml.Xpp3DomBuilder;
/**
* Add support for GWT Modules.
* <p>
* Search and read the gwt.xml module files to detect project structure.
*
* @author <a href="mailto:nicolas@apache.org">Nicolas De Loof</a>
* @version $Id$
*/
public abstract class AbstractGwtModuleMojo
extends AbstractGwtMojo
implements GwtModuleReader
{
/**
* The project GWT modules. If not set, the plugin will scan the project for <code>.gwt.xml</code> files.
*/
@Parameter(alias = "compileTargets")
private String[] modules;
/**
* A single GWT module. Shortcut for <modules> or option to specify a single module from command line
*/
@Parameter(property = "gwt.module")
private String module;
public List<String> getGwtModules()
{
String[] modules = getModules();
return ArrayUtils.isEmpty( modules )? new ArrayList<String>(0) : Arrays.asList( modules );
}
/**
* Return the configured modules or scan the project source/resources folder to find them
*
* @return the modules
*/
// FIXME move to DefaultGwtModuleReader !
public String[] getModules()
{
// module has higher priority if set by expression
if ( module != null )
{
return new String[] { module };
}
if ( modules == null )
{
//Use a Set to avoid duplicate when user set src/main/java as <resource>
Set<String> mods = new HashSet<String>();
Collection<String> sourcePaths = getProject().getCompileSourceRoots();
for ( String sourcePath : sourcePaths )
{
File sourceDirectory = new File( sourcePath );
if ( sourceDirectory.exists() )
{
DirectoryScanner scanner = new DirectoryScanner();
scanner.setBasedir( sourceDirectory.getAbsolutePath() );
scanner.setIncludes( new String[] { "**/*" + DefaultGwtModuleReader.GWT_MODULE_EXTENSION } );
scanner.scan();
mods.addAll( Arrays.asList( scanner.getIncludedFiles() ) );
}
}
Collection<Resource> resources = getProject().getResources();
for ( Resource resource : resources )
{
File resourceDirectoryFile = new File( resource.getDirectory() );
if ( !resourceDirectoryFile.exists() )
{
continue;
}
DirectoryScanner scanner = new DirectoryScanner();
scanner.setBasedir( resource.getDirectory() );
scanner.setIncludes( new String[] { "**/*" + DefaultGwtModuleReader.GWT_MODULE_EXTENSION } );
scanner.scan();
mods.addAll( Arrays.asList( scanner.getIncludedFiles() ) );
}
if ( mods.isEmpty() )
{
getLog().warn( "GWT plugin is configured to detect modules, but none were found." );
}
modules = new String[mods.size()];
int i = 0;
for ( String fileName : mods )
{
String path =
fileName.substring( 0, fileName.length() - DefaultGwtModuleReader.GWT_MODULE_EXTENSION.length() );
modules[i++] = path.replace( File.separatorChar, '.' );
}
if ( modules.length > 0 )
{
getLog().info( "auto discovered modules " + Arrays.asList( modules ) );
}
}
return modules;
}
public GwtModule readModule( String name )
throws GwtModuleReaderException
{
String modulePath = name.replace( '.', '/' ) + DefaultGwtModuleReader.GWT_MODULE_EXTENSION;
Collection<String> sourceRoots = getProject().getCompileSourceRoots();
for ( String sourceRoot : sourceRoots )
{
File root = new File( sourceRoot );
File xml = new File( root, modulePath );
if ( xml.exists() )
{
getLog().debug( "GWT module " + name + " found in " + root );
return readModule( name, xml );
}
}
Collection<Resource> resources = getProject().getResources();
for ( Resource resource : resources )
{
File root = new File( resource.getDirectory() );
File xml = new File( root, modulePath );
if ( xml.exists() )
{
getLog().debug( "GWT module " + name + " found in " + root );
return readModule( name, xml );
}
}
try
{
Collection<File> classpath = getClasspath( Artifact.SCOPE_COMPILE );
URL[] urls = new URL[classpath.size()];
int i = 0;
for ( File file : classpath )
{
urls[i++] = file.toURI().toURL();
}
InputStream stream = new URLClassLoader( urls ).getResourceAsStream( modulePath );
if ( stream != null )
{
return readModule( name, stream );
}
}
catch ( MalformedURLException e )
{
// ignored;
} catch (MojoExecutionException e)
{
throw new GwtModuleReaderException(e.getMessage(), e);
}
throw new GwtModuleReaderException( "GWT Module " + name + " not found in project sources or resources." );
}
private GwtModule readModule( String name, File file )
throws GwtModuleReaderException
{
try
{
GwtModule module = readModule( name, new FileInputStream( file ) );
module.setSourceFile(file);
return module;
}
catch ( FileNotFoundException e )
{
throw new GwtModuleReaderException( "Failed to read module file " + file );
}
}
/**
* @param module2
* @return
*/
private GwtModule readModule( String name, InputStream xml )
throws GwtModuleReaderException
{
try
{
Xpp3Dom dom = Xpp3DomBuilder.build( ReaderFactory.newXmlReader( xml ) );
return new GwtModule( name, dom, this );
}
catch ( Exception e )
{
String error = "Failed to read module XML file " + xml;
getLog().error( error );
throw new GwtModuleReaderException( error, e );
}
}
}