/*
* Copyright 2009 Toni Menzel.
*
* 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 org.ops4j.pax.exam.mavenplugin;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.maven.artifact.Artifact;
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.ArtifactCollector;
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.DefaultArtifactCollector;
import org.apache.maven.artifact.versioning.VersionRange;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.model.Dependency;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.project.MavenProject;
/**
* @author Toni Menzel (tonit)
* @goal generate-config
* @phase generate-resources
* @since Mar 17, 2009
*/
public class GenerateConfigMojo extends AbstractMojo
{
protected static final String SEPARATOR = "/";
private static final String SETTINGS_DEPENDENCY_OPTIONS = "dependency_options";
/**
* The maven project.
*
* @parameter expression="${project}"
* @required
* @readonly
*/
protected MavenProject project;
/**
* The file to generate
*
* @parameter default-value="${project.build.directory}/regression-classes/META-INF/maven/paxexam-config.args"
*/
private File configOutput;
/**
* @parameter default-value="provided"
*/
private String dependencyScope;
/**
* pax runner arguments defined in <options> tag in configuration of plugin.
*
* @parameter
*/
private Map<String, String> options = new HashMap<String,String>();
/**
* settings for this plugin in <settings> tag.
*
* @parameter
*/
private Map<String, String> settings = new HashMap<String,String>();
/**
* @component
*/
protected ArtifactMetadataSource artifactMetadataSource;
/**
* @component
*/
protected ArtifactResolver resolver;
protected ArtifactCollector collector = new DefaultArtifactCollector();
/**
* @component
*/
protected ArtifactFactory factory;
/**
* @parameter expression="${project.remoteArtifactRepositories}"
*/
private List<ArtifactRepository> remoteRepositories;
/**
* The Maven Session Object
*
* @parameter expression="${session}"
* @required
* @readonly
*/
private MavenSession session;
public void execute()
throws MojoExecutionException, MojoFailureException
{
OutputStream out = null;
try
{
configOutput.getParentFile().mkdirs();
out = new FileOutputStream( configOutput );
PrintStream printer = new PrintStream( out );
List<Dependency> dependencies;
dependencies = getProvisionableDependencies();
writeHeader( printer );
writeProvisioning( printer, dependencies );
writeSettings( printer );
getLog().info( "Generated configuration as Pax Runner arguments file " + configOutput );
}
catch( Exception e )
{
throw new MojoExecutionException(
"Unable to create dependencies file: " + e, e
);
}
finally
{
if( out != null )
{
try
{
out.close();
}
catch( IOException e )
{
getLog().info( "Failed to close: " + configOutput + ". Reason: " + e, e );
}
}
}
}
private void writeHeader( PrintStream out )
{
out.println( "# Configurations generated by the Pax Exam Maven Plugin" );
out.println( "# Generated at: " + new Date() );
out.println();
out.println( "# groupId = " + project.getGroupId() );
out.println( "# artifactId = " + project.getArtifactId() );
out.println( "# version = " + project.getVersion() );
out.println( "# " +
project.getGroupId() + SEPARATOR + project.getArtifactId() + SEPARATOR + "version = "
+ project.getVersion()
);
out.println();
}
private void writeSettings( PrintStream out )
{
out.println( "# Settings parsed from pom.xml in settings of plugin" );
for( String key : options.keySet() )
{
out.println( "--" + key + "=" + options.get( key ) );
}
out.println();
}
/**
* Dependency resolution inspired by servicemix depends-maven-plguin
*
* @return list of dependencies to be written to disk.
*/
private List<Dependency> getProvisionableDependencies()
{
List<Dependency> dependencies = new ArrayList<Dependency>();
getLog().info( "Adding dependencies in scope " + dependencyScope );
for( Dependency d : getDependencies() )
{
if( d.getScope() != null && d.getScope().equalsIgnoreCase( dependencyScope ) )
{
dependencies.add( d );
}
}
return dependencies;
}
@SuppressWarnings( "unchecked" )
private List<Dependency> getDependencies()
{
return (List<Dependency>) project.getDependencies();
}
protected void writeProvisioning( PrintStream out, List<Dependency> dependencies )
throws
ArtifactResolutionException,
ArtifactNotFoundException
{
out.println( "# provisioning" );
out.println();
for( Dependency dependency : dependencies )
{
Artifact artifact = factory.createDependencyArtifact(
dependency.getGroupId(), dependency.getArtifactId(),
VersionRange.createFromVersion( dependency.getVersion() ),
dependency.getType(), dependency.getClassifier(), dependency.getScope()
);
// try to find
boolean found = false;
for( MavenProject project : (List<MavenProject>) session.getSortedProjects() )
{
Artifact projectArtifact = project.getArtifact();
if( projectArtifact.getArtifactId().equals( artifact.getArtifactId() ) && (
projectArtifact.getGroupId().equals( artifact.getGroupId() ) && projectArtifact.getVersion()
.equals( artifact.getVersion() ) ) )
{
artifact = projectArtifact;
found = true;
break;
}
}
if( !found )
{
resolver.resolve( artifact, remoteRepositories, session.getLocalRepository() );
}
out.println(
createPaxRunnerScan( artifact,
getSettingsForArtifact( settings.get( SETTINGS_DEPENDENCY_OPTIONS ),
artifact.getGroupId(), artifact.getArtifactId()
)
)
);
getLog().debug( "Dependency: " + dependency
+ " classifier: " + dependency.getClassifier()
+ " type: " + dependency.getType()
);
}
out.println();
}
/**
* Example:
* getSettingsForArtifact ( "foo:bar@1,chees:ham2@3@nostart","cheese","ham") --> @3@nostart
*
* @param fullSettings settings separated by comma. GA patter + @options
* @param groupId GA part groupId to be matched inside fulllSettings
* @param artifactId GA part artifactId to be matched inside fulllSettings
*
* @return option portion of matched part in fullSettings or empty string if no matching.
*/
public String getSettingsForArtifact( String fullSettings, String groupId, String artifactId )
{
if( fullSettings != null )
{
for( String token : fullSettings.split( "," ) )
{
int end = ( token.indexOf( "@" ) >= 0 ) ? token.indexOf( "@" ) : token.length();
String ga_part[] = token.substring( 0, end ).split( ":" );
if( ga_part[ 0 ].equals( groupId ) && ga_part[ 1 ].equals( artifactId ) )
{
return token.substring( end );
}
}
}
return "";
}
/**
* Creates scanner directives from artifact to be parsed by pax runner.
* Also includes options found and matched in settings part of configuration.
*
* @param artifact to be used to create scanner directive.
* @param optionTokens to be used to create scanner directive.
*
* @return pax runner compatible scanner directive.
*/
private String createPaxRunnerScan( Artifact artifact, String optionTokens )
{
return "scan-bundle:" + artifact.getFile().toURI().normalize().toString() + "@update" + optionTokens;
}
}