View Javadoc
1   package org.apache.maven.plugin.surefire;
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.Iterator;
23  import java.util.LinkedHashSet;
24  import java.util.List;
25  import java.util.Map;
26  import java.util.Set;
27  
28  import org.apache.maven.artifact.Artifact;
29  import org.apache.maven.artifact.factory.ArtifactFactory;
30  import org.apache.maven.artifact.repository.ArtifactRepository;
31  import org.apache.maven.artifact.resolver.ArtifactResolutionRequest;
32  import org.apache.maven.artifact.resolver.ArtifactResolutionResult;
33  import org.apache.maven.artifact.resolver.filter.ExcludesArtifactFilter;
34  import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
35  import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
36  import org.apache.maven.artifact.versioning.OverConstrainedVersionException;
37  import org.apache.maven.artifact.versioning.VersionRange;
38  import org.apache.maven.plugin.surefire.log.api.ConsoleLogger;
39  import org.apache.maven.repository.RepositorySystem;
40  
41  import javax.annotation.Nonnull;
42  import javax.annotation.Nullable;
43  
44  import static java.util.Collections.singletonList;
45  import static org.apache.maven.artifact.Artifact.SCOPE_TEST;
46  import static org.apache.maven.artifact.versioning.VersionRange.createFromVersion;
47  import static org.apache.maven.artifact.versioning.VersionRange.createFromVersionSpec;
48  
49  /**
50   * Does dependency resolution and artifact handling for the surefire plugin.
51   *
52   * @author Stephen Connolly
53   * @author Kristian Rosenvold
54   */
55  final class SurefireDependencyResolver
56  {
57      static final String PROVIDER_GROUP_ID = "org.apache.maven.surefire";
58  
59      private static final String[] PROVIDER_CLASSPATH_ORDER = {
60              "surefire-junit3",
61              "surefire-junit4",
62              "surefire-junit47",
63              "surefire-testng",
64              "surefire-junit-platform",
65              "surefire-api",
66              "surefire-logger-api",
67              "common-java5",
68              "common-junit3",
69              "common-junit4",
70              "common-junit48",
71              "common-testng-utils"
72      };
73  
74      private final RepositorySystem repositorySystem;
75  
76      private final ArtifactFactory artifactFactory;
77  
78      private final ConsoleLogger log;
79  
80      private final ArtifactRepository localRepository;
81  
82      private final List<ArtifactRepository> remoteRepositories;
83  
84      private final String pluginName;
85  
86      SurefireDependencyResolver( RepositorySystem repositorySystem, ArtifactFactory artifactFactory, ConsoleLogger log,
87                                            ArtifactRepository localRepository,
88                                            List<ArtifactRepository> remoteRepositories, String pluginName )
89      {
90          this.repositorySystem = repositorySystem;
91          this.artifactFactory = artifactFactory;
92          this.log = log;
93          this.localRepository = localRepository;
94          this.remoteRepositories = remoteRepositories;
95          this.pluginName = pluginName;
96      }
97  
98      static boolean isWithinVersionSpec( @Nullable Artifact artifact, @Nonnull String versionSpec )
99      {
100         if ( artifact == null )
101         {
102             return false;
103         }
104         try
105         {
106             VersionRange range = createFromVersionSpec( versionSpec );
107             try
108             {
109                 return range.containsVersion( artifact.getSelectedVersion() );
110             }
111             catch ( NullPointerException e )
112             {
113                 return range.containsVersion( new DefaultArtifactVersion( artifact.getBaseVersion() ) );
114             }
115         }
116         catch ( InvalidVersionSpecificationException e )
117         {
118             throw new RuntimeException( "Bug in plugin. Please report with stacktrace" );
119         }
120         catch ( OverConstrainedVersionException e )
121         {
122             throw new RuntimeException( "Bug in plugin. Please report with stacktrace" );
123         }
124     }
125 
126     ArtifactResolutionResult resolveArtifact( Artifact providerArtifact )
127     {
128         return resolveArtifact( providerArtifact, null );
129     }
130 
131     private ArtifactResolutionResult resolveArtifact( Artifact providerArtifact, @Nullable Artifact excludeArtifact )
132     {
133         ArtifactResolutionRequest request = new ArtifactResolutionRequest()
134                                                     .setArtifact( providerArtifact )
135                                                     .setRemoteRepositories( remoteRepositories )
136                                                     .setLocalRepository( localRepository )
137                                                     .setResolveTransitively( true );
138         if ( excludeArtifact != null )
139         {
140             String pattern = excludeArtifact.getGroupId() + ":" + excludeArtifact.getArtifactId();
141             request.setCollectionFilter( new ExcludesArtifactFilter( singletonList( pattern ) ) );
142         }
143         return repositorySystem.resolve( request );
144     }
145 
146     @Nonnull
147     Set<Artifact> getProviderClasspath( String providerArtifactId, String providerVersion )
148     {
149         Artifact providerArtifact = artifactFactory.createDependencyArtifact( PROVIDER_GROUP_ID,
150                 providerArtifactId, createFromVersion( providerVersion ), "jar", null, SCOPE_TEST );
151 
152         ArtifactResolutionResult result = resolveArtifact( providerArtifact );
153 
154         if ( log.isDebugEnabled() )
155         {
156             for ( Artifact artifact : result.getArtifacts() )
157             {
158                 String artifactPath = artifact.getFile().getAbsolutePath();
159                 String scope = artifact.getScope();
160                 log.debug( "Adding to " + pluginName + " test classpath: " + artifactPath + " Scope: " + scope );
161             }
162         }
163 
164         return orderProviderArtifacts( result.getArtifacts() );
165     }
166 
167     Set<Artifact> addProviderToClasspath( Map<String, Artifact> pluginArtifactMap, Artifact mojoPluginArtifact,
168                                           Artifact surefireCommon, Artifact surefireApi, Artifact surefireLoggerApi )
169     {
170         Set<Artifact> providerArtifacts = new LinkedHashSet<Artifact>();
171         ArtifactResolutionResult artifactResolutionResult = resolveArtifact( mojoPluginArtifact );
172         for ( Artifact artifact : pluginArtifactMap.values() )
173         {
174             if ( !artifactResolutionResult.getArtifacts().contains( artifact ) )
175             {
176                 providerArtifacts.add( artifact );
177                 for ( Artifact dependency : resolveArtifact( artifact ).getArtifacts() )
178                 {
179                     String groupId = dependency.getGroupId();
180                     String artifactId = dependency.getArtifactId();
181                     if ( groupId.equals( surefireCommon.getGroupId() )
182                             && artifactId.equals( surefireCommon.getArtifactId() ) )
183                     {
184                         providerArtifacts.add( surefireCommon );
185                     }
186                     else if ( groupId.equals( surefireApi.getGroupId() )
187                             && artifactId.equals( surefireApi.getArtifactId() ) )
188                     {
189                         providerArtifacts.add( surefireApi );
190                     }
191                     else if ( groupId.equals( surefireLoggerApi.getGroupId() )
192                             && artifactId.equals( surefireLoggerApi.getArtifactId() ) )
193                     {
194                         providerArtifacts.add( surefireLoggerApi );
195                     }
196                 }
197             }
198         }
199         return orderProviderArtifacts( providerArtifacts );
200     }
201 
202     private static Set<Artifact> orderProviderArtifacts( Set<Artifact> providerArtifacts )
203     {
204         Set<Artifact> orderedProviderArtifacts = new LinkedHashSet<Artifact>();
205         for ( String order : PROVIDER_CLASSPATH_ORDER )
206         {
207             Iterator<Artifact> providerArtifactsIt = providerArtifacts.iterator();
208             while ( providerArtifactsIt.hasNext() )
209             {
210                 Artifact providerArtifact = providerArtifactsIt.next();
211                 if ( providerArtifact.getArtifactId().equals( order ) )
212                 {
213                     orderedProviderArtifacts.add( providerArtifact );
214                     providerArtifactsIt.remove();
215                 }
216             }
217         }
218         orderedProviderArtifacts.addAll( providerArtifacts );
219         return orderedProviderArtifacts;
220     }
221 }