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 * @Component
58 * private ProjectBuilder projectBuilder;
59 *
60 * // For Components
61 * @Requirement // or @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 }