View Javadoc

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.util.Arrays;
23  import java.util.Collections;
24  import java.util.HashSet;
25  import java.util.Iterator;
26  import java.util.LinkedHashSet;
27  import java.util.Set;
28  
29  import org.apache.maven.artifact.Artifact;
30  
31  /**
32   * Project dependencies analysis result.
33   * 
34   * @author <a href="mailto:markhobson@gmail.com">Mark Hobson</a>
35   * @version $Id: ProjectDependencyAnalysis.java 1400637 2012-10-21 13:09:09Z hboutemy $
36   */
37  public class ProjectDependencyAnalysis
38  {
39      // fields -----------------------------------------------------------------
40  
41      private final Set<Artifact> usedDeclaredArtifacts;
42  
43      private final Set<Artifact> usedUndeclaredArtifacts;
44  
45      private final Set<Artifact> unusedDeclaredArtifacts;
46  
47      // constructors -----------------------------------------------------------
48  
49      public ProjectDependencyAnalysis()
50      {
51          this( null, null, null );
52      }
53  
54      public ProjectDependencyAnalysis( Set<Artifact> usedDeclaredArtifacts, Set<Artifact> usedUndeclaredArtifacts,
55                                        Set<Artifact> unusedDeclaredArtifacts )
56      {
57          this.usedDeclaredArtifacts = safeCopy( usedDeclaredArtifacts );
58          this.usedUndeclaredArtifacts = safeCopy( usedUndeclaredArtifacts );
59          this.unusedDeclaredArtifacts = safeCopy( unusedDeclaredArtifacts );
60      }
61  
62      // public methods ---------------------------------------------------------
63  
64      /**
65       * Used and declared artifacts.
66       */
67      public Set<Artifact> getUsedDeclaredArtifacts()
68      {
69          return usedDeclaredArtifacts;
70      }
71  
72      /**
73       * Used but not declared artifacts.
74       */
75      public Set<Artifact> getUsedUndeclaredArtifacts()
76      {
77          return usedUndeclaredArtifacts;
78      }
79  
80      /**
81       * Unused but declared artifacts.
82       */
83      public Set<Artifact> getUnusedDeclaredArtifacts()
84      {
85          return unusedDeclaredArtifacts;
86      }
87  
88      /**
89       * Filter not-compile scoped artifacts from unused declared.
90       * 
91       * @return updated project dependency analysis
92       * @since 1.3
93       */
94      public ProjectDependencyAnalysis ignoreNonCompile()
95      {
96          Set<Artifact> filteredUnusedDeclared = new HashSet<Artifact>( unusedDeclaredArtifacts );
97          for ( Iterator<Artifact> iter = filteredUnusedDeclared.iterator(); iter.hasNext(); )
98          {
99              Artifact artifact = iter.next();
100             if ( !artifact.getScope().equals( Artifact.SCOPE_COMPILE ) )
101             {
102                 iter.remove();
103             }
104         }
105 
106         return new ProjectDependencyAnalysis( usedDeclaredArtifacts, usedUndeclaredArtifacts, filteredUnusedDeclared );
107     }
108 
109     /**
110      * Force use status of some declared dependencies, to manually fix consequences of bytecode-level analysis which
111      * happens to not detect some effective use (constants, annotation with source-retention, javadoc).
112      * 
113      * @param forceUsedDependencies dependencies to move from "unused-declared" to "used-declared", with
114      *            <code>groupId:artifactId</code> format
115      * @return updated project dependency analysis
116      * @throws ProjectDependencyAnalyzerException if dependencies forced were either not declared or already detected as
117      *             used
118      * @since 1.3
119      */
120     public ProjectDependencyAnalysis forceDeclaredDependenciesUsage( String[] forceUsedDependencies )
121         throws ProjectDependencyAnalyzerException
122     {
123         Set<String> forced = new HashSet<String>( Arrays.asList( forceUsedDependencies ) );
124 
125         Set<Artifact> forcedUnusedDeclared = new HashSet<Artifact>( unusedDeclaredArtifacts );
126         Set<Artifact> forcedUsedDeclared = new HashSet<Artifact>( usedDeclaredArtifacts );
127 
128         for ( Iterator<Artifact> iter = forcedUnusedDeclared.iterator(); iter.hasNext(); )
129         {
130             Artifact artifact = iter.next();
131 
132             if ( forced.remove( artifact.getGroupId() + ':' + artifact.getArtifactId() ) )
133             {
134                 // ok, change artifact status from unused-declared to used-declared
135                 iter.remove();
136                 forcedUsedDeclared.add( artifact );
137             }
138         }
139 
140         if ( !forced.isEmpty() )
141         {
142             // trying to force dependencies as used-declared which were not declared or already detected as used
143             Set<String> used = new HashSet<String>();
144             for ( Artifact artifact : usedDeclaredArtifacts )
145             {
146                 String id = artifact.getGroupId() + ':' + artifact.getArtifactId();
147                 if ( forced.remove( id ) )
148                 {
149                     used.add( id );
150                 }
151             }
152 
153             StringBuilder builder = new StringBuilder();
154             if ( !forced.isEmpty() )
155             {
156                 builder.append( "not declared: " + forced );
157             }
158             if ( !used.isEmpty() )
159             {
160                 if ( builder.length() > 0 )
161                 {
162                     builder.append( " and " );
163                 }
164                 builder.append( "declared but already detected as used: " + used );
165             }
166             throw new ProjectDependencyAnalyzerException( "Trying to force use of dependencies which are " + builder );
167         }
168 
169         return new ProjectDependencyAnalysis( forcedUsedDeclared, usedUndeclaredArtifacts, forcedUnusedDeclared );
170     }
171 
172     // Object methods ---------------------------------------------------------
173 
174     /*
175      * @see java.lang.Object#hashCode()
176      */
177     public int hashCode()
178     {
179         int hashCode = getUsedDeclaredArtifacts().hashCode();
180         hashCode = ( hashCode * 37 ) + getUsedUndeclaredArtifacts().hashCode();
181         hashCode = ( hashCode * 37 ) + getUnusedDeclaredArtifacts().hashCode();
182 
183         return hashCode;
184     }
185 
186     /*
187      * @see java.lang.Object#equals(java.lang.Object)
188      */
189     public boolean equals( Object object )
190     {
191         if ( object instanceof ProjectDependencyAnalysis )
192         {
193             ProjectDependencyAnalysis analysis = (ProjectDependencyAnalysis) object;
194 
195             return getUsedDeclaredArtifacts().equals( analysis.getUsedDeclaredArtifacts() )
196                 && getUsedUndeclaredArtifacts().equals( analysis.getUsedUndeclaredArtifacts() )
197                 && getUnusedDeclaredArtifacts().equals( analysis.getUnusedDeclaredArtifacts() );
198         }
199 
200         return false;
201     }
202 
203     /*
204      * @see java.lang.Object#toString()
205      */
206     public String toString()
207     {
208         StringBuffer buffer = new StringBuffer();
209 
210         if ( !getUsedDeclaredArtifacts().isEmpty() )
211         {
212             buffer.append( "usedDeclaredArtifacts=" ).append( getUsedDeclaredArtifacts() );
213         }
214 
215         if ( !getUsedUndeclaredArtifacts().isEmpty() )
216         {
217             if ( buffer.length() > 0)
218             {
219                 buffer.append( "," );
220             }
221 
222             buffer.append( "usedUndeclaredArtifacts=" ).append( getUsedUndeclaredArtifacts() );
223         }
224 
225         if ( !getUnusedDeclaredArtifacts().isEmpty() )
226         {
227             if ( buffer.length() > 0)
228             {
229                 buffer.append( "," );
230             }
231 
232             buffer.append( "unusedDeclaredArtifacts=" ).append( getUnusedDeclaredArtifacts() );
233         }
234 
235         buffer.insert( 0, "[" );
236         buffer.insert( 0, getClass().getName() );
237 
238         buffer.append( "]" );
239 
240         return buffer.toString();
241     }
242 
243     // private methods --------------------------------------------------------
244 
245     private Set<Artifact> safeCopy( Set<Artifact> set )
246     {
247         return ( set == null ) ? Collections.<Artifact> emptySet()
248                         : Collections.unmodifiableSet( new LinkedHashSet<Artifact>( set ) );
249     }
250 }