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

org.codehaus.mojo.versions.DisplayPluginUpdatesMojo Maven / Gradle / Ivy

Go to download

Versions Plugin for Maven 2. The Versions Plugin updates the versions of components in the POM.

The newest version!
package org.codehaus.mojo.versions;

/*
 * 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 org.apache.maven.BuildFailureException;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.ArtifactUtils;
import org.apache.maven.artifact.metadata.ArtifactMetadataRetrievalException;
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.versioning.ArtifactVersion;
import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
import org.apache.maven.artifact.versioning.VersionRange;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.execution.RuntimeInformation;
import org.apache.maven.lifecycle.Lifecycle;
import org.apache.maven.lifecycle.LifecycleExecutionException;
import org.apache.maven.lifecycle.LifecycleExecutor;
import org.apache.maven.lifecycle.mapping.LifecycleMapping;
import org.apache.maven.model.*;
import org.apache.maven.model.io.xpp3.MavenXpp3Writer;
import org.apache.maven.plugin.*;
import org.apache.maven.plugin.descriptor.PluginDescriptor;
import org.apache.maven.plugin.version.PluginVersionNotFoundException;
import org.apache.maven.plugin.version.PluginVersionResolutionException;
import org.apache.maven.project.DefaultProjectBuilderConfiguration;
import org.apache.maven.project.MavenProject;
import org.apache.maven.project.ProjectBuildingException;
import org.apache.maven.project.interpolation.ModelInterpolationException;
import org.apache.maven.project.interpolation.ModelInterpolator;
import org.apache.maven.settings.Settings;
import org.codehaus.mojo.versions.api.ArtifactVersions;
import org.codehaus.mojo.versions.api.PomHelper;
import org.codehaus.mojo.versions.ordering.MavenVersionComparator;
import org.codehaus.mojo.versions.report.ArtifactUpdate;
import org.codehaus.mojo.versions.report.DisplayPluginUpdatesReport;
import org.codehaus.mojo.versions.report.IncompatibleParentAndProjectMavenVersion;
import org.codehaus.mojo.versions.rewriting.ModifiedPomXMLEventReader;
import org.codehaus.mojo.versions.utils.ObjectToXmlWriter;
import org.codehaus.mojo.versions.utils.PluginComparator;
import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
import org.codehaus.plexus.util.IOUtil;
import org.codehaus.plexus.util.ReaderFactory;
import org.codehaus.plexus.util.StringUtils;

import javax.xml.stream.XMLStreamException;
import javax.xml.stream.events.XMLEvent;
import java.io.File;
import java.io.IOException;
import java.io.Reader;
import java.io.StringWriter;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.*;
import java.util.regex.Pattern;

/**
 * Displays all plugins that have newer versions available.
 *
 * @author Stephen Connolly
 * @goal display-plugin-updates
 * @requiresProject true
 * @requiresDirectInvocation false
 * @since 1.0-alpha-1
 */
