MDEP-76: added exclusion checking

git-svn-id: https://svn.apache.org/repos/asf/maven/plugins/trunk@522140 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/src/main/java/org/apache/maven/plugin/dependency/AnalyzeDepMgt.java b/src/main/java/org/apache/maven/plugin/dependency/AnalyzeDepMgt.java
index 5ba707d..e8d169e 100644
--- a/src/main/java/org/apache/maven/plugin/dependency/AnalyzeDepMgt.java
+++ b/src/main/java/org/apache/maven/plugin/dependency/AnalyzeDepMgt.java
@@ -19,7 +19,9 @@
  * under the License.

  */

 

+import java.util.ArrayList;

 import java.util.HashMap;

+import java.util.HashSet;

 import java.util.Iterator;

 import java.util.List;

 import java.util.Map;

@@ -42,7 +44,9 @@
  * to 2.0.6, it was possible to inherit versions that didn't match your

  * dependencyManagement. See <a

  * href="http://jira.codehaus.org/browse/MNG-1577">MNG-1577</a> for more info.

- * This mojo is also usefull for just detecting projects that override the dependencyManagement directly. Set ignoreDirect to false to detect these otherwise normal conditions.

+ * This mojo is also usefull for just detecting projects that override the

+ * dependencyManagement directly. Set ignoreDirect to false to detect these

+ * otherwise normal conditions.

  * 

  * @author <a href="mailto:brianefox@gmail.com">Brian Fox</a>

  * @version $Id: AnalyzeMojo.java 519377 2007-03-17 17:37:26Z brianf $

@@ -78,7 +82,6 @@
      */

     private boolean ignoreDirect = true;

 

-

     // Mojo methods -----------------------------------------------------------

 

     /*

@@ -102,16 +105,20 @@
         }

     }

 

-    // private methods --------------------------------------------------------

-

+    /**

+     * Does the work of checking the DependencyManagement Section.

+     * @return true if errors are found.

+     * @throws MojoExecutionException

+     */

     private boolean checkDependencyManagement()

         throws MojoExecutionException

     {

-        boolean foundMismatch = false;

+        boolean foundError = false;

 

         getLog().info( "Found Resolved Dependency / DependencyManagement mismatches:" );

 

         List depMgtDependencies = null;

+

         DependencyManagement depMgt = project.getDependencyManagement();

         if ( depMgt != null )

         {

@@ -121,15 +128,20 @@
         if ( depMgtDependencies != null && !depMgtDependencies.isEmpty() )

         {

             // put all the dependencies from depMgt into a map for quick lookup

-            Map map = new HashMap();

+            Map depMgtMap = new HashMap();

+            Map exclusions = new HashMap();

             Iterator iter = depMgtDependencies.iterator();

             while ( iter.hasNext() )

             {

-                Dependency dependency = (Dependency) iter.next();

-                map.put( dependency.getManagementKey(), dependency );

+                Dependency depMgtDependency = (Dependency) iter.next();

+                depMgtMap.put( depMgtDependency.getManagementKey(), depMgtDependency );

+

+                // now put all the exclusions into a map for quick lookup

+                exclusions.putAll( addExclusions( depMgtDependency.getExclusions() ) );

             }

 

-            Set allDependencies = project.getArtifacts();

+            // get dependencies for the project (including transitive)

+            Set allDependencyArtifacts = new HashSet( project.getArtifacts() );

 

             // don't warn if a dependency that is directly listed overrides

             // depMgt. That's ok.

@@ -137,25 +149,29 @@
             {

                 getLog().info( "\tIgnoring Direct Dependencies." );

                 Set directDependencies = project.getDependencyArtifacts();

-                allDependencies.removeAll( directDependencies );

+                allDependencyArtifacts.removeAll( directDependencies );

             }

 

-            iter = allDependencies.iterator();

-            while ( iter.hasNext() )

+            // log exclusion errors

+            List exclusionErrors = getExclusionErrors( exclusions, allDependencyArtifacts );

+            Iterator exclusionIter = exclusionErrors.iterator();

+            while ( exclusionIter.hasNext() )

             {

-                Artifact dependencyArtifact = (Artifact) iter.next();

-                Dependency depFromDepMgt = (Dependency) map.get( getArtifactManagementKey( dependencyArtifact ) );

-                if ( depFromDepMgt != null )

-                {

-                    ArtifactVersion artifactVersion = new DefaultArtifactVersion( dependencyArtifact.getVersion() );

+                Artifact exclusion = (Artifact) iter.next();

+                getLog().info(

+                               getArtifactManagementKey( exclusion ) + " was excluded in DepMgt, but version "

+                                   + exclusion.getVersion() + " has been found in the dependency tree." );

+                foundError = true;

+            }

 

-                    if ( !dependencyArtifact.isSnapshot() && !depFromDepMgt.getVersion().equals( dependencyArtifact.getVersion() ) )

-

-                    {

-                        logMismatch( dependencyArtifact, depFromDepMgt );

-                        foundMismatch = true;

-                    }

-                }

+            // find and log version mismatches

+            Map mismatch = getMismatch( depMgtMap, allDependencyArtifacts );

+            Iterator mismatchIter = mismatch.keySet().iterator();

+            while ( mismatchIter.hasNext() )

+            {

+                Artifact resolvedArtifact = (Artifact) mismatchIter.next();

+                Dependency depMgtDependency = (Dependency) mismatch.get( resolvedArtifact );

+                logMismatch( resolvedArtifact, depMgtDependency );

             }

         }

         else

@@ -163,20 +179,118 @@
             getLog().info( "   Nothing in DepMgt." );

         }

 

-        if ( !foundMismatch )

+        if ( !foundError )

         {

             getLog().info( "   None" );

         }

 

-        return foundMismatch;

+        return foundError;

     }

 

-    private void logMismatch( Artifact dependencyArtifact, Dependency dependencyFromDepMgt )

+    /**

+     * Returns a map of the exclusions using the Dependency ManagementKey as the

+     * keyset.

+     * 

+     * @param exclusionList

+     *            to be added to the map.

+     * @return a map of the exclusions using the Dependency ManagementKey as the

+     *         keyset.

+     */

+    public Map addExclusions( List exclusionList )

+    {

+        Map exclusions = new HashMap();

+        if ( exclusionList != null )

+        {

+            Iterator exclusionIter = exclusionList.iterator();

+            while ( exclusionIter.hasNext() )

+            {

+                Dependency exclusion = (Dependency) exclusionIter.next();

+                exclusions.put( exclusion.getManagementKey(), exclusion );

+            }

+        }

+        return exclusions;

+    }

+

+    /**

+     * Returns a List of the artifacts that should have been excluded, but where

+     * found in the dependency tree.

+     * 

+     * @param exclusions

+     *            a map of the DependencyManagement exclusions, with the

+     *            ManagementKey as the key and Dependency as the value.

+     * @param allDependencyArtifacts

+     *            resolved artifacts to be compared.

+     * @return list of artifacts that should have been excluded.

+     */

+    public List getExclusionErrors( Map exclusions, Set allDependencyArtifacts )

+    {

+        List list = new ArrayList();

+

+        Iterator iter = allDependencyArtifacts.iterator();

+        while ( iter.hasNext() )

+        {

+            Artifact artifact = (Artifact) iter.next();

+            if ( exclusions.containsKey( getArtifactManagementKey( artifact ) ) )

+            {

+                list.add( artifact );

+            }

+        }

+

+        return list;

+    }

+

+    /**

+     * Calculate the mismatches between the DependencyManagement and resolved

+     * artifacts

+     * 

+     * @param depMgtMap

+     *            contains the Dependency.GetManagementKey as the keyset for

+     *            quick lookup.

+     * @param allDependencyArtifacts

+     *            contains the set of all artifacts to compare.

+     * @return a map containing the resolved artifact as the key and the listed

+     *         dependency as the value.

+     */

+    public Map getMismatch( Map depMgtMap, Set allDependencyArtifacts )

+    {

+        Map mismatchMap = new HashMap();

+

+        Iterator iter = allDependencyArtifacts.iterator();

+        while ( iter.hasNext() )

+        {

+            Artifact dependencyArtifact = (Artifact) iter.next();

+            Dependency depFromDepMgt = (Dependency) depMgtMap.get( getArtifactManagementKey( dependencyArtifact ) );

+            if ( depFromDepMgt != null )

+            {

+                ArtifactVersion artifactVersion = new DefaultArtifactVersion( dependencyArtifact.getVersion() );

+

+                if ( !dependencyArtifact.isSnapshot()

+                    && !depFromDepMgt.getVersion().equals( dependencyArtifact.getVersion() ) )

+                {

+                    mismatchMap.put( dependencyArtifact, depFromDepMgt );

+                }

+            }

+        }

+        return mismatchMap;

+    }

+

+    /**

+     * This function displays the log to the screen showing the versions and

+     * information about the artifacts that don't match.

+     * 

+     * @param dependencyArtifact

+     *            the artifact that was resolved.

+     * @param dependencyFromDepMgt

+     *            the dependency listed in the DependencyManagement section.

+     * @throws MojoExecutionException

+     */

+    public void logMismatch( Artifact dependencyArtifact, Dependency dependencyFromDepMgt )

         throws MojoExecutionException

     {

         if ( dependencyArtifact == null || dependencyFromDepMgt == null )

         {

-            throw new MojoExecutionException( "Invalid params: Artifact:" + dependencyArtifact + " Dependency:" + dependencyFromDepMgt );

+            throw new MojoExecutionException( "Invalid params: Artifact:" + dependencyArtifact + " Dependency:"

+                + dependencyFromDepMgt );

         }

 

         getLog().info( "\tDependency: " + dependencyFromDepMgt.getManagementKey() );

@@ -184,10 +298,18 @@
         getLog().info( "\t\tResolved: " + dependencyArtifact.getVersion() );

     }

 

-    private String getArtifactManagementKey( Artifact artifact )

+    /**

+     * This function returns a string comparable with

+     * Dependency.GetManagementKey.

+     * 

+     * @param artifact

+     *            to gen the key for

+     * @return a string in the form: groupId:ArtifactId:Type[:Classifier]

+     */

+    public String getArtifactManagementKey( Artifact artifact )

     {

         return artifact.getGroupId() + ":" + artifact.getArtifactId() + ":" + artifact.getType()

-            + ( !StringUtils.isEmpty( artifact.getClassifier() ) ? ":" + artifact.getClassifier() : "" );

+            + (( artifact.getClassifier() !=null ) ? ":" + artifact.getClassifier() : "" );

     }

 

     /**

diff --git a/src/site/apt/usage.apt b/src/site/apt/usage.apt
index be832a9..b197488 100644
--- a/src/site/apt/usage.apt
+++ b/src/site/apt/usage.apt
@@ -578,6 +578,8 @@
 	
 	This mojo is also usefull for just detecting projects that override the dependencyManagement directly. Set ignoreDirect to false to detect these otherwise normal conditions.
 	
+	NOTE: In 2.0-alpha-3, the Labels shown in the output are reversed. This is corrected in 2.0-alpha-4: See MDEP-78.
+	
 	This mojo can be executed from the command line:
 	
 +---+
diff --git a/src/test/java/org/apache/maven/plugin/dependency/TestAnalyzeDepMgt.java b/src/test/java/org/apache/maven/plugin/dependency/TestAnalyzeDepMgt.java
new file mode 100644
index 0000000..0aac518
--- /dev/null
+++ b/src/test/java/org/apache/maven/plugin/dependency/TestAnalyzeDepMgt.java
@@ -0,0 +1,186 @@
+package org.apache.maven.plugin.dependency;

+

+import java.io.File;

+import java.io.IOException;

+import java.util.ArrayList;

+import java.util.HashMap;

+import java.util.Iterator;

+import java.util.List;

+import java.util.Map;

+import java.util.Set;

+

+import junit.framework.TestCase;

+

+import org.apache.maven.artifact.Artifact;

+import org.apache.maven.model.Dependency;

+import org.apache.maven.plugin.MojoExecutionException;

+import org.apache.maven.plugin.MojoFailureException;

+import org.apache.maven.plugin.dependency.testUtils.ArtifactStubFactory;

+import org.apache.maven.plugin.dependency.testUtils.stubs.DependencyProjectStub;

+import org.apache.maven.project.MavenProject;

+

+/*

+ * 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.

+ */

+

+

+public class TestAnalyzeDepMgt

+    extends TestCase

+{

+

+    AnalyzeDepMgt mojo;

+    ArtifactStubFactory stubFactory;

+    Dependency exclusion;

+    Artifact exclusionArtifact;

+

+    protected void setUp()

+        throws Exception

+    {

+        

+        stubFactory = new ArtifactStubFactory( new File(""), false );

+        

+        Set allArtifacts = stubFactory.getMixedArtifacts();

+        Set directArtifacts = stubFactory.getClassifiedArtifacts();

+        

+        exclusionArtifact = stubFactory.getReleaseArtifact();

+        exclusion = new Dependency();

+        exclusion.setArtifactId( exclusionArtifact.getArtifactId() );

+        exclusion.setGroupId( exclusionArtifact.getGroupId() );

+        exclusion.setType( exclusionArtifact.getType() );

+        exclusion.setClassifier( "" );

+        exclusion.setVersion( "3.0" );

+        

+        mojo = new AnalyzeDepMgt();

+        MavenProject project = new DependencyProjectStub();

+        project.setArtifacts( allArtifacts );

+        project.setDependencyArtifacts( directArtifacts );

+        

+        mojo.setProject( project );

+        

+    }

+

+    public void testGetManagementKey() throws IOException

+    {

+        Dependency dep = new Dependency();

+        dep.setArtifactId( "artifact" );

+        dep.setClassifier( "class" );

+        dep.setGroupId( "group" );

+        dep.setType( "type" );

+        

+        //version isn't used in the key, it can be different

+        dep.setVersion( "1.1" );

+        

+        Artifact artifact = stubFactory.createArtifact( "group", "artifact", "1.0",Artifact.SCOPE_COMPILE,"type","class" );

+

+        //basic case ok

+        assertEquals( dep.getManagementKey(), mojo.getArtifactManagementKey( artifact ) );

+        

+        //now change each one and make sure it fails, then set it back and make sure it's ok before

+        //testing the next one

+        dep.setType( "t" );

+        assertFalse ( dep.getManagementKey().equals(mojo.getArtifactManagementKey( artifact ) ));

+        

+        dep.setType( "type" );

+        assertEquals( dep.getManagementKey(), mojo.getArtifactManagementKey( artifact ) );

+        

+        dep.setArtifactId( "a" );

+        assertFalse ( dep.getManagementKey().equals(mojo.getArtifactManagementKey( artifact ) ));

+        

+        dep.setArtifactId( "artifact" );

+        assertEquals( dep.getManagementKey(), mojo.getArtifactManagementKey( artifact ) );

+        

+        dep.setClassifier( "c" );

+        assertFalse ( dep.getManagementKey().equals(mojo.getArtifactManagementKey( artifact ) ));

+        

+        dep.setClassifier( "class" );

+        assertEquals( dep.getManagementKey(), mojo.getArtifactManagementKey( artifact ) );

+                

+        dep.setGroupId( "g" );

+        assertFalse ( dep.getManagementKey().equals(mojo.getArtifactManagementKey( artifact ) ));

+        

+        dep.setGroupId( "group" );

+        dep.setClassifier( null );

+        artifact = stubFactory.createArtifact( "group", "artifact", "1.0",Artifact.SCOPE_COMPILE,"type",null );

+        assertEquals( dep.getManagementKey(), mojo.getArtifactManagementKey( artifact ) );

+        

+        dep.setClassifier( "" );

+        artifact = stubFactory.createArtifact( "group", "artifact", "1.0",Artifact.SCOPE_COMPILE,"type","" );

+        assertEquals( dep.getManagementKey(), mojo.getArtifactManagementKey( artifact ) );

+    }

+    

+    public void testAddExclusions()

+    {

+        Dependency dep = new Dependency();

+        dep.setArtifactId( "artifact" );

+        dep.setClassifier( "class" );

+        dep.setGroupId( "group" );

+        dep.setType( "type" );

+        

+        assertEquals( 0, mojo.addExclusions( null ).size() );

+       

+        ArrayList list = new ArrayList();

+        assertEquals( 0, mojo.addExclusions( null ).size() );

+        

+        list.add( dep );

+        Map map = mojo.addExclusions( list );

+        

+        assertTrue(map.containsKey( dep.getManagementKey() ));

+        assertSame( dep, map.get( dep.getManagementKey() ) );

+    }

+    

+    public void testGetExclusionErrors()

+    {

+        ArrayList list = new ArrayList();

+        list.add( exclusion );

+        

+        //already tested this method so I can trust it.

+        Map map = mojo.addExclusions( list );

+        

+        List l = mojo.getExclusionErrors( map, mojo.getProject().getArtifacts() );

+        

+        assertEquals( 1, l.size() );

+        

+        assertEquals( exclusion.getManagementKey(), mojo.getArtifactManagementKey( (Artifact) l.get( 0 ) ));

+    }

+

+    public void testGetMismatch() throws IOException

+    {

+        Map depMgtMap = new HashMap();

+

+        depMgtMap.put( exclusion.getManagementKey(), exclusion );

+        

+        Map results = mojo.getMismatch( depMgtMap, mojo.getProject().getArtifacts() );

+        

+        assertEquals( 1, results.size() );

+        //the release artifact is used to create the exclusion

+        assertTrue( results.containsKey( stubFactory.getReleaseArtifact()));

+        assertSame( exclusion,results.get( stubFactory.getReleaseArtifact()));

+    }

+    

+    public void testMojo()

+    {

+        try

+        {

+            mojo.execute();

+        }

+        catch ( Exception e )

+        {

+            fail("Caught Unexpected Exception:"+e.getLocalizedMessage());

+        }

+    }

+}