Coverage Report - org.apache.maven.shared.dependency.analyzer.DefaultProjectDependencyAnalyzer
 
Classes in this File Line Coverage Branch Coverage Complexity
DefaultProjectDependencyAnalyzer
94%
55/58
87%
21/24
3
 
 1  
 package org.apache.maven.shared.dependency.analyzer;
 2  
 
 3  
 /*
 4  
  * Licensed to the Apache Software Foundation (ASF) under one
 5  
  * or more contributor license agreements.  See the NOTICE file
 6  
  * distributed with this work for additional information
 7  
  * regarding copyright ownership.  The ASF licenses this file
 8  
  * to you under the Apache License, Version 2.0 (the
 9  
  * "License"); you may not use this file except in compliance
 10  
  * with the License.  You may obtain a copy of the License at
 11  
  *
 12  
  *  http://www.apache.org/licenses/LICENSE-2.0
 13  
  *
 14  
  * Unless required by applicable law or agreed to in writing,
 15  
  * software distributed under the License is distributed on an
 16  
  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 17  
  * KIND, either express or implied.  See the License for the
 18  
  * specific language governing permissions and limitations
 19  
  * under the License.
 20  
  */
 21  
 
 22  
 import java.io.File;
 23  
 import java.io.IOException;
 24  
 import java.net.URL;
 25  
 import java.util.Collections;
 26  
 import java.util.HashSet;
 27  
 import java.util.LinkedHashMap;
 28  
 import java.util.LinkedHashSet;
 29  
 import java.util.Map;
 30  
 import java.util.Set;
 31  
 
 32  
 import org.apache.maven.artifact.Artifact;
 33  
 import org.apache.maven.project.MavenProject;
 34  
 import org.codehaus.plexus.component.annotations.Component;
 35  
 import org.codehaus.plexus.component.annotations.Requirement;
 36  
 
 37  
 /**
 38  
  * 
 39  
  * 
 40  
  * @author <a href="mailto:markhobson@gmail.com">Mark Hobson</a>
 41  
  * @version $Id: DefaultProjectDependencyAnalyzer.java 1399946 2012-10-19 02:05:16Z hboutemy $
 42  
  */
 43  
 @Component( role = ProjectDependencyAnalyzer.class )
 44  5
 public class DefaultProjectDependencyAnalyzer
 45  
     implements ProjectDependencyAnalyzer
 46  
 {
 47  
     // fields -----------------------------------------------------------------
 48  
 
 49  
     /**
 50  
      * ClassAnalyzer
 51  
      */
 52  
     @Requirement
 53  
     private ClassAnalyzer classAnalyzer;
 54  
 
 55  
     /**
 56  
      * DependencyAnalyzer
 57  
      */
 58  
     @Requirement
 59  
     private DependencyAnalyzer dependencyAnalyzer;
 60  
 
 61  
     // ProjectDependencyAnalyzer methods --------------------------------------
 62  
 
 63  
     /*
 64  
      * @see org.apache.maven.shared.dependency.analyzer.ProjectDependencyAnalyzer#analyze(org.apache.maven.project.MavenProject)
 65  
      */
 66  
     public ProjectDependencyAnalysis analyze( MavenProject project )
 67  
         throws ProjectDependencyAnalyzerException
 68  
     {
 69  
         try
 70  
         {
 71  5
             Map<Artifact, Set<String>> artifactClassMap = buildArtifactClassMap( project );
 72  
 
 73  5
             Set<String> dependencyClasses = buildDependencyClasses( project );
 74  
 
 75  5
             Set<Artifact> declaredArtifacts = buildDeclaredArtifacts( project );
 76  
 
 77  5
             Set<Artifact> usedArtifacts = buildUsedArtifacts( artifactClassMap, dependencyClasses );
 78  
 
 79  5
             Set<Artifact> usedDeclaredArtifacts = new LinkedHashSet<Artifact>( declaredArtifacts );
 80  5
             usedDeclaredArtifacts.retainAll( usedArtifacts );
 81  
 
 82  5
             Set<Artifact> usedUndeclaredArtifacts = new LinkedHashSet<Artifact>( usedArtifacts );
 83  5
             usedUndeclaredArtifacts = removeAll( usedUndeclaredArtifacts, declaredArtifacts );
 84  
 
 85  5
             Set<Artifact> unusedDeclaredArtifacts = new LinkedHashSet<Artifact>( declaredArtifacts );
 86  5
             unusedDeclaredArtifacts = removeAll( unusedDeclaredArtifacts, usedArtifacts );
 87  
 
 88  5
             return new ProjectDependencyAnalysis( usedDeclaredArtifacts, usedUndeclaredArtifacts,
 89  
                                                   unusedDeclaredArtifacts );
 90  
         }
 91  0
         catch ( IOException exception )
 92  
         {
 93  0
             throw new ProjectDependencyAnalyzerException( "Cannot analyze dependencies", exception );
 94  
         }
 95  
     }
 96  
 
 97  
     /**
 98  
      * This method defines a new way to remove the artifacts by using the
 99  
      * conflict id. We don't care about the version here because there can be
 100  
      * only 1 for a given artifact anyway.
 101  
      * 
 102  
      * @param start
 103  
      *            initial set
 104  
      * @param remove
 105  
      *            set to exclude
 106  
      * @return set with remove excluded
 107  
      */
 108  
     private Set<Artifact> removeAll( Set<Artifact> start, Set<Artifact> remove )
 109  
     {
 110  10
         Set<Artifact> results = new LinkedHashSet<Artifact>( start.size() );
 111  
 
 112  10
         for ( Artifact artifact : start )
 113  
         {
 114  8
             boolean found = false;
 115  
 
 116  8
             for ( Artifact artifact2 : remove )
 117  
             {
 118  9
                 if ( artifact.getDependencyConflictId().equals( artifact2.getDependencyConflictId() ) )
 119  
                 {
 120  6
                     found = true;
 121  6
                     break;
 122  
                 }
 123  
             }
 124  
 
 125  8
             if ( !found )
 126  
             {
 127  2
                 results.add( artifact );
 128  
             }
 129  8
         }
 130  
 
 131  10
         return results;
 132  
     }
 133  
 
 134  
     // private methods --------------------------------------------------------
 135  
 
 136  
     private Map<Artifact, Set<String>> buildArtifactClassMap( MavenProject project )
 137  
         throws IOException
 138  
     {
 139  5
         Map<Artifact, Set<String>> artifactClassMap = new LinkedHashMap<Artifact, Set<String>>();
 140  
 
 141  
         @SuppressWarnings( "unchecked" )
 142  5
         Set<Artifact> dependencyArtifacts = project.getArtifacts();
 143  
 
 144  5
         for ( Artifact artifact : dependencyArtifacts )
 145  
         {
 146  5
             File file = artifact.getFile();
 147  
 
 148  5
             if ( file != null && file.getName().endsWith( ".jar" ) )
 149  
             {
 150  5
                 URL url = file.toURL();
 151  
 
 152  5
                 Set<String> classes = classAnalyzer.analyze( url );
 153  
 
 154  5
                 artifactClassMap.put( artifact, classes );
 155  
             }
 156  5
         }
 157  
 
 158  5
         return artifactClassMap;
 159  
     }
 160  
 
 161  
     protected Set<String> buildDependencyClasses( MavenProject project )
 162  
         throws IOException
 163  
     {
 164  5
         Set<String> dependencyClasses = new HashSet<String>();
 165  
 
 166  5
         String outputDirectory = project.getBuild().getOutputDirectory();
 167  5
         dependencyClasses.addAll( buildDependencyClasses( outputDirectory ) );
 168  
 
 169  5
         String testOutputDirectory = project.getBuild().getTestOutputDirectory();
 170  5
         dependencyClasses.addAll( buildDependencyClasses( testOutputDirectory ) );
 171  
 
 172  5
         return dependencyClasses;
 173  
     }
 174  
     
 175  
     private Set<String> buildDependencyClasses( String path )
 176  
         throws IOException
 177  
     {
 178  10
         URL url = new File( path ).toURI().toURL();
 179  
 
 180  10
         return dependencyAnalyzer.analyze( url );
 181  
     }
 182  
     
 183  
     private Set<Artifact> buildDeclaredArtifacts( MavenProject project )
 184  
     {
 185  
         @SuppressWarnings( "unchecked" )
 186  5
         Set<Artifact> declaredArtifacts = project.getDependencyArtifacts();
 187  
 
 188  5
         if ( declaredArtifacts == null )
 189  
         {
 190  0
             declaredArtifacts = Collections.<Artifact>emptySet();
 191  
         }
 192  
 
 193  5
         return declaredArtifacts;
 194  
     }
 195  
     
 196  
     private Set<Artifact> buildUsedArtifacts( Map<Artifact, Set<String>> artifactClassMap, Set<String> dependencyClasses )
 197  
     {
 198  5
         Set<Artifact> usedArtifacts = new HashSet<Artifact>();
 199  
 
 200  5
         for ( String className : dependencyClasses )
 201  
         {
 202  12
             Artifact artifact = findArtifactForClassName( artifactClassMap, className );
 203  
 
 204  12
             if ( artifact != null )
 205  
             {
 206  4
                 usedArtifacts.add( artifact );
 207  
             }
 208  12
         }
 209  
 
 210  5
         return usedArtifacts;
 211  
     }
 212  
 
 213  
     protected Artifact findArtifactForClassName( Map<Artifact, Set<String>> artifactClassMap, String className )
 214  
     {
 215  12
         for ( Map.Entry<Artifact, Set<String>> entry : artifactClassMap.entrySet() )
 216  
         {
 217  16
             if ( entry.getValue().contains( className ) )
 218  
             {
 219  4
                 return entry.getKey();
 220  
             }
 221  
         }
 222  
 
 223  8
         return null;
 224  
     }
 225  
 }