public class DisplayPluginUpdatesMojo
    extends AbstractVersionsUpdaterMojo
{

// ------------------------------ FIELDS ------------------------------

    /**
     * The width to pad warn messages.
     *
     * @since 1.0-alpha-1
     */
    private static final int WARN_PAD_SIZE = 65;

    /**
     * The width to pad info messages.
     *
     * @since 1.0-alpha-1
     */
    private static final int INFO_PAD_SIZE = 68;

    /**
     * String to flag a plugin version being forced by the super-pom.
     *
     * @since 1.0-alpha-1
     */
    private static final String FROM_SUPER_POM = "(from super-pom) ";

    /**
     * @component
     * @since 1.0-alpha-1
     */
    private LifecycleExecutor lifecycleExecutor;

    /**
     * @component
     * @since 1.0-alpha-3
     */
    private ModelInterpolator modelInterpolator;

    /**
     * The plugin manager.
     *
     * @component
     * @since 1.0-alpha-1
     */
    private PluginManager pluginManager;

    /**
     * @component
     * @since 1.3
     */
    private RuntimeInformation runtimeInformation;

    private DisplayPluginUpdatesReport report =new DisplayPluginUpdatesReport();

    /**
     * file to write xml report to
     *
     * @parameter expression="${xmlReport}" defaultValue="null"
     */
    private File xmlReport;

    // --------------------- GETTER / SETTER METHODS ---------------------

    public void setXmlReport(File xmlReport) {
        this.xmlReport = xmlReport;
    }
    /**
     * Returns the pluginManagement section of the super-pom.
     *
     * @return Returns the pluginManagement section of the super-pom.
     * @throws MojoExecutionException when things go wrong.
     */
    private Map getSuperPomPluginManagement()
        throws MojoExecutionException
    {
        if ( new DefaultArtifactVersion( "3.0" ).compareTo( runtimeInformation.getApplicationVersion() ) <= 0 )
        {
            getLog().debug( "Using Maven 3.x strategy to determine superpom defined plugins" );
            try
            {
                Method getPluginsBoundByDefaultToAllLifecycles =
                    LifecycleExecutor.class.getMethod( "getPluginsBoundByDefaultToAllLifecycles",
                                                       new Class[]{ String.class } );
                Set plugins = (Set) getPluginsBoundByDefaultToAllLifecycles.invoke( lifecycleExecutor,
                                                                                                    new Object[]{
                                                                                                        getProject().getPackaging() } );
                // we need to provide a copy with the version blanked out so that inferring from super-pom
                // works as for 2.x as 3.x fills in the version on us!
                Map result = new LinkedHashMap( plugins.size() );
                for ( Plugin plugin : plugins )
                {
                    result.put( getPluginCoords( plugin ), getPluginVersion( plugin ) );
                }
                URL superPom = getClass().getClassLoader().getResource( "org/apache/maven/model/pom-4.0.0.xml" );
                if ( superPom != null )
                {
                    try
                    {
                        Reader reader = ReaderFactory.newXmlReader( superPom );
                        try
                        {
                            StringBuilder buf = new StringBuilder( IOUtil.toString( reader ) );
                            ModifiedPomXMLEventReader pom = newModifiedPomXER( buf );

                            Pattern pathRegex = Pattern.compile(
                                "/project(/profiles/profile)?" + "((/build(/pluginManagement)?)|(/reporting))"
                                    + "/plugins/plugin" );
                            Stack pathStack = new Stack();
                            StackState curState = null;
                            while ( pom.hasNext() )
                            {
                                XMLEvent event = pom.nextEvent();
                                if ( event.isStartDocument() )
                                {
                                    curState = new StackState( "" );
                                    pathStack.clear();
                                }
                                else if ( event.isStartElement() )
                                {
                                    String elementName = event.asStartElement().getName().getLocalPart();
                                    if ( curState != null && pathRegex.matcher( curState.path ).matches() )
                                    {
                                        if ( "groupId".equals( elementName ) )
                                        {
                                            curState.groupId = pom.getElementText().trim();
                                            continue;
                                        }
                                        else if ( "artifactId".equals( elementName ) )
                                        {
                                            curState.artifactId = pom.getElementText().trim();
                                            continue;

                                        }
                                        else if ( "version".equals( elementName ) )
                                        {
                                            curState.version = pom.getElementText().trim();
                                            continue;
                                        }
                                    }

                                    pathStack.push( curState );
                                    curState = new StackState( curState.path + "/" + elementName );
                                }
                                else if ( event.isEndElement() )
                                {
                                    if ( curState != null && pathRegex.matcher( curState.path ).matches() )
                                    {
                                        if ( curState.artifactId != null )
                                        {
                                            Plugin plugin = new Plugin();
                                            plugin.setArtifactId( curState.artifactId );
                                            plugin.setGroupId( curState.groupId == null
                                                                   ? PomHelper.APACHE_MAVEN_PLUGINS_GROUPID
                                                                   : curState.groupId );
                                            plugin.setVersion( curState.version );
                                            if ( !result.containsKey( getPluginCoords( plugin ) ) )
                                            {
                                                result.put( getPluginCoords( plugin ), getPluginVersion( plugin ) );
                                            }
                                        }
                                    }
                                    curState = pathStack.pop();
                                }
                            }
                        }
                        finally
                        {
                            IOUtil.close( reader );
                        }
                    }
                    catch ( IOException e )
                    {
                        // ignore
                    }
                    catch ( XMLStreamException e )
                    {
                        // ignore
                    }
                }

                return result;
            }
            catch ( NoSuchMethodException e1 )
            {
                // no much we can do here
            }
            catch ( InvocationTargetException e1 )
            {
                // no much we can do here
            }
            catch ( IllegalAccessException e1 )
            {
                // no much we can do here
            }
        }
        getLog().debug( "Using Maven 2.x strategy to determine superpom defined plugins" );
        Map superPomPluginManagement = new HashMap();
        try
        {
            MavenProject superProject =
                projectBuilder.buildStandaloneSuperProject( new DefaultProjectBuilderConfiguration() );
            superPomPluginManagement.putAll( getPluginManagement( superProject.getOriginalModel() ) );
        }
        catch ( ProjectBuildingException e )
        {
            throw new MojoExecutionException( "Could not determine the super pom.xml", e );
        }
        return superPomPluginManagement;
    }

    /**
     * Gets the plugin management plugins of a specific project.
     *
     * @param model the model to get the plugin management plugins from.
     * @return The map of effective plugin versions keyed by coordinates.
     * @since 1.0-alpha-1
     */
    private Map getPluginManagement( Model model )
    {
        // we want only those parts of pluginManagement that are defined in this project
        Map pluginManagement = new HashMap();
        try
        {
            for ( Plugin plugin : model.getBuild().getPluginManagement().getPlugins() )
            {
                String coord = getPluginCoords( plugin );
                String version = getPluginVersion( plugin );
                if ( version != null )
                {
                    pluginManagement.put( coord, version );
                }
            }
        }
        catch ( NullPointerException e )
        {
            // guess there are no plugins here
        }
        try
        {
            for ( Profile profile : model.getProfiles() )
            {
                try
                {
                    for ( Plugin plugin : profile.getBuild().getPluginManagement().getPlugins() )
                    {
                        String coord = getPluginCoords( plugin );
                        String version = getPluginVersion( plugin );
                        if ( version != null )
                        {
                            pluginManagement.put( coord, version );
                        }
                    }
                }
                catch ( NullPointerException e )
                {
                    // guess there are no plugins here
                }
            }
        }
        catch ( NullPointerException e )
        {
            // guess there are no profiles here
        }

        return pluginManagement;
    }

// ------------------------ INTERFACE METHODS ------------------------

// --------------------- Interface Mojo ---------------------

    /**
     * @throws MojoExecutionException when things go wrong
     * @throws MojoFailureException   when things go wrong in a very bad way
     * @see AbstractVersionsUpdaterMojo#execute()
     * @since 1.0-alpha-1
     */
    public void execute()
        throws MojoExecutionException, MojoFailureException
    {
        Set pluginsWithVersionsSpecified;
        try
        {
            pluginsWithVersionsSpecified = findPluginsWithVersionsSpecified( getProject() );
        }
        catch ( XMLStreamException e )
        {
            throw new MojoExecutionException( e.getMessage(), e );
        }
        catch ( IOException e )
        {
            throw new MojoExecutionException( e.getMessage(), e );
        }

        Map superPomPluginManagement = getSuperPomPluginManagement();
        getLog().debug( "superPom plugins = " + superPomPluginManagement );

        Map parentPluginManagement = new HashMap();
        Map parentBuildPlugins = new HashMap();
        Map parentReportPlugins = new HashMap();

        List parents = getParentProjects( getProject() );

        for ( MavenProject parentProject : parents )
        {
            getLog().debug(
                "Processing parent: " + parentProject.getGroupId() + ":" + parentProject.getArtifactId() + ":"
                    + parentProject.getVersion() + " -> " + parentProject.getFile() );

            StringWriter writer = new StringWriter();
            boolean havePom = false;
            Model interpolatedModel;
            try
            {
                Model originalModel = parentProject.getOriginalModel();
                if ( originalModel == null )
                {
                    getLog().warn( "project.getOriginalModel()==null for  " + parentProject.getGroupId() + ":"
                                       + parentProject.getArtifactId() + ":" + parentProject.getVersion()
                                       + " is null, substituting project.getModel()" );
                    originalModel = parentProject.getModel();
                }
                try
                {
                    new MavenXpp3Writer().write( writer, originalModel );
                    writer.close();
                    havePom = true;
                }
                catch ( IOException e )
                {
                    // ignore
                }
                interpolatedModel = modelInterpolator.interpolate( originalModel, null,
                                                                   new DefaultProjectBuilderConfiguration().setExecutionProperties(
                                                                       getProject().getProperties() ), false );
            }
            catch ( ModelInterpolationException e )
            {
                throw new MojoExecutionException( e.getMessage(), e );
            }
            if ( havePom )
            {
                try
                {
                    Set withVersionSpecified =
                        findPluginsWithVersionsSpecified( new StringBuilder( writer.toString() ) );
                    Map map = getPluginManagement( interpolatedModel );
                    map.keySet().retainAll( withVersionSpecified );
                    parentPluginManagement.putAll( map );

                    map = getBuildPlugins( interpolatedModel, true );
                    map.keySet().retainAll( withVersionSpecified );
                    parentPluginManagement.putAll( map );

                    map = getReportPlugins( interpolatedModel, true );
                    map.keySet().retainAll( withVersionSpecified );
                    parentPluginManagement.putAll( map );
                }
                catch ( IOException e )
                {
                    throw new MojoExecutionException( e.getMessage(), e );
                }
                catch ( XMLStreamException e )
                {
                    throw new MojoExecutionException( e.getMessage(), e );
                }
            }
            else
            {
                parentPluginManagement.putAll( getPluginManagement( interpolatedModel ) );
                parentPluginManagement.putAll( getBuildPlugins( interpolatedModel, true ) );
                parentPluginManagement.putAll( getReportPlugins( interpolatedModel, true ) );
            }
        }

        Set plugins = getProjectPlugins( superPomPluginManagement, parentPluginManagement, parentBuildPlugins,
                                                 parentReportPlugins, pluginsWithVersionsSpecified );
        List updates = new ArrayList();
        List lockdowns = new ArrayList();
        Map> upgrades =
            new TreeMap>( new MavenVersionComparator() );
        ArtifactVersion curMavenVersion = runtimeInformation.getApplicationVersion();
        ArtifactVersion specMavenVersion = new DefaultArtifactVersion( getRequiredMavenVersion( getProject(), "2.0" ) );
        ArtifactVersion minMavenVersion = null;
        boolean superPomDrivingMinVersion = false;
        Iterator i = plugins.iterator();
        while ( i.hasNext() )
        {
            Object plugin = i.next();
            String groupId = getPluginGroupId( plugin );
            String artifactId = getPluginArtifactId( plugin );
            String version = getPluginVersion( plugin );
            String coords = ArtifactUtils.versionlessKey( groupId, artifactId );

            if ( version == null )
            {
                version = parentPluginManagement.get( coords );
            }
            getLog().debug(
                new StringBuilder().append( "Checking " ).append( coords ).append( " for updates newer than " ).append(
                    version ).toString() );
            String effectiveVersion = version;

            VersionRange versionRange;
            boolean unspecified = version == null;
            try
            {
                versionRange = unspecified
                    ? VersionRange.createFromVersionSpec( "[0,)" )
                    : VersionRange.createFromVersionSpec( version );
            }
            catch ( InvalidVersionSpecificationException e )
            {
                throw new MojoExecutionException( "Invalid version range specification: " + version, e );
            }

            Artifact artifact = artifactFactory.createPluginArtifact( groupId, artifactId, versionRange );

            ArtifactVersion artifactVersion = null;
            try
            {
                // now we want to find the newest version that is compatible with the invoking version of Maven
                ArtifactVersions artifactVersions = getHelper().lookupArtifactVersions( artifact, true );
                ArtifactVersion[] newerVersions =
                    artifactVersions.getVersions( Boolean.TRUE.equals( this.allowSnapshots ) );
                ArtifactVersion minRequires = null;
                for ( int j = newerVersions.length - 1; j >= 0; j-- )
                {
                    Artifact probe = artifactFactory.createDependencyArtifact( groupId, artifactId,
                                                                               VersionRange.createFromVersion(
                                                                                   newerVersions[j].toString() ), "pom",
                                                                               null, "runtime" );
                    try
                    {
                        getHelper().resolveArtifact( probe, true );
                        MavenProject mavenProject =
                            projectBuilder.buildFromRepository( probe, remotePluginRepositories, localRepository );
                        ArtifactVersion requires =
                            new DefaultArtifactVersion( getRequiredMavenVersion( mavenProject, "2.0" ) );
                        if ( specMavenVersion.compareTo( requires ) >= 0 && artifactVersion == null )
                        {
                            artifactVersion = newerVersions[j];
                        }
                        if ( effectiveVersion == null && curMavenVersion.compareTo( requires ) >= 0 )
                        {
                            // version was unspecified, current version of maven thinks it should use this
                            effectiveVersion = newerVersions[j].toString();
                        }
                        if ( artifactVersion != null && effectiveVersion != null )
                        {
                            // no need to look at any older versions.
                            break;
                        }
                        if ( minRequires == null || minRequires.compareTo( requires ) > 0 )
                        {
                            Map upgradePlugins = upgrades.get( requires );
                            if ( upgradePlugins == null )
                            {
                                upgrades.put( requires, upgradePlugins = new LinkedHashMap() );
                            }
                            String upgradePluginKey = compactKey( groupId, artifactId );
                            if ( !upgradePlugins.containsKey( upgradePluginKey ) )
                            {
                                upgradePlugins.put( upgradePluginKey, newerVersions[j].toString() );
                            }
                            minRequires = requires;
                        }
                    }
                    catch ( ArtifactResolutionException e )
                    {
                        // ignore bad version
                    }
                    catch ( ArtifactNotFoundException e )
                    {
                        // ignore bad version
                    }
                    catch ( ProjectBuildingException e )
                    {
                        // ignore bad version
                    }
                }
                if ( effectiveVersion != null )
                {
                    VersionRange currentVersionRange = VersionRange.createFromVersion( effectiveVersion );
                    Artifact probe =
                        artifactFactory.createDependencyArtifact( groupId, artifactId, currentVersionRange, "pom", null,
                                                                  "runtime" );
                    try
                    {
                        getHelper().resolveArtifact( probe, true );
                        MavenProject mavenProject =
                            projectBuilder.buildFromRepository( probe, remotePluginRepositories, localRepository );
                        ArtifactVersion requires =
                            new DefaultArtifactVersion( getRequiredMavenVersion( mavenProject, "2.0" ) );
                        if ( minMavenVersion == null || minMavenVersion.compareTo( requires ) < 0 )
                        {
                            minMavenVersion = requires;
                        }
                    }
                    catch ( ArtifactResolutionException e )
                    {
                        // ignore bad version
                    }
                    catch ( ArtifactNotFoundException e )
                    {
                        // ignore bad version
                    }
                    catch ( ProjectBuildingException e )
                    {
                        // ignore bad version
                    }
                }
            }
            catch ( ArtifactMetadataRetrievalException e )
            {
                throw new MojoExecutionException( e.getMessage(), e );
            }

            String newVersion;

            if ( version == null && pluginsWithVersionsSpecified.contains( coords ) )
            {
                // Hack ALERT!
                //
                // All this should be re-written in a less "pom is xml" way... but it'll
                // work for now :-(
                //
                // we have removed the version information, as it was the same as from
                // the super-pom... but it actually was specified.
                version = artifactVersion != null ? artifactVersion.toString() : null;
            }

            getLog().debug( "[" + coords + "].version=" + version );
            getLog().debug( "[" + coords + "].artifactVersion=" + artifactVersion );
            getLog().debug( "[" + coords + "].effectiveVersion=" + effectiveVersion );
            getLog().debug( "[" + coords + "].specified=" + pluginsWithVersionsSpecified.contains( coords ) );
            if ( version == null || !pluginsWithVersionsSpecified.contains( coords ) )
            {
                version = (String) superPomPluginManagement.get( ArtifactUtils.versionlessKey( artifact ) );
                getLog().debug( "[" + coords + "].superPom.version=" + version );

                newVersion = artifactVersion != null
                    ? artifactVersion.toString()
                    : ( version != null ? version : ( effectiveVersion != null ? effectiveVersion : "(unknown)" ) );
                StringBuilder buf = new StringBuilder( compactKey( groupId, artifactId ) );
                buf.append( ' ' );
                int padding =
                    WARN_PAD_SIZE - effectiveVersion.length() - ( version != null ? FROM_SUPER_POM.length() : 0 );
                while ( buf.length() < padding )
                {
                    buf.append( '.' );
                }
                buf.append( ' ' );
                if ( version != null )
                {
                    buf.append( FROM_SUPER_POM );
                    superPomDrivingMinVersion = true;
                }
                buf.append( effectiveVersion );
                lockdowns.add( buf.toString() );

                addMissingVersionPlugin(groupId, artifactId, version);
            }
            else if ( artifactVersion != null )
            {
                newVersion = artifactVersion.toString();
            }
            else
            {
                newVersion = null;
            }
            if ( version != null && artifactVersion != null && newVersion != null &&
                new DefaultArtifactVersion( effectiveVersion ).compareTo( new DefaultArtifactVersion( newVersion ) )
                    < 0 )
            {
                StringBuilder buf = new StringBuilder( compactKey( groupId, artifactId ) );
                buf.append( ' ' );
                int padding = INFO_PAD_SIZE - version.length() - newVersion.length() - 4;
                while ( buf.length() < padding )
                {
                    buf.append( '.' );
                }
                buf.append( ' ' );
                buf.append( effectiveVersion );
                buf.append( " -> " );
                buf.append( newVersion );
                updates.add( buf.toString() );

                addUpdate(groupId,artifactId,version,artifactVersion);
            }
        }
        getLog().info( "" );
        if ( updates.isEmpty() )
        {
            getLog().info( "All plugins with a version specified are using the latest versions." );
        }
        else
        {
            getLog().info( "The following plugin updates are available:" );
            for ( String update : updates )
            {
                getLog().info( "  " + update );
            }
        }
        getLog().info( "" );
        if ( lockdowns.isEmpty() )
        {
            getLog().info( "All plugins have a version specified." );
        }
        else
        {
            getLog().warn( "The following plugins do not have their version specified:" );
            for ( String lockdown : lockdowns )
            {
                getLog().warn( "  " + lockdown );
            }
        }
        getLog().info( "" );
        boolean noMavenMinVersion = getRequiredMavenVersion( getProject(), null ) == null;
        boolean noExplicitMavenMinVersion =
            getProject().getPrerequisites() == null || getProject().getPrerequisites().getMaven() == null;
        if ( noMavenMinVersion )
        {
            getLog().warn( "Project does not define minimum Maven version, default is: 2.0" );
            report.warnNoMinimumVersion();
        }
        else if ( noExplicitMavenMinVersion )
        {
            getLog().info( "Project inherits minimum Maven version as: " + specMavenVersion );
        }
        else
        {
            ArtifactVersion explicitMavenVersion =
                new DefaultArtifactVersion( getProject().getPrerequisites().getMaven() );
            if ( explicitMavenVersion.compareTo( specMavenVersion ) < 0 )
            {
                getLog().error( "Project's effective minimum Maven (from parent) is: " + specMavenVersion );
                getLog().error( "Project defines minimum Maven version as: " + explicitMavenVersion );

                IncompatibleParentAndProjectMavenVersion incompatibleParentAndProjectMavenVersion = new IncompatibleParentAndProjectMavenVersion();
                incompatibleParentAndProjectMavenVersion.setParentVersion(specMavenVersion.toString());
                incompatibleParentAndProjectMavenVersion.setProjectVersion(explicitMavenVersion.toString());

                report.warn(incompatibleParentAndProjectMavenVersion);
            }
            else
            {
                getLog().info( "Project defines minimum Maven version as: " + specMavenVersion );
            }
        }
        getLog().info( "Plugins require minimum Maven version of: " + minMavenVersion );
        if ( superPomDrivingMinVersion )
        {
            getLog().info( "Note: the super-pom from Maven " + curMavenVersion + " defines some of the plugin" );
            getLog().info( "      versions and may be influencing the plugins required minimum Maven" );
            getLog().info( "      version." );
        }
        getLog().info( "" );
        if ( "maven-plugin".equals( getProject().getPackaging() ) )
        {
            if ( noMavenMinVersion )
            {
                getLog().warn( "Project (which is a Maven Plugin) does not define required minimum version of Maven." );
                getLog().warn( "Update the pom.xml to contain" );
                getLog().warn( "    " );
                getLog().warn( "      " );
                getLog().warn( "    " );
                getLog().warn( "To build this plugin you need at least Maven " + minMavenVersion );
                getLog().warn( "A Maven Enforcer rule can be used to enforce this if you have not already set one up" );
            }
            else if ( minMavenVersion != null && specMavenVersion.compareTo( minMavenVersion ) < 0 )
            {
                getLog().warn( "Project (which is a Maven Plugin) targets Maven " + specMavenVersion + " or newer" );
                getLog().warn( "but requires Maven " + minMavenVersion + " or newer to build." );
                getLog().warn( "This may or may not be a problem. A Maven Enforcer rule can help " );
                getLog().warn( "enforce that the correct version of Maven is used to build this plugin." );
            }
            else
            {
                getLog().info( "No plugins require a newer version of Maven than specified by the pom." );
            }
        }
        else
        {
            if ( noMavenMinVersion )
            {
                getLog().error( "Project does not define required minimum version of Maven." );
                getLog().error( "Update the pom.xml to contain" );
                getLog().error( "    " );
                getLog().error( "      " + minMavenVersion + "" );
                getLog().error( "    " );
            }
            else if ( minMavenVersion != null && specMavenVersion.compareTo( minMavenVersion ) < 0 )
            {
                getLog().error( "Project requires an incorrect minimum version of Maven." );
                getLog().error( "Either change plugin versions to those compatible with " + specMavenVersion );
                getLog().error( "or update the pom.xml to contain" );
                getLog().error( "    " );
                getLog().error( "      " + minMavenVersion + "" );
                getLog().error( "    " );

                IncompatibleParentAndProjectMavenVersion incompatibleParentAndProjectMavenVersion = new IncompatibleParentAndProjectMavenVersion();
                incompatibleParentAndProjectMavenVersion.setParentVersion(specMavenVersion.toString());
                incompatibleParentAndProjectMavenVersion.setProjectVersion(minMavenVersion.toString());

                report.warn(incompatibleParentAndProjectMavenVersion);
            }
            else
            {
                getLog().info( "No plugins require a newer version of Maven than specified by the pom." );
            }
        }
        for ( Map.Entry> mavenUpgrade : upgrades.entrySet() )
        {
            ArtifactVersion mavenUpgradeVersion = (ArtifactVersion) mavenUpgrade.getKey();
            Map upgradePlugins = mavenUpgrade.getValue();
            if ( upgradePlugins.isEmpty() || specMavenVersion.compareTo( mavenUpgradeVersion ) >= 0 )
            {
                continue;
            }
            getLog().info( "" );
            getLog().info( "Require Maven " + mavenUpgradeVersion + " to use the following plugin updates:" );
            for ( Map.Entry entry : upgradePlugins.entrySet() )
            {
                StringBuilder buf = new StringBuilder( "  " );
                buf.append( entry.getKey() );
                buf.append( ' ' );
                String s = entry.getValue();
                int padding = INFO_PAD_SIZE - s.length() + 2;
                while ( buf.length() < padding )
                {
                    buf.append( '.' );
                }
                buf.append( ' ' );
                buf.append( s );
                getLog().info( buf.toString() );
            }
        }
        getLog().info( "" );

        ObjectToXmlWriter.writeXmlReport(xmlReport, report);
    }

    private void addUpdate(final String groupId, final String artifactId, final String version,
                           final ArtifactVersion artifactVersion) {

        ArtifactUpdate update = new ArtifactUpdate();
        org.codehaus.mojo.versions.report.Dependency dependency = new org.codehaus.mojo.versions.report.Dependency();
        dependency.setGroupId(groupId);
        dependency.setArtifactId(artifactId);
        dependency.setVersion(version);

        update.setDependency(dependency);
        update.setVersionUpdate(artifactVersion.toString());

        report.addPluginUpdate(update);
    }

    private void addMissingVersionPlugin(final String groupId, final String artifactId, final String version) {
        org.codehaus.mojo.versions.report.Dependency dependency = new org.codehaus.mojo.versions.report.Dependency();
        dependency.setGroupId(groupId);
        dependency.setArtifactId(artifactId);
        dependency.setVersion(version);

        report.addMissingVersionPlugin(dependency);
    }

    private String compactKey( String groupId, String artifactId )
    {
        if ( PomHelper.APACHE_MAVEN_PLUGINS_GROUPID.equals( groupId ) )
        {
            // a core plugin... group id is not needed
            return artifactId;
        }
        return groupId + ":" + artifactId;
    }

    private String getRequiredMavenVersion( MavenProject mavenProject, String defaultValue )
    {
        ArtifactVersion requiredMavenVersion = null;
        while ( mavenProject != null )
        {
            final Prerequisites prerequisites = mavenProject.getPrerequisites();
            final String mavenVersion = prerequisites == null ? null : prerequisites.getMaven();
            if ( mavenVersion != null )
            {
                final ArtifactVersion v = new DefaultArtifactVersion( mavenVersion );
                if ( requiredMavenVersion == null || requiredMavenVersion.compareTo( v ) < 0 )
                {
                    requiredMavenVersion = v;
                }
            }
            mavenProject = mavenProject.getParent();
        }
        return requiredMavenVersion == null ? defaultValue : requiredMavenVersion.toString();
    }

    private static final class StackState
    {
        private final String path;

        private String groupId;

        private String artifactId;

        private String version;

        public StackState( String path )
        {
            this.path = path;
        }

        public String toString()
        {
            return path + "[groupId=" + groupId + ", artifactId=" + artifactId + ", version=" + version + "]";
        }
    }

    /**
     * Returns a set of Strings which correspond to the plugin coordinates where there is a version
     * specified.
     *
     * @param project The project to get the plugins with versions specified.
     * @return a set of Strings which correspond to the plugin coordinates where there is a version
     *         specified.
     */
    private Set findPluginsWithVersionsSpecified( MavenProject project )
        throws IOException, XMLStreamException
    {
        return findPluginsWithVersionsSpecified( PomHelper.readXmlFile( project.getFile() ) );
    }

    /**
     * Returns a set of Strings which correspond to the plugin coordinates where there is a version
     * specified.
     *
     * @param pomContents The project to get the plugins with versions specified.
     * @return a set of Strings which correspond to the plugin coordinates where there is a version
     *         specified.
     */
    private Set findPluginsWithVersionsSpecified( StringBuilder pomContents )
        throws IOException, XMLStreamException
    {
        Set result = new HashSet();
        ModifiedPomXMLEventReader pom = newModifiedPomXER( pomContents );

        Pattern pathRegex = Pattern.compile(
            "/project(/profiles/profile)?" + "((/build(/pluginManagement)?)|(/reporting))" + "/plugins/plugin" );
        Stack pathStack = new Stack();
        StackState curState = null;
        while ( pom.hasNext() )
        {
            XMLEvent event = pom.nextEvent();
            if ( event.isStartDocument() )
            {
                curState = new StackState( "" );
                pathStack.clear();
            }
            else if ( event.isStartElement() )
            {
                String elementName = event.asStartElement().getName().getLocalPart();
                if ( curState != null && pathRegex.matcher( curState.path ).matches() )
                {
                    if ( "groupId".equals( elementName ) )
                    {
                        curState.groupId = pom.getElementText().trim();
                        continue;
                    }
                    else if ( "artifactId".equals( elementName ) )
                    {
                        curState.artifactId = pom.getElementText().trim();
                        continue;

                    }
                    else if ( "version".equals( elementName ) )
                    {
                        curState.version = pom.getElementText().trim();
                        continue;
                    }
                }

                pathStack.push( curState );
                curState = new StackState( curState.path + "/" + elementName );
            }
            else if ( event.isEndElement() )
            {
                if ( curState != null && pathRegex.matcher( curState.path ).matches() )
                {
                    if ( curState.artifactId != null && curState.version != null )
                    {
                        if ( curState.groupId == null )
                        {
                            curState.groupId = PomHelper.APACHE_MAVEN_PLUGINS_GROUPID;
                        }
                        result.add( curState.groupId + ":" + curState.artifactId );
                    }
                }
                curState = pathStack.pop();
            }
        }

        return result;

    }

// -------------------------- OTHER METHODS --------------------------

    /**
     * Gets the build plugins of a specific project.
     *
     * @param model                the model to get the build plugins from.
     * @param onlyIncludeInherited true to only return the plugins definitions that will be
     *                             inherited by child projects.
     * @return The map of effective plugin versions keyed by coordinates.
     * @since 1.0-alpha-1
     */
    private Map getBuildPlugins( Model model, boolean onlyIncludeInherited )
    {
        Map buildPlugins = new HashMap();
        try
        {
            for ( Plugin plugin : model.getBuild().getPlugins() )
            {
                String coord = getPluginCoords( plugin );
                String version = getPluginVersion( plugin );
                if ( version != null && ( !onlyIncludeInherited || getPluginInherited( plugin ) ) )
                {
                    buildPlugins.put( coord, version );
                }
            }
        }
        catch ( NullPointerException e )
        {
            // guess there are no plugins here
        }
        try
        {
            for ( Profile profile : model.getProfiles() )
            {
                try
                {
                    for ( Plugin plugin : profile.getBuild().getPlugins() )
                    {
                        String coord = getPluginCoords( plugin );
                        String version = getPluginVersion( plugin );
                        if ( version != null && ( !onlyIncludeInherited || getPluginInherited( plugin ) ) )
                        {
                            buildPlugins.put( coord, version );
                        }
                    }
                }
                catch ( NullPointerException e )
                {
                    // guess there are no plugins here
                }
            }
        }
        catch ( NullPointerException e )
        {
            // guess there are no profiles here
        }
        return buildPlugins;
    }

    /**
     * Returns the Inherited of a {@link Plugin} or {@link ReportPlugin}
     *
     * @param plugin the {@link Plugin} or {@link ReportPlugin}
     * @return the Inherited of the {@link Plugin} or {@link ReportPlugin}
     * @since 1.0-alpha-1
     */
    private static boolean getPluginInherited( Object plugin )
    {
        return "true".equalsIgnoreCase( plugin instanceof ReportPlugin
                                            ? ( (ReportPlugin) plugin ).getInherited()
                                            : ( (Plugin) plugin ).getInherited() );
    }

    /**
     * Returns the lifecycle plugins of a specific project.
     *
     * @param project the project to get the lifecycle plugins from.
     * @return The map of effective plugin versions keyed by coordinates.
     * @throws org.apache.maven.plugin.MojoExecutionException
     *          if things go wrong.
     * @since 1.0-alpha-1
     */
    private Map getLifecyclePlugins( MavenProject project )
        throws MojoExecutionException
    {
        Map lifecyclePlugins = new HashMap();
        try
        {
            Set plugins = getBoundPlugins( project, "clean,deploy,site" );
            for ( Plugin plugin : plugins )
            {
                lifecyclePlugins.put( getPluginCoords( plugin ), plugin );
            }
        }
        catch ( PluginNotFoundException e )
        {
            throw new MojoExecutionException( "Could not find plugin", e );
        }
        catch ( LifecycleExecutionException e )
        {
            throw new MojoExecutionException( "Could not determine lifecycle", e );
        }
        catch ( IllegalAccessException e )
        {
            throw new MojoExecutionException( "Could not determine lifecycles", e );
        }
        catch ( NullPointerException e )
        {
            // Maven 3.x

        }
        return lifecyclePlugins;
    }

    /**
     * Gets the plugins that are bound to the defined phases. This does not find plugins bound in the pom to a phase
     * later than the plugin is executing.
     *
     * @param project   the project
     * @param thePhases the the phases
     * @return the bound plugins
     * @throws org.apache.maven.plugin.PluginNotFoundException
     *                                     the plugin not found exception
     * @throws LifecycleExecutionException the lifecycle execution exception
     * @throws IllegalAccessException      the illegal access exception
     */
    // pilfered this from enforcer-rules
    // TODO coordinate with Brian Fox to remove the duplicate code
    private Set getBoundPlugins( MavenProject project, String thePhases )
        throws PluginNotFoundException, LifecycleExecutionException, IllegalAccessException
    {
        if ( new DefaultArtifactVersion( "3.0" ).compareTo( runtimeInformation.getApplicationVersion() ) <= 0 )
        {
            getLog().debug( "Using Maven 3.0+ strategy to determine lifecycle defined plugins" );
            try
            {
                Method getPluginsBoundByDefaultToAllLifecycles =
                    LifecycleExecutor.class.getMethod( "getPluginsBoundByDefaultToAllLifecycles",
                                                       new Class[]{ String.class } );
                Set plugins = (Set) getPluginsBoundByDefaultToAllLifecycles.invoke( lifecycleExecutor,
                                                                                                    new Object[]{
                                                                                                        project.getPackaging()
                                                                                                            == null
                                                                                                            ? "jar"
                                                                                                            : project.getPackaging() } );
                // we need to provide a copy with the version blanked out so that inferring from super-pom
                // works as for 2.x as 3.x fills in the version on us!
                Set result = new LinkedHashSet( plugins.size() );
                for ( Plugin plugin : plugins )
                {
                    Plugin dup = new Plugin();
                    dup.setGroupId( plugin.getGroupId() );
                    dup.setArtifactId( plugin.getArtifactId() );
                    result.add( dup );
                }
                return result;
            }
            catch ( NoSuchMethodException e1 )
            {
                // no much we can do here
            }
            catch ( InvocationTargetException e1 )
            {
                // no much we can do here
            }
            catch ( IllegalAccessException e1 )
            {
                // no much we can do here
            }
        }
        List lifecycles = null;
        getLog().debug( "Using Maven 2.0.10+ strategy to determine lifecycle defined plugins" );
        try
        {
            Method getLifecycles = LifecycleExecutor.class.getMethod( "getLifecycles", new Class[0] );
            lifecycles = (List) getLifecycles.invoke( lifecycleExecutor, new Object[0] );
        }
        catch ( NoSuchMethodException e1 )
        {
            // no much we can do here
        }
        catch ( InvocationTargetException e1 )
        {
            // no much we can do here
        }
        catch ( IllegalAccessException e1 )
        {
            // no much we can do here
        }

        Set allPlugins = new HashSet();

        // lookup the bindings for all the passed in phases
        for ( String lifecyclePhase : thePhases.split( "," ) )
        {
            if ( StringUtils.isNotEmpty( lifecyclePhase ) )
            {
                try
                {
                    Lifecycle lifecycle = getLifecycleForPhase( lifecycles, lifecyclePhase );
                    allPlugins.addAll( getAllPlugins( project, lifecycle ) );
                }
                catch ( BuildFailureException e )
                {
                    // i'm going to swallow this because the
                    // user may have declared a phase that
                    // doesn't exist for every module.
                }
            }
        }
        return allPlugins;
    }

    /**
     * Gets the lifecycle for phase.
     *
     * @param lifecycles The list of lifecycles.
     * @param phase      the phase
     * @return the lifecycle for phase
     * @throws BuildFailureException       the build failure exception
     * @throws LifecycleExecutionException the lifecycle execution exception
     */
    private Lifecycle getLifecycleForPhase( List lifecycles, String phase )
        throws BuildFailureException, LifecycleExecutionException
    {
        Lifecycle lifecycle = (Lifecycle) getPhaseToLifecycleMap( lifecycles ).get( phase );

        if ( lifecycle == null )
        {
            throw new BuildFailureException( "Unable to find lifecycle for phase '" + phase + "'" );
        }
        return lifecycle;
    }

    /*
     * Uses borrowed lifecycle code to get a list of all plugins bound to the lifecycle.
     */

    /**
     * Gets the all plugins.
     *
     * @param project   the project
     * @param lifecycle the lifecycle
     * @return the all plugins
     * @throws PluginNotFoundException     the plugin not found exception
     * @throws LifecycleExecutionException the lifecycle execution exception
     */
    private Set getAllPlugins( MavenProject project, Lifecycle lifecycle )
        throws PluginNotFoundException, LifecycleExecutionException

    {
        Set plugins = new HashSet();
        // first, bind those associated with the packaging
        Map mappings = findMappingsForLifecycle( project, lifecycle );

        Iterator iter = mappings.entrySet().iterator();
        while ( iter.hasNext() )
        {
            Map.Entry entry = (Map.Entry) iter.next();
            String value = (String) entry.getValue();
            String[] tokens = value.split( ":" );

            Plugin plugin = new Plugin();
            plugin.setGroupId( tokens[0] );
            plugin.setArtifactId( tokens[1] );
            plugins.add( plugin );
        }

        for ( String value : findOptionalMojosForLifecycle( project, lifecycle ) )
        {
            String[] tokens = value.split( ":" );

            Plugin plugin = new Plugin();
            plugin.setGroupId( tokens[0] );
            plugin.setArtifactId( tokens[1] );
            plugins.add( plugin );
        }

        plugins.addAll( (List) project.getBuildPlugins() );

        return plugins;
    }

    /**
     * Find mappings for lifecycle.
     *
     * @param project   the project
     * @param lifecycle the lifecycle
     * @return the map
     * @throws LifecycleExecutionException the lifecycle execution exception
     * @throws PluginNotFoundException     the plugin not found exception
     */
    private Map findMappingsForLifecycle( MavenProject project, Lifecycle lifecycle )
        throws LifecycleExecutionException, PluginNotFoundException
    {
        String packaging = project.getPackaging();
        Map mappings = null;

        LifecycleMapping m =
            (LifecycleMapping) findExtension( project, LifecycleMapping.ROLE, packaging, session.getSettings(),
                                              session.getLocalRepository() );
        if ( m != null )
        {
            mappings = m.getPhases( lifecycle.getId() );
        }

        Map defaultMappings = lifecycle.getDefaultPhases();

        if ( mappings == null )
        {
            try
            {
                m = (LifecycleMapping) session.lookup( LifecycleMapping.ROLE, packaging );
                mappings = m.getPhases( lifecycle.getId() );
            }
            catch ( ComponentLookupException e )
            {
                if ( defaultMappings == null )
                {
                    throw new LifecycleExecutionException(
                        "Cannot find lifecycle mapping for packaging: \'" + packaging + "\'.", e );
                }
            }
        }

        if ( mappings == null )
        {
            if ( defaultMappings == null )
            {
                throw new LifecycleExecutionException(
                    "Cannot find lifecycle mapping for packaging: \'" + packaging + "\', and there is no default" );
            }
            else
            {
                mappings = defaultMappings;
            }
        }

        return mappings;
    }

    /**
     * Find optional mojos for lifecycle.
     *
     * @param project   the project
     * @param lifecycle the lifecycle
     * @return the list
     * @throws LifecycleExecutionException the lifecycle execution exception
     * @throws PluginNotFoundException     the plugin not found exception
     */
    private List findOptionalMojosForLifecycle( MavenProject project, Lifecycle lifecycle )
        throws LifecycleExecutionException, PluginNotFoundException
    {
        String packaging = project.getPackaging();
        List optionalMojos = null;

        LifecycleMapping m =
            (LifecycleMapping) findExtension( project, LifecycleMapping.ROLE, packaging, session.getSettings(),
                                              session.getLocalRepository() );

        if ( m != null )
        {
            optionalMojos = m.getOptionalMojos( lifecycle.getId() );
        }

        if ( optionalMojos == null )
        {
            try
            {
                m = (LifecycleMapping) session.lookup( LifecycleMapping.ROLE, packaging );
                optionalMojos = m.getOptionalMojos( lifecycle.getId() );
            }
            catch ( ComponentLookupException e )
            {
                getLog().debug( "Error looking up lifecycle mapping to retrieve optional mojos. Lifecycle ID: " +
                                    lifecycle.getId() + ". Error: " + e.getMessage(), e );
            }
        }

        if ( optionalMojos == null )
        {
            optionalMojos = Collections.emptyList();
        }

        return optionalMojos;
    }

    /**
     * Find extension.
     *
     * @param project         the project
     * @param role            the role
     * @param roleHint        the role hint
     * @param settings        the settings
     * @param localRepository the local repository
     * @return the object
     * @throws LifecycleExecutionException the lifecycle execution exception
     * @throws PluginNotFoundException     the plugin not found exception
     */
    private Object findExtension( MavenProject project, String role, String roleHint, Settings settings,
                                  ArtifactRepository localRepository )
        throws LifecycleExecutionException, PluginNotFoundException
    {
        Object pluginComponent = null;

        for ( Iterator i = project.getBuildPlugins().iterator(); i.hasNext() && pluginComponent == null; )
        {
            Plugin plugin = (Plugin) i.next();

            if ( plugin.isExtensions() )
            {
                loadPluginDescriptor( plugin, project, session );

                // TODO: if moved to the plugin manager we
                // already have the descriptor from above
                // and so do can lookup the container
                // directly
                try
                {
                    pluginComponent = pluginManager.getPluginComponent( plugin, role, roleHint );
                }
                catch ( ComponentLookupException e )
                {
                    getLog().debug( "Unable to find the lifecycle component in the extension", e );
                }
                catch ( PluginManagerException e )
                {
                    throw new LifecycleExecutionException(
                        "Error getting extensions from the plugin '" + plugin.getKey() + "': " + e.getMessage(), e );
                }
            }
        }
        return pluginComponent;
    }

    /**
     * Verify plugin.
     *
     * @param plugin  the plugin
     * @param project the project
     * @param session the session
     * @return the plugin descriptor
     * @throws LifecycleExecutionException the lifecycle execution exception
     * @throws PluginNotFoundException     the plugin not found exception
     */
    private PluginDescriptor loadPluginDescriptor( Plugin plugin, MavenProject project, MavenSession session )
        throws LifecycleExecutionException, PluginNotFoundException
    {
        PluginDescriptor pluginDescriptor;
        try
        {
            pluginDescriptor = pluginManager.loadPluginDescriptor( plugin, project, session );
        }
        catch ( PluginManagerException e )
        {
            throw new LifecycleExecutionException(
                "Internal error in the plugin manager getting plugin '" + plugin.getKey() + "': " + e.getMessage(), e );
        }
        catch ( PluginVersionResolutionException e )
        {
            throw new LifecycleExecutionException( e.getMessage(), e );
        }
        catch ( InvalidVersionSpecificationException e )
        {
            throw new LifecycleExecutionException( e.getMessage(), e );
        }
        catch ( InvalidPluginException e )
        {
            throw new LifecycleExecutionException( e.getMessage(), e );
        }
        catch ( ArtifactNotFoundException e )
        {
            throw new LifecycleExecutionException( e.getMessage(), e );
        }
        catch ( ArtifactResolutionException e )
        {
            throw new LifecycleExecutionException( e.getMessage(), e );
        }
        catch ( PluginVersionNotFoundException e )
        {
            throw new LifecycleExecutionException( e.getMessage(), e );
        }
        return pluginDescriptor;
    }

    /**
     * Returns all the parent projects of the specified project, with the root project first.
     *
     * @param project The maven project to get the parents of
     * @return the parent projects of the specified project, with the root project first.
     * @throws org.apache.maven.plugin.MojoExecutionException
     *          if the super-pom could not be created.
     * @since 1.0-alpha-1
     */
    private List getParentProjects( MavenProject project )
        throws MojoExecutionException
    {
        List parents = new ArrayList();
        while ( project.getParent() != null )
        {
            project = project.getParent();
            parents.add( 0, project );
        }
        return parents;
    }

    /*
     * NOTE: All the code following this point was scooped from the DefaultLifecycleExecutor. There must be a better way
     * but for now it should work.
     */

    /**
     * Gets the phase to lifecycle map.
     *
     * @param lifecycles The list of lifecycles.
     * @return the phase to lifecycle map.
     * @throws LifecycleExecutionException the lifecycle execution exception.
     */
    public Map getPhaseToLifecycleMap( List lifecycles )
        throws LifecycleExecutionException
    {
        Map phaseToLifecycleMap = new HashMap();

        for ( Iterator i = lifecycles.iterator(); i.hasNext(); )
        {
            Lifecycle lifecycle = (Lifecycle) i.next();

            for ( Iterator p = lifecycle.getPhases().iterator(); p.hasNext(); )
            {
                String phase = (String) p.next();

                if ( phaseToLifecycleMap.containsKey( phase ) )
                {
                    Lifecycle prevLifecycle = (Lifecycle) phaseToLifecycleMap.get( phase );
                    throw new LifecycleExecutionException(
                        "Phase '" + phase + "' is defined in more than one lifecycle: '" + lifecycle.getId() +
                            "' and '" + prevLifecycle.getId() + "'" );
                }
                else
                {
                    phaseToLifecycleMap.put( phase, lifecycle );
                }
            }
        }
        return phaseToLifecycleMap;
    }

    /**
     * Returns the set of all plugins used by the project.
     *
     * @param superPomPluginManagement     the super pom's pluginManagement plugins.
     * @param parentPluginManagement       the parent pom's pluginManagement plugins.
     * @param parentBuildPlugins           the parent pom's build plugins.
     * @param parentReportPlugins          the parent pom's report plugins.
     * @param pluginsWithVersionsSpecified the plugin coords that have a version defined in the project.
     * @return the set of plugins used by the project.
     * @throws org.apache.maven.plugin.MojoExecutionException
     *          if things go wrong.
     */
    private Set getProjectPlugins( Map superPomPluginManagement,
                                           Map parentPluginManagement,
                                           Map parentBuildPlugins,
                                           Map parentReportPlugins,
                                           Set pluginsWithVersionsSpecified )
        throws MojoExecutionException
    {
        Map plugins = new HashMap();

        getLog().debug( "Building list of project plugins..." );

        if ( getLog().isDebugEnabled() )
        {
            StringWriter origModel = new StringWriter();

            try
            {
                origModel.write( "Original model:\n" );
                getProject().writeOriginalModel( origModel );
                getLog().debug( origModel.toString() );
            }
            catch ( IOException e )
            {
                // ignore
            }
        }

        debugVersionMap( "super-pom version map", superPomPluginManagement );
        debugVersionMap( "parent version map", parentPluginManagement );

        Map excludePluginManagement = new HashMap( superPomPluginManagement );
        excludePluginManagement.putAll( parentPluginManagement );

        debugVersionMap( "aggregate version map", excludePluginManagement );

        excludePluginManagement.keySet().removeAll( pluginsWithVersionsSpecified );

        debugVersionMap( "final aggregate version map", excludePluginManagement );

        Model originalModel;
        try
        {
            originalModel = modelInterpolator.interpolate( getProject().getOriginalModel(), getProject().getBasedir(),
                                                           new DefaultProjectBuilderConfiguration().setExecutionProperties(
                                                               getProject().getProperties() ), true );
        }
        catch ( ModelInterpolationException e )
        {
            throw new MojoExecutionException( e.getMessage(), e );
        }
        try
        {
            addProjectPlugins( plugins, originalModel.getBuild().getPluginManagement().getPlugins(),
                               excludePluginManagement );
        }
        catch ( NullPointerException e )
        {
            // guess there are no plugins here
        }
        debugPluginMap( "after adding local pluginManagement", plugins );

        try
        {
            List lifecyclePlugins = new ArrayList( getLifecyclePlugins( getProject() ).values() );
            for ( Iterator i = lifecyclePlugins.iterator(); i.hasNext(); )
            {
                Plugin lifecyclePlugin = i.next();
                if ( getPluginVersion( lifecyclePlugin ) != null )
                {
                    // version comes from lifecycle, therefore cannot modify
                    i.remove();
                }
                else
                {
                    // lifecycle leaves version open
                    String parentVersion = parentPluginManagement.get( getPluginCoords( lifecyclePlugin ) );
                    if ( parentVersion != null )
                    {
                        // parent controls version
                        i.remove();
                    }
                }
            }
            addProjectPlugins( plugins, lifecyclePlugins, parentPluginManagement );

            debugPluginMap( "after adding lifecycle plugins", plugins );
        }
        catch ( NullPointerException e )
        {
            // using maven 3.x or newer
        }

        try
        {
            List buildPlugins = new ArrayList( originalModel.getBuild().getPlugins() );
            for ( Iterator i = buildPlugins.iterator(); i.hasNext(); )
            {
                Plugin buildPlugin = i.next();
                if ( getPluginVersion( buildPlugin ) == null )
                {
                    String parentVersion = parentPluginManagement.get( getPluginCoords( buildPlugin ) );
                    if ( parentVersion != null )
                    {
                        // parent controls version
                        i.remove();
                    }
                }
            }
            addProjectPlugins( plugins, buildPlugins, parentBuildPlugins );
        }
        catch ( NullPointerException e )
        {
            // guess there are no plugins here
        }
        debugPluginMap( "after adding build plugins", plugins );

        try
        {
            List reportPlugins = new ArrayList( originalModel.getReporting().getPlugins() );
            for ( Iterator i = reportPlugins.iterator(); i.hasNext(); )
            {
                ReportPlugin reportPlugin = i.next();
                if ( getPluginVersion( reportPlugin ) == null )
                {
                    String parentVersion = parentPluginManagement.get( getPluginCoords( reportPlugin ) );
                    if ( parentVersion != null )
                    {
                        // parent controls version
                        i.remove();
                    }
                }
            }
            addProjectPlugins( plugins, toPlugins( reportPlugins ), parentReportPlugins );
        }
        catch ( NullPointerException e )
        {
            // guess there are no plugins here
        }
        debugPluginMap( "after adding reporting plugins", plugins );

        for ( Profile profile : originalModel.getProfiles() )
        {
            try
            {
                addProjectPlugins( plugins, profile.getBuild().getPluginManagement().getPlugins(),
                                   excludePluginManagement );
            }
            catch ( NullPointerException e )
            {
                // guess there are no plugins here
            }
            debugPluginMap( "after adding build pluginManagement for profile " + profile.getId(), plugins );

            try
            {
                addProjectPlugins( plugins, profile.getBuild().getPlugins(), parentBuildPlugins );
            }
            catch ( NullPointerException e )
            {
                // guess there are no plugins here
            }
            debugPluginMap( "after adding build plugins for profile " + profile.getId(), plugins );

            try
            {
                addProjectPlugins( plugins, toPlugins( profile.getReporting().getPlugins() ), parentReportPlugins );
            }
            catch ( NullPointerException e )
            {
                // guess there are no plugins here
            }
            debugPluginMap( "after adding reporting plugins for profile " + profile.getId(), plugins );
        }
        Set result = new TreeSet( new PluginComparator() );
        result.addAll( plugins.values() );
        return result;
    }

    /**
     * Adds those project plugins which are not inherited from the parent definitions to the list of plugins.
     *
     * @param plugins           The list of plugins.
     * @param projectPlugins    The project's plugins.
     * @param parentDefinitions The parent plugin definitions.
     * @since 1.0-alpha-1
     */
    private void addProjectPlugins( Map plugins, Collection projectPlugins,
                                    Map parentDefinitions )
    {
        for ( Plugin plugin : projectPlugins )
        {
            String coord = getPluginCoords( plugin );
            String version = getPluginVersion( plugin );
            String parentVersion = parentDefinitions.get( coord );
            if ( version == null && ( !plugins.containsKey( coord )
                || getPluginVersion( plugins.get( coord ) ) == null ) && parentVersion != null )
            {
                Plugin parentPlugin = new Plugin();
                parentPlugin.setGroupId( getPluginGroupId( plugin ) );
                parentPlugin.setArtifactId( getPluginArtifactId( plugin ) );
                parentPlugin.setVersion( parentVersion );
                plugins.put( coord, parentPlugin );
            }
            else if ( parentVersion == null || !parentVersion.equals( version ) )
            {
                if ( !plugins.containsKey( coord ) || getPluginVersion( plugins.get( coord ) ) == null )
                {
                    plugins.put( coord, plugin );
                }
            }
            if ( !plugins.containsKey( coord ) )
            {
                plugins.put( coord, plugin );
            }
        }
    }

    /**
     * Logs at debug level a map of plugins keyed by versionless key.
     *
     * @param description log description
     * @param plugins     a map with keys being the {@link String} corresponding to the versionless artifact key and
     *                    values being {@link Plugin} or {@link ReportPlugin}.
     */
    private void debugPluginMap( String description, Map plugins )
    {
        if ( getLog().isDebugEnabled() )
        {
            Set sorted = new TreeSet( new PluginComparator() );
            sorted.addAll( plugins.values() );
            StringBuilder buf = new StringBuilder( description );
            Iterator i = sorted.iterator();
            while ( i.hasNext() )
            {
                Object plugin = i.next();
                buf.append( "\n    " );
                buf.append( getPluginCoords( plugin ) );
                buf.append( ":" );
                buf.append( getPluginVersion( plugin ) );
            }
            getLog().debug( buf.toString() );
        }
    }

    /**
     * Logs at debug level a map of plugin versions keyed by versionless key.
     *
     * @param description log description
     * @param plugins     a map with keys being the {@link String} corresponding to the versionless artifact key and
     *                    values being {@link String} plugin version.
     */
    private void debugVersionMap( String description, Map plugins )
    {
        if ( getLog().isDebugEnabled() )
        {
            StringBuilder buf = new StringBuilder( description );
            Iterator i = plugins.entrySet().iterator();
            while ( i.hasNext() )
            {
                Map.Entry plugin = (Map.Entry) i.next();
                buf.append( "\n    " );
                buf.append( plugin.getKey() );
                buf.append( ":" );
                buf.append( plugin.getValue() );
            }
            getLog().debug( buf.toString() );
        }
    }

    /**
     * Returns the coordinates of a plugin.
     *
     * @param plugin The plugin
     * @return The groupId and artifactId separated by a colon.
     * @since 1.0-alpha-1
     */
    private static String getPluginCoords( Object plugin )
    {
        return getPluginGroupId( plugin ) + ":" + getPluginArtifactId( plugin );
    }

    /**
     * Returns the ArtifactId of a {@link Plugin} or {@link ReportPlugin}
     *
     * @param plugin the {@link Plugin} or {@link ReportPlugin}
     * @return the ArtifactId of the {@link Plugin} or {@link ReportPlugin}
     * @since 1.0-alpha-1
     */
    private static String getPluginArtifactId( Object plugin )
    {
        return plugin instanceof ReportPlugin
            ? ( (ReportPlugin) plugin ).getArtifactId()
            : ( (Plugin) plugin ).getArtifactId();
    }

    private static Plugin toPlugin( ReportPlugin reportPlugin )
    {
        Plugin plugin = new Plugin();
        plugin.setGroupId( reportPlugin.getGroupId() );
        plugin.setArtifactId( reportPlugin.getArtifactId() );
        plugin.setVersion( reportPlugin.getVersion() );
        return plugin;
    }

    private static ReportPlugin toReportPlugin( Plugin plugin )
    {
        ReportPlugin reportPlugin = new ReportPlugin();
        reportPlugin.setGroupId( plugin.getGroupId() );
        reportPlugin.setArtifactId( plugin.getArtifactId() );
        reportPlugin.setVersion( plugin.getVersion() );
        return reportPlugin;
    }

    private static Set toPlugins( Set reportPlugins )
    {
        Set result;
        if ( reportPlugins instanceof LinkedHashSet )
        {
            result = new LinkedHashSet( reportPlugins.size() );
        }
        else if ( reportPlugins instanceof SortedSet )
        {
            final Comparator comparator =
                ( (SortedSet) reportPlugins ).comparator();
            result = new TreeSet( new Comparator()
            {
                public int compare( Plugin o1, Plugin o2 )
                {
                    return comparator.compare( toReportPlugin( o1 ), toReportPlugin( o2 ) );
                }
            } );
        }
        else
        {
            result = new HashSet( reportPlugins.size() );
        }
        for ( ReportPlugin reportPlugin : reportPlugins )
        {
            result.add( toPlugin( reportPlugin ) );
        }
        return result;
    }

    private static List toPlugins( List reportPlugins )
    {
        List result = new ArrayList( reportPlugins.size() );
        for ( ReportPlugin reportPlugin : reportPlugins )
        {
            result.add( toPlugin( reportPlugin ) );
        }
        return result;
    }

    private static Collection toPlugins( Collection reportPlugins )
    {
        if ( reportPlugins instanceof Set )
        {
            return toPlugins( (Set) reportPlugins );
        }
        if ( reportPlugins instanceof List )
        {
            return toPlugins( (List) reportPlugins );
        }
        return toPlugins( new ArrayList( reportPlugins ) );
    }

    /**
     * Returns the GroupId of a {@link Plugin} or {@link ReportPlugin}
     *
     * @param plugin the {@link Plugin} or {@link ReportPlugin}
     * @return the GroupId of the {@link Plugin} or {@link ReportPlugin}
     * @since 1.0-alpha-1
     */
    private static String getPluginGroupId( Object plugin )
    {
        return plugin instanceof ReportPlugin
            ? ( (ReportPlugin) plugin ).getGroupId()
            : ( (Plugin) plugin ).getGroupId();
    }

    /**
     * Returns the Version of a {@link Plugin} or {@link ReportPlugin}
     *
     * @param plugin the {@link Plugin} or {@link ReportPlugin}
     * @return the Version of the {@link Plugin} or {@link ReportPlugin}
     * @since 1.0-alpha-1
     */
    private static String getPluginVersion( Object plugin )
    {
        return plugin instanceof ReportPlugin
            ? ( (ReportPlugin) plugin ).getVersion()
            : ( (Plugin) plugin ).getVersion();
    }

    /**
     * Gets the report plugins of a specific project.
     *
     * @param model                the model to get the report plugins from.
     * @param onlyIncludeInherited true to only return the plugins definitions that will be
     *                             inherited by child projects.
     * @return The map of effective plugin versions keyed by coordinates.
     * @since 1.0-alpha-1
     */
    private Map getReportPlugins( Model model, boolean onlyIncludeInherited )
    {
        Map reportPlugins = new HashMap();
        try
        {
            for ( ReportPlugin plugin : model.getReporting().getPlugins() )
            {
                String coord = getPluginCoords( plugin );
                String version = getPluginVersion( plugin );
                if ( version != null && ( !onlyIncludeInherited || getPluginInherited( plugin ) ) )
                {
                    reportPlugins.put( coord, version );
                }
            }
        }
        catch ( NullPointerException e )
        {
            // guess there are no plugins here
        }
        try
        {
            for ( Profile profile : model.getProfiles() )
            {
                try
                {
                    for ( ReportPlugin plugin : profile.getReporting().getPlugins() )
                    {
                        String coord = getPluginCoords( plugin );
                        String version = getPluginVersion( plugin );
                        if ( version != null && ( !onlyIncludeInherited || getPluginInherited( plugin ) ) )
                        {
                            reportPlugins.put( coord, version );
                        }
                    }
                }
                catch ( NullPointerException e )
                {
                    // guess there are no plugins here
                }
            }
        }
        catch ( NullPointerException e )
        {
            // guess there are no profiles here
        }
        return reportPlugins;
    }

    /**
     * @param pom the pom to update.
     * @throws MojoExecutionException when things go wrong
     * @throws MojoFailureException   when things go wrong in a very bad way
     * @throws XMLStreamException     when things go wrong with XML streaming
     * @see AbstractVersionsUpdaterMojo#update(ModifiedPomXMLEventReader)
     * @since 1.0-alpha-1
     */
    protected void update( ModifiedPomXMLEventReader pom )
        throws MojoExecutionException, MojoFailureException, XMLStreamException
    {
        // do nothing
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy