All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.code.play2.plugin.AbstractPlay2Mojo Maven / Gradle / Ivy

There is a newer version: 1.0.0-rc5
Show newest version
/*
 * Copyright 2013-2014 Grzegorz Slowikowski (gslowikowski at gmail dot com)
 *
 * Licensed 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.
 */

package com.google.code.play2.plugin;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

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.resolver.filter.AndArtifactFilter;
import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
import org.apache.maven.artifact.resolver.filter.ScopeArtifactFilter;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugin.descriptor.PluginDescriptor;
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.ProjectBuildingException;
import org.apache.maven.project.artifact.InvalidDependencyVersionException;

import org.codehaus.plexus.util.FileUtils;

import com.google.code.play2.provider.api.Play2Provider;
import com.google.code.play2.provider.api.Play2Providers;

/**
 * Abstract base class for Play! Mojos.
 * 
 * @author Grzegorz Slowikowski
 */
public abstract class AbstractPlay2Mojo
    extends AbstractMojo
{
    /**
     * Used to automatically select one of the "well known" Play! providers if no provider added explicitly as plugin's dependency.
     * 
     * @since 1.0.0
     */
    @Parameter( property = "play2.version" )
    protected String playVersion;

    /**
     * Maven Internal: Project to interact with.
     */
    @Parameter( defaultValue = "${project}", readonly = true, required = true )
    protected MavenProject project;

    /**
     * Maven project builder used to resolve artifacts.
     */
    @Component
    protected MavenProjectBuilder projectBuilder;

    /**
     * Artifact factory used to look up artifacts in the remote repository.
     */
    @Component
    protected ArtifactFactory factory;

    /**
     * Artifact resolver used to resolve artifacts.
     */
    @Component
    protected ArtifactResolver resolver;

    /**
     * Location of the local repository.
     */
    @Parameter( property = "localRepository", readonly = true, required = true )
    protected ArtifactRepository localRepo;

    /**
     * Remote repositories used by the resolver
     */
    @Parameter( property = "project.remoteArtifactRepositories", readonly = true, required = true )
    protected List remoteRepos;

    /**
     * Plugin descriptor used to retrieve this plugin's properties.
     */
    @Parameter( defaultValue = "${plugin}", readonly = true, required = true )
    protected/*private*/ PluginDescriptor plugin;

    /**
     * Map of provider implementations. For now only zero or one allowed.
     */
    @Component( role = Play2Provider.class )
    private Map play2Providers;

    @Override
    public void execute()
        throws MojoExecutionException, MojoFailureException
    {
        if ( !"pom".equals( project.getPackaging() ) )
        {
            try
            {
                long ts = System.currentTimeMillis();
                internalExecute();
                long te = System.currentTimeMillis();
                getLog().debug( String.format( "Mojo execution time: %d ms", te - ts ) );
            }
            catch ( IOException e )
            {
                throw new MojoExecutionException( "?", e );
            }
        }
    }

    protected abstract void internalExecute()
        throws MojoExecutionException, MojoFailureException, IOException;

    protected final BufferedReader createBufferedFileReader( File file, String encoding )
        throws FileNotFoundException, UnsupportedEncodingException
    {
        return new BufferedReader( new InputStreamReader( new FileInputStream( file ), encoding ) );
    }

    protected final BufferedWriter createBufferedFileWriter( File file, String encoding )
        throws FileNotFoundException, UnsupportedEncodingException
    {
        return new BufferedWriter( new OutputStreamWriter( new FileOutputStream( file ), encoding ) );
    }

    protected String readFileFirstLine( File file )
        throws IOException
    {
        String result = null;

        BufferedReader is = createBufferedFileReader( file, "UTF-8" );
        try
        {
            result = is.readLine();
        }
        finally
        {
            is.close();
        }
        return result;
    }

    protected void writeToFile( File file, String line )
        throws IOException
    {
        BufferedWriter writer = createBufferedFileWriter( file, "UTF-8" );
        try
        {
            writer.write( line );
        }
        finally
        {
            writer.flush();
            writer.close();
        }
    }

    protected void createDirectory( File directory, boolean overwrite )
        throws IOException
    {
        if ( directory.exists() )
        {
            if ( directory.isDirectory() )
            {
                if ( overwrite )
                {
                    FileUtils.cleanDirectory( directory );
                }
            }
            else
            // file if ( directory.isFile() )
            {
                getLog().info( String.format( "Deleting \"%s\" file", directory ) ); // TODO-more descriptive message
                if ( !directory.delete() )
                {
                    throw new IOException( String.format( "Cannot delete \"%s\" file", directory.getCanonicalPath() ) );
                }
            }
        }

        if ( !directory.exists() )
        {
            if ( !directory.mkdirs() )
            {
                throw new IOException( String.format( "Cannot create \"%s\" directory", directory.getCanonicalPath() ) );
            }
        }
    }

    // Cached classloaders
    private static final ConcurrentHashMap cachedClassLoaders = new ConcurrentHashMap( 2 );

    private static ClassLoader getCachedClassLoader( String providerId )
    {
        return cachedClassLoaders.get( providerId );
    }

    private static void setCachedClassLoader( String providerId, ClassLoader classLoader )
    {
        cachedClassLoaders.put( providerId, classLoader );
    }

    protected Play2Provider getProvider()
        throws MojoExecutionException
    {
        Play2Provider provider = null;
        if ( !play2Providers.isEmpty() )
        {
            provider = getDeclaredProvider();
        }
        else
        {
            provider = getWellKnownProvider();
        }
        return provider;
    }

    private Play2Provider getDeclaredProvider()
        throws MojoExecutionException
    {
        if ( play2Providers.size() > 1 )
        {
            throw new MojoExecutionException( "Too many Play! providers defined. A maximum of one allowed." );
        }

        Map.Entry providerEntry = play2Providers.entrySet().iterator().next();
        String providerId = providerEntry.getKey();
        Play2Provider provider = providerEntry.getValue();

        getLog().debug( String.format( "Using declared provider \"%s\".", providerId ) );

        return provider;
    }

    private Play2Provider getWellKnownProvider()
        throws MojoExecutionException
    {
        try
        {
            String providerId = Play2Providers.getDefaultProviderId( playVersion );
            ClassLoader providerClassLoader = getCachedClassLoader( providerId );
            if ( providerClassLoader == null )
            {
                getLog().debug( String.format( "Cached classloader for provider \"%s\" not available.", providerId ) );
            }
            else
            {
                if ( providerClassLoader.getParent() == Thread.currentThread().getContextClassLoader() )
                {
                    getLog().debug( String.format( "Using cached classloader for provider \"%s\".", providerId ) );
                }
                else
                {
                    getLog().debug( String.format( "Invalidated cached classloader for provider \"%s\". Parent classloader changed from %d to %d.",
                                                   providerId,
                                                   Integer.valueOf( providerClassLoader.getParent().hashCode() ),
                                                   Integer.valueOf( Thread.currentThread().getContextClassLoader().hashCode() ) ) );
                    providerClassLoader = null;
                }
            }

            if ( providerClassLoader == null )
            {
                Artifact providerArtifact =
                    getResolvedArtifact( plugin.getGroupId(), "play2-provider-" + providerId,
                                         plugin.getVersion() );

                Set providerDependencies = getAllDependencies( providerArtifact );
                List classPathFiles = new ArrayList( providerDependencies.size() + 2 );
                classPathFiles.add( providerArtifact.getFile() );
                for ( Artifact dependencyArtifact : providerDependencies )
                {
                    classPathFiles.add( dependencyArtifact.getFile() );
                }

                List classPathUrls = new ArrayList( classPathFiles.size() );
                for ( File classPathFile : classPathFiles )
                {
                    classPathUrls.add( new URL( classPathFile.toURI().toASCIIString() ) );
                }

                providerClassLoader =
                    new URLClassLoader( classPathUrls.toArray( new URL[classPathUrls.size()] ),
                                        Thread.currentThread().getContextClassLoader() );
                getLog().debug( "Setting cached classloader for " + providerId );
                setCachedClassLoader( providerId, providerClassLoader );
            }

            String providerClassName =
                String.format( "com.google.code.play2.provider.%s.%sProvider", providerId,
                               providerId.substring( 0, 1 ).toUpperCase( Locale.ROOT ) + providerId.substring( 1 ) );
            Play2Provider provider = (Play2Provider) providerClassLoader.loadClass( providerClassName ).newInstance();

            getLog().debug( String.format( "Using autodetected provider \"%s\".", providerId ) );

            return provider;
        }
        catch ( ArtifactNotFoundException e )
        {
            throw new MojoExecutionException( "Provider autodetection failed", e );
        }
        catch ( ArtifactResolutionException e )
        {
            throw new MojoExecutionException( "Provider autodetection failed", e );
        }
        catch ( ClassNotFoundException e )
        {
            throw new MojoExecutionException( "Provider autodetection failed", e );
        }
        catch ( IllegalAccessException e )
        {
            throw new MojoExecutionException( "Provider autodetection failed", e );
        }
        catch ( InstantiationException e )
        {
            throw new MojoExecutionException( "Provider autodetection failed", e );
        }
        catch ( InvalidDependencyVersionException e )
        {
            throw new MojoExecutionException( "Provider autodetection failed", e );
        }
        catch ( MalformedURLException e )
        {
            throw new MojoExecutionException( "Provider autodetection failed", e );
        }
        catch ( ProjectBuildingException e )
        {
            throw new MojoExecutionException( "Provider autodetection failed", e );
        }
    }

    // Private utility methods

    protected/*private*/ Artifact getResolvedArtifact( String groupId, String artifactId, String version )
        throws ArtifactNotFoundException, ArtifactResolutionException
    {
        Artifact artifact = factory.createArtifact( groupId, artifactId, version, Artifact.SCOPE_RUNTIME, "jar" );
        resolver.resolve( artifact, remoteRepos, localRepo );
        return artifact;
    }

    protected/*private*/ Set getAllDependencies( Artifact artifact )
        throws ArtifactNotFoundException, ArtifactResolutionException, InvalidDependencyVersionException,
        ProjectBuildingException
    {
        Set result = new HashSet();
        MavenProject p = projectBuilder.buildFromRepository( artifact, remoteRepos, localRepo );
        Set d = resolveDependencyArtifacts( p );
        result.addAll( d );
        for ( Artifact dependency : d )
        {
            Set transitive = getAllDependencies( dependency );
            result.addAll( transitive );
        }
        return result;
    }

    /**
     * This method resolves the dependency artifacts from the project.
     * 
     * @param theProject The POM.
     * @return resolved set of dependency artifacts.
     * @throws ArtifactResolutionException
     * @throws ArtifactNotFoundException
     * @throws InvalidDependencyVersionException
     */
    private Set resolveDependencyArtifacts( MavenProject theProject )
        throws ArtifactNotFoundException, ArtifactResolutionException, InvalidDependencyVersionException
    {
        AndArtifactFilter filter = new AndArtifactFilter();
        filter.add( new ScopeArtifactFilter( Artifact.SCOPE_TEST ) );
        filter.add( new NonOptionalArtifactFilter() );
        // TODO follow the dependenciesManagement and override rules
        Set artifacts = theProject.createArtifacts( factory, Artifact.SCOPE_RUNTIME, filter );
        for ( Artifact artifact : artifacts )
        {
            resolver.resolve( artifact, remoteRepos, localRepo );
        }
        return artifacts;
    }

    private static class NonOptionalArtifactFilter
        implements ArtifactFilter
    {
        public boolean include( Artifact artifact )
        {
            return !artifact.isOptional();
        }
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy