View Javadoc
1   package org.apache.maven.shared.artifact.filter.collection;
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 org.apache.maven.RepositoryUtils;
23  import org.apache.maven.artifact.Artifact;
24  import org.apache.maven.project.DefaultProjectBuildingRequest;
25  import org.apache.maven.project.DependencyResolutionResult;
26  import org.apache.maven.project.ProjectBuilder;
27  import org.apache.maven.project.ProjectBuildingException;
28  import org.apache.maven.project.ProjectBuildingRequest;
29  import org.apache.maven.project.ProjectBuildingResult;
30  
31  import java.lang.reflect.InvocationTargetException;
32  import java.util.HashSet;
33  import java.util.List;
34  import java.util.Set;
35  
36  /**
37   * This filter will exclude everything that is not a dependency of the selected artifact.
38   *
39   * @author <a href="mailto:brianf@apache.org">Brian Fox</a>
40   * @version $Id: ArtifactTransitivityFilter.java 1716978 2015-11-28 14:47:04Z khmarbaise $
41   */
42  public class ArtifactTransitivityFilter
43      extends AbstractArtifactsFilter
44  {
45      /**
46       * List of dependencyConflictIds of transitiveArtifacts
47       */
48      private Set<String> transitiveArtifacts;
49  
50      /**
51       * <p>
52       * Use {@link org.apache.maven.execution.MavenSession#getProjectBuildingRequest()} to get the buildingRequest.
53       * The projectBuilder should be resolved with CDI.
54       * </p>
55       * <pre>
56       *   // For Mojo
57       *   &#64;Component
58       *   private ProjectBuilder projectBuilder;
59       *
60       *   // For Components
61       *   &#64;Requirement // or &#64;Inject
62       *   private ProjectBuilder projectBuilder;
63       * </pre>
64       *
65       * @param artifact        the artifact to resolve the dependencies from
66       * @param buildingRequest the buildingRequest
67       * @param projectBuilder  the projectBuilder
68       * @throws ProjectBuildingException if the project descriptor could not be successfully built
69       */
70      public ArtifactTransitivityFilter( Artifact artifact, ProjectBuildingRequest buildingRequest,
71                                         ProjectBuilder projectBuilder )
72          throws ProjectBuildingException
73      {
74          ProjectBuildingRequest request = new DefaultProjectBuildingRequest( buildingRequest );
75  
76          request.setResolveDependencies( true );
77  
78          ProjectBuildingResult buildingResult = projectBuilder.build( artifact, request );
79  
80          DependencyResolutionResult resolutionResult = buildingResult.getDependencyResolutionResult();
81          if ( resolutionResult != null )
82          {
83              if ( isMaven31() )
84              {
85                  try
86                  {
87                      @SuppressWarnings( "unchecked" ) List<org.eclipse.aether.graph.Dependency> dependencies =
88                          (List<org.eclipse.aether.graph.Dependency>) Invoker.invoke( resolutionResult,
89                                                                                      "getDependencies" );
90  
91                      for ( org.eclipse.aether.graph.Dependency dependency : dependencies )
92                      {
93                          Artifact mavenArtifact = 
94                                          (Artifact) Invoker.invoke( RepositoryUtils.class, "toArtifact",
95                                                                      org.eclipse.aether.artifact.Artifact.class,
96                                                                      dependency.getArtifact() );
97  
98                          transitiveArtifacts.add( mavenArtifact.getDependencyConflictId() );
99                      }
100                 }
101                 catch ( IllegalAccessException e )
102                 {
103                     // don't want to pollute method signature with ReflectionExceptions
104                     throw new RuntimeException( e.getMessage(), e );
105                 }
106                 catch ( InvocationTargetException e )
107                 {
108                     // don't want to pollute method signature with ReflectionExceptions
109                     throw new RuntimeException( e.getMessage(), e );
110                 }
111                 catch ( NoSuchMethodException e )
112                 {
113                     // don't want to pollute method signature with ReflectionExceptions
114                     throw new RuntimeException( e.getMessage(), e );
115                 }
116             }
117             else
118             {
119                 try
120                 {
121                     @SuppressWarnings( "unchecked" ) List<org.sonatype.aether.graph.Dependency> dependencies =
122                         (List<org.sonatype.aether.graph.Dependency>) Invoker.invoke( resolutionResult,
123                                                                                      "getDependencies" );
124 
125                     for ( org.sonatype.aether.graph.Dependency dependency : dependencies )
126                     {
127                         Artifact mavenArtifact = 
128                                         (Artifact) Invoker.invoke( RepositoryUtils.class, "toArtifact",
129                                                                     org.sonatype.aether.artifact.Artifact.class,
130                                                                     dependency.getArtifact() );
131 
132                         transitiveArtifacts.add( mavenArtifact.getDependencyConflictId() );
133                     }
134                 }
135                 catch ( IllegalAccessException e )
136                 {
137                     // don't want to pollute method signature with ReflectionExceptions
138                     throw new RuntimeException( e.getMessage(), e );
139                 }
140                 catch ( InvocationTargetException e )
141                 {
142                     // don't want to pollute method signature with ReflectionExceptions
143                     throw new RuntimeException( e.getMessage(), e );
144                 }
145                 catch ( NoSuchMethodException e )
146                 {
147                     // don't want to pollute method signature with ReflectionExceptions
148                     throw new RuntimeException( e.getMessage(), e );
149                 }
150             }
151         }
152     }
153 
154     /**
155      * @return true if the current Maven version is Maven 3.1.
156      */
157     protected static boolean isMaven31()
158     {
159         return canFindCoreClass( "org.eclipse.aether.artifact.Artifact" ); // Maven 3.1 specific
160     }
161 
162     private static boolean canFindCoreClass( String className )
163     {
164         try
165         {
166             Thread.currentThread().getContextClassLoader().loadClass( className );
167 
168             return true;
169         }
170         catch ( ClassNotFoundException e )
171         {
172             return false;
173         }
174     }
175 
176     /**
177      * {@inheritDoc}
178      */
179     public Set<Artifact> filter( Set<Artifact> artifacts )
180     {
181 
182         Set<Artifact> result = new HashSet<Artifact>();
183         for ( Artifact artifact : artifacts )
184         {
185             if ( artifactIsATransitiveDependency( artifact ) )
186             {
187                 result.add( artifact );
188             }
189         }
190         return result;
191     }
192 
193     /**
194      * Compares the artifact to the list of dependencies to see if it is directly included by this project
195      *
196      * @param artifact representing the item to compare.
197      * @return true if artifact is a transitive dependency
198      */
199     public boolean artifactIsATransitiveDependency( Artifact artifact )
200     {
201         return transitiveArtifacts.contains( artifact.getDependencyConflictId() );
202     }
203 }