package org.codehaus.mojo.clirr;
/*
* Copyright 2006 The Codehaus
*
* 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.
*/
import net.sf.clirr.core.ApiDifference;
import net.sf.clirr.core.Checker;
import net.sf.clirr.core.ClassFilter;
import net.sf.clirr.core.PlainDiffListener;
import net.sf.clirr.core.Severity;
import net.sf.clirr.core.XmlDiffListener;
import net.sf.clirr.core.internal.bcel.BcelTypeArrayBuilder;
import net.sf.clirr.core.spi.JavaType;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
import org.apache.maven.artifact.resolver.ArtifactResolutionException;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.project.ProjectBuildingException;
import org.apache.maven.project.artifact.InvalidDependencyVersionException;
import org.codehaus.plexus.i18n.I18N;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Set;
/**
* Check for compatibility between two arbitrary artifact sets.
*
* @author <a href="mailto:brett@apache.org">Brett Porter</a>
* @author <a href="mailto:jmcconnell@apache.org">Jesse McConnell</a>
* @goal check-arbitrary
* @phase verify
* @execute phase="compile"
*/
public class ClirrArbitraryCheckMojo
extends AbstractClirrMojo
{
/**
* Whether to fail on errors.
*
* @parameter expression="${failOnError}" default-value="true"
*/
private boolean failOnError;
/**
* Whether to fail on warnings.
*
* @parameter expression="${failOnWarning}" default-value="false"
*/
private boolean failOnWarning;
/**
* @component
*/
private I18N i18n;
/**
* List of artifacts to serve as a baseline to compare against.
*
* @parameter
* @required
*/
protected ArtifactSpecification[] oldComparisonArtifacts;
/**
* List of artifacts to compare to baseline.
*
* @parameter
* @required
*/
protected ArtifactSpecification[] newComparisonArtifacts;
protected void doExecute()
throws MojoExecutionException, MojoFailureException
{
if ( oldComparisonArtifacts == null || oldComparisonArtifacts.length == 0 )
{
getLog().info( "Missing required oldComparisonArtifacts" );
}
if ( newComparisonArtifacts == null || newComparisonArtifacts.length == 0 )
{
getLog().info( "Missing required newComparisonArtifacts" );
}
ClirrDiffListener listener;
try
{
listener = executeClirr( Severity.INFO );
}
catch ( MissingPreviousException e )
{
getLog().debug( e );
getLog().info( "No previous version was found. Use 'comparisonArtifacts'"
+ " for explicit configuration if you think this is wrong." );
return;
}
Locale locale = Locale.getDefault();
int errorCount = listener.getSeverityCount( Severity.ERROR );
if ( failOnError && errorCount > 0 )
{
log( listener, Severity.ERROR );
String message;
if ( errorCount > 1 )
{
String[] args = new String[]{String.valueOf( errorCount )};
message = i18n.format( "clirr-report", locale, "check.clirr.failure.errors", args );
}
else
{
message = i18n.getString( "clirr-report", locale, "check.clirr.failure.error" );
}
throw new MojoFailureException( message );
}
int warningCount = listener.getSeverityCount( Severity.WARNING );
if ( failOnWarning && errorCount > 0 )
{
log( listener, Severity.WARNING );
String message;
if ( errorCount > 1 )
{
String[] args = new String[]{String.valueOf( errorCount )};
message = i18n.format( "clirr-report", locale, "check.clirr.failure.warnings", args );
}
else
{
message = i18n.getString( "clirr-report", locale, "check.clirr.failure.warning" );
}
throw new MojoFailureException( message );
}
int infoCount = listener.getSeverityCount( Severity.INFO );
String[] args =
new String[]{String.valueOf( errorCount ), String.valueOf( warningCount ), String.valueOf( infoCount )};
getLog().info( i18n.format( "clirr-report", locale, "check.clirr.success", args ) );
}
private void log( ClirrDiffListener listener, Severity severity )
{
if ( !logResults )
{
LogDiffListener l = new LogDiffListener( getLog() );
for ( Iterator i = listener.getApiDifferences().iterator(); i.hasNext(); )
{
ApiDifference difference = (ApiDifference) i.next();
if ( difference.getMaximumSeverity().equals( severity ) )
{
l.reportDiff( difference );
}
}
}
}
protected JavaType[] resolveClasses( ArtifactSpecification[] artifacts, ClassFilter classFilter )
throws MojoFailureException, MojoExecutionException
{
final Set artifactSet;
artifactSet = resolveArtifacts( artifacts );
Artifact a = null;
for ( Iterator iter = artifactSet.iterator(); iter.hasNext(); )
{
Artifact artifact = (Artifact) iter.next();
if ( a == null )
{
a = artifact;
}
getLog().debug( "Comparing to " + artifact.getGroupId() + ":" + artifact.getArtifactId() + ":"
+ artifact.getVersion() + ":" + artifact.getClassifier() + ":" + artifact.getType() );
}
try
{
for ( Iterator iter = artifactSet.iterator(); iter.hasNext(); )
{
Artifact artifact = (Artifact) iter.next();
resolver.resolve( artifact, project.getRemoteArtifactRepositories(), localRepository );
}
final List dependencies = getTransitiveDependencies( artifactSet );
ClassLoader origDepCL = createClassLoader( dependencies, artifactSet );
final File[] files = new File[artifactSet.size()];
int i = 0;
for ( Iterator iter = artifactSet.iterator(); iter.hasNext(); )
{
Artifact artifact = (Artifact) iter.next();
files[i++] = new File( localRepository.getBasedir(), localRepository.pathOf( artifact ) );
}
return BcelTypeArrayBuilder.createClassSet( files, origDepCL, classFilter );
}
catch ( ProjectBuildingException e )
{
throw new MojoExecutionException( "Failed to build project for previous artifact: " + e.getMessage(), e );
}
catch ( InvalidDependencyVersionException e )
{
throw new MojoExecutionException( e.getMessage(), e );
}
catch ( ArtifactResolutionException e )
{
throw new MissingPreviousException( "Error resolving previous version: " + e.getMessage(), e );
}
catch ( ArtifactNotFoundException e )
{
throw new MojoExecutionException( "Error finding previous version: " + e.getMessage(), e );
}
catch ( MalformedURLException e )
{
throw new MojoExecutionException( "Error creating classloader for previous version's classes", e );
}
}
protected ClirrDiffListener executeClirr( Severity minSeverity )
throws MojoExecutionException, MojoFailureException
{
ClirrDiffListener listener = new ClirrDiffListener();
ClassFilter classFilter = new ClirrClassFilter( includes, excludes );
JavaType[] origClasses = resolveClasses( oldComparisonArtifacts, classFilter );
JavaType[] currentClasses = resolveClasses( newComparisonArtifacts, classFilter );
// Create a Clirr checker and execute
Checker checker = new Checker();
List listeners = new ArrayList();
listeners.add( listener );
if ( xmlOutputFile != null )
{
try
{
listeners.add( new XmlDiffListener( xmlOutputFile.getAbsolutePath() ) );
}
catch ( IOException e )
{
throw new MojoExecutionException( "Error adding '" + xmlOutputFile + "' for output: " + e.getMessage(),
e );
}
}
if ( textOutputFile != null )
{
try
{
listeners.add( new PlainDiffListener( textOutputFile.getAbsolutePath() ) );
}
catch ( IOException e )
{
throw new MojoExecutionException( "Error adding '" + textOutputFile + "' for output: " + e.getMessage(),
e );
}
}
if ( logResults )
{
listeners.add( new LogDiffListener( getLog() ) );
}
checker.addDiffListener( new DelegatingListener( listeners, minSeverity ) );
checker.reportDiffs( origClasses, currentClasses );
return listener;
}
}