com.google.code.play2.plugin.Play2EbeanEnhanceMojo Maven / Gradle / Ivy
/*
* Copyright 2013-2017 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.File;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.plugins.annotations.ResolutionScope;
import com.typesafe.config.Config;
import com.typesafe.config.ConfigException;
import com.typesafe.config.ConfigFactory;
import com.typesafe.config.ConfigValue;
import com.typesafe.config.ConfigValueType;
import com.google.code.play2.provider.api.Play2EbeanEnhancer;
import com.google.code.play2.provider.api.Play2Provider;
import com.google.code.sbt.compiler.api.Analysis;
import com.google.code.sbt.compiler.api.AnalysisProcessor;
/**
* Enhence Ebean entity classes
*
* @author Grzegorz Slowikowski
* @since 1.0.0
*/
@Mojo( name = "ebean-enhance", defaultPhase = LifecyclePhase.PROCESS_CLASSES, requiresDependencyResolution = ResolutionScope.COMPILE )
public class Play2EbeanEnhanceMojo
extends AbstractPlay2EnhanceMojo
{
/**
* Project classpath.
*/
@Parameter( property = "project.compileClasspathElements", readonly = true, required = true )
private List classpathElements;
@Override
protected void internalExecute()
throws MojoExecutionException, MojoFailureException, IOException
{
Config config = getPlayConfiguration().resolve();
String models = getEBeanModelsToEnhance( config );
File outputDirectory = new File( project.getBuild().getOutputDirectory() );
File timestampFile = new File( getAnalysisCacheFile().getParentFile(), "play_ebean_instrumentation" );
long lastEnhanced = 0L;
if ( timestampFile.exists() )
{
String line = readFileFirstLine( timestampFile, "ASCII" );
lastEnhanced = Long.parseLong( line );
}
int processedFiles = 0;
int enhancedFiles = 0;
List modelClassesToEnhance = collectClassFilesToEnhance( lastEnhanced, outputDirectory, models );
if ( !modelClassesToEnhance.isEmpty() )
{
classpathElements.remove( outputDirectory.getAbsolutePath() );
List classpathFiles = new ArrayList( classpathElements.size() );
for ( String path : classpathElements )
{
classpathFiles.add( new File( path ) );
}
List classPathUrls = new ArrayList( classpathFiles.size() + 1 );
for ( File classpathFile : classpathFiles )
{
classPathUrls.add( classpathFile.toURI().toURL() );
}
classPathUrls.add( outputDirectory.toURI().toURL() );
Play2Provider play2Provider = getProvider();
Play2EbeanEnhancer enhancer = play2Provider.getEbeanEnhancer();
enhancer.setOutputDirectory( outputDirectory );
enhancer.setClassPathUrls( classPathUrls );
File analysisCacheFile = getAnalysisCacheFile();
if ( !analysisCacheFile.exists() )
{
throw new MojoExecutionException( String.format( "Analysis cache file \"%s\" not found",
analysisCacheFile.getAbsolutePath() ) );
}
if ( !analysisCacheFile.isFile() )
{
throw new MojoExecutionException( String.format( "Analysis cache \"%s\" is not a file",
analysisCacheFile.getAbsolutePath() ) );
}
Analysis analysis = null;
AnalysisProcessor sbtAnalysisProcessor = getSbtAnalysisProcessor();
if ( sbtAnalysisProcessor.areClassFileTimestampsSupported() )
{
analysis = sbtAnalysisProcessor.readFromFile( analysisCacheFile );
}
for ( File classFile: modelClassesToEnhance )
{
processedFiles++;
try
{
if ( enhancer.enhanceModel( classFile ) )
{
enhancedFiles++;
getLog().debug( String.format( "\"%s\" enhanced", classFile.getPath() ) );
if ( analysis != null )
{
analysis.updateClassFileTimestamp( classFile );
}
}
else
{
getLog().debug( String.format( "\"%s\" skipped", classFile.getPath() ) );
}
}
catch ( Exception e )
{
//??
}
}
if ( enhancedFiles > 0 )
{
if ( analysis != null )
{
analysis.writeToFile( analysisCacheFile );
}
writeToFile( timestampFile, "ASCII", Long.toString( System.currentTimeMillis() ) );
}
}
if ( processedFiles > 0 )
{
getLog().info( String.format( "%d Ebean %s processed, %d enhanced", Integer.valueOf( processedFiles ),
processedFiles > 1 ? "classes" : "class", Integer.valueOf( enhancedFiles ) ) );
}
else
{
getLog().info( "No Ebean classes to enhance" );
}
}
private Config getPlayConfiguration()
{
String configResource = System.getProperty( "config.resource" );
if ( configResource != null )
{
return ConfigFactory.parseResources( configResource );
}
String configFileName = System.getProperty( "config.file", "conf/application.conf" );
File applicationConfFile = new File( project.getBasedir(), configFileName );
return ConfigFactory.parseFileAnySyntax( applicationConfFile );
}
private String getEBeanModelsToEnhance( Config config )
{
try
{
StringBuilder collector = new StringBuilder();
Set> entries = config.getConfig( "ebean" ).entrySet();
for ( Map.Entry entry : entries )
{
ConfigValue configValue = entry.getValue();
if ( configValue.valueType() == ConfigValueType.STRING )
{
collector.append( ',' ).append( configValue.unwrapped().toString() );
}
else
{
String configKey = "ebean." + entry.getKey();
List tmpModels = config.getStringList( configKey );
for ( String tmpModel : tmpModels )
{
collector.append( ',' ).append( tmpModel );
}
}
}
return collector.length() != 0 ? collector.substring( 1 ) : null;
}
catch ( ConfigException.Missing e )
{
return "models.*";
}
}
/**
* Process all the comma delimited list of packages.
*
* Package names are effectively converted into a directory on the file
* system, and the class files are found and processed.
*
*
* @param lastEnhanced previous enhancement timestamp
* @param outputDirectory directory containing classes to enhance
* @param packageNames package names include filter
* @return list of files to enhance
*/
public List collectClassFilesToEnhance( long lastEnhanced, File outputDirectory, String packageNames )
{
if ( packageNames == null || packageNames.isEmpty() )
{
return collectClassFilesToEnhanceFromPackage( lastEnhanced, outputDirectory, "", true );
// return;
}
List result = new ArrayList();
String[] pkgs = packageNames.split( "," );
for ( int i = 0; i < pkgs.length; i++ )
{
String pkg = pkgs[i].trim().replace( '.', '/' );
boolean recurse = false;
if ( pkg.endsWith( "**" ) )
{
recurse = true;
pkg = pkg.substring( 0, pkg.length() - 2 );
}
else if ( pkg.endsWith( "*" ) )
{
recurse = true;
pkg = pkg.substring( 0, pkg.length() - 1 );
}
pkg = trimSlash( pkg );
result.addAll( collectClassFilesToEnhanceFromPackage( lastEnhanced, outputDirectory, pkg, recurse ) );
}
return result;
}
private List collectClassFilesToEnhanceFromPackage( long lastEnhanced, File outputDirectory, String dir,
boolean recurse )
{
List result = new ArrayList();
File d = new File( outputDirectory.getAbsolutePath(), dir );
if ( !d.exists() )
{
getLog().warn( String.format( "\"%s\" directory does not exist", d.getPath() ) );
}
else if ( !d.isDirectory() )
{
getLog().warn( String.format( "\"%s\" is not a directory", d.getPath() ) );
}
else
{
for ( File file: d.listFiles() )
{
if ( file.isDirectory() )
{
if ( recurse )
{
String subdir = dir + "/" + file.getName();
result.addAll( collectClassFilesToEnhanceFromPackage( lastEnhanced, outputDirectory, subdir,
recurse ) );
}
}
else
{
if ( file.getName().endsWith( ".class" ) && ( file.lastModified() > lastEnhanced ) )
{
result.add( file );
// transformFile(file);
}
}
}
}
return result;
}
private String trimSlash( String dir )
{
String result = dir;
if ( dir.endsWith( "/" ) )
{
result = dir.substring( 0, dir.length() - 1 );
}
return result;
}
}