View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.maven.plugins.dependency.utils;
20  
21  import javax.inject.Inject;
22  import javax.inject.Named;
23  import javax.inject.Provider;
24  import javax.inject.Singleton;
25  
26  import java.util.ArrayList;
27  import java.util.Collection;
28  import java.util.List;
29  import java.util.Objects;
30  import java.util.stream.Collectors;
31  
32  import org.apache.maven.execution.MavenSession;
33  import org.eclipse.aether.RepositorySystem;
34  import org.eclipse.aether.RepositorySystemSession;
35  import org.eclipse.aether.artifact.Artifact;
36  import org.eclipse.aether.artifact.ArtifactType;
37  import org.eclipse.aether.artifact.ArtifactTypeRegistry;
38  import org.eclipse.aether.artifact.DefaultArtifact;
39  import org.eclipse.aether.collection.CollectRequest;
40  import org.eclipse.aether.collection.CollectResult;
41  import org.eclipse.aether.collection.DependencyCollectionException;
42  import org.eclipse.aether.graph.Dependency;
43  import org.eclipse.aether.repository.RemoteRepository;
44  import org.eclipse.aether.repository.RepositoryPolicy;
45  import org.eclipse.aether.resolution.ArtifactRequest;
46  import org.eclipse.aether.resolution.ArtifactResolutionException;
47  import org.eclipse.aether.resolution.ArtifactResult;
48  import org.eclipse.aether.resolution.DependencyRequest;
49  import org.eclipse.aether.resolution.DependencyResolutionException;
50  import org.eclipse.aether.resolution.DependencyResult;
51  import org.eclipse.aether.util.graph.visitor.PreorderNodeListGenerator;
52  
53  /**
54   * Helper class for using Resolver API.
55   */
56  @Named
57  @Singleton
58  public class ResolverUtil {
59  
60      private final RepositorySystem repositorySystem;
61  
62      private final Provider<MavenSession> mavenSessionProvider;
63  
64      @Inject
65      public ResolverUtil(RepositorySystem repositorySystem, Provider<MavenSession> mavenSessionProvider) {
66          this.repositorySystem = repositorySystem;
67          this.mavenSessionProvider = mavenSessionProvider;
68      }
69  
70      /**
71       * Collects the transitive dependencies.
72       *
73       * @param root a root dependency for collections
74       * @return a resolved dependencies collections
75       */
76      public Collection<Dependency> collectDependencies(Dependency root) throws DependencyCollectionException {
77  
78          MavenSession session = mavenSessionProvider.get();
79  
80          CollectRequest request =
81                  new CollectRequest(root, session.getCurrentProject().getRemoteProjectRepositories());
82          CollectResult result = repositorySystem.collectDependencies(session.getRepositorySession(), request);
83  
84          PreorderNodeListGenerator nodeListGenerator = new PreorderNodeListGenerator();
85          result.getRoot().accept(nodeListGenerator);
86          return nodeListGenerator.getDependencies(true);
87      }
88  
89      /**
90       * Resolve given artifact
91       *
92       * @param artifact     an artifact to resolve
93       * @param repositories remote repositories list
94       * @return resolved artifact
95       * @throws ArtifactResolutionException If the artifact could not be resolved.
96       */
97      public Artifact resolveArtifact(Artifact artifact, List<RemoteRepository> repositories)
98              throws ArtifactResolutionException {
99          MavenSession session = mavenSessionProvider.get();
100         ArtifactRequest request = new ArtifactRequest(artifact, repositories, null);
101         ArtifactResult result = repositorySystem.resolveArtifact(session.getRepositorySession(), request);
102         return result.getArtifact();
103     }
104 
105     /**
106      * Resolve transitive dependencies for artifact.
107      *
108      * @param artifact     an artifact to resolve
109      * @param repositories remote repositories list
110      * @return list of transitive dependencies for artifact
111      * @throws DependencyResolutionException If the dependency tree could not be built or any dependency artifact could
112      *                                       not be resolved.
113      */
114     public List<Artifact> resolveDependencies(Artifact artifact, List<RemoteRepository> repositories)
115             throws DependencyResolutionException {
116         MavenSession session = mavenSessionProvider.get();
117 
118         CollectRequest collectRequest = new CollectRequest(new Dependency(artifact, null), repositories);
119         DependencyRequest request = new DependencyRequest(collectRequest, null);
120         DependencyResult result = repositorySystem.resolveDependencies(session.getRepositorySession(), request);
121         return result.getArtifactResults().stream()
122                 .map(ArtifactResult::getArtifact)
123                 .collect(Collectors.toList());
124     }
125 
126     /**
127      * Prepare a remote repositories list for given descriptions.
128      *
129      * @param repositories remote repositories descriptions
130      * @return a list of remote repositories
131      */
132     public List<RemoteRepository> remoteRepositories(List<String> repositories) {
133         MavenSession mavenSession = mavenSessionProvider.get();
134         List<RemoteRepository> projectRepositories =
135                 mavenSession.getCurrentProject().getRemoteProjectRepositories();
136         if (repositories == null || repositories.isEmpty()) {
137             return projectRepositories;
138         }
139 
140         List<RemoteRepository> repositoriesList =
141                 repositories.stream().map(this::prepareRemoteRepository).collect(Collectors.toList());
142         repositoriesList =
143                 repositorySystem.newResolutionRepositories(mavenSession.getRepositorySession(), repositoriesList);
144 
145         List<RemoteRepository> result = new ArrayList<>(projectRepositories);
146         result.addAll(repositoriesList);
147         return result;
148     }
149 
150     // protected for testing purpose
151     protected RemoteRepository prepareRemoteRepository(String repository) {
152         String[] items = Objects.requireNonNull(repository, "repository must be not null")
153                 .split("::");
154         String id = "temp";
155         String type = null;
156         String url;
157         switch (items.length) {
158             case 3:
159                 id = items[0];
160                 type = items[1];
161                 url = items[2];
162                 break;
163             case 2:
164                 id = items[0];
165                 url = items[1];
166                 break;
167             case 1:
168                 url = items[0];
169                 break;
170             default:
171                 throw new IllegalArgumentException("Invalid repository: " + repository);
172         }
173 
174         if (type == null || type.isEmpty()) {
175             type = "default";
176         }
177 
178         MavenSession mavenSession = mavenSessionProvider.get();
179         RepositorySystemSession repositorySession = mavenSession.getRepositorySession();
180 
181         String checksumPolicy = repositorySession.getChecksumPolicy();
182         if (checksumPolicy == null) {
183             checksumPolicy = RepositoryPolicy.CHECKSUM_POLICY_WARN;
184         }
185         String updatePolicy =
186                 mavenSession.getRequest().isUpdateSnapshots() ? RepositoryPolicy.UPDATE_POLICY_ALWAYS : null;
187         RepositoryPolicy repositoryPolicy = new RepositoryPolicy(true, updatePolicy, checksumPolicy);
188 
189         RemoteRepository.Builder builder = new RemoteRepository.Builder(id, type, url);
190         builder.setReleasePolicy(repositoryPolicy);
191         builder.setSnapshotPolicy(repositoryPolicy);
192 
193         return builder.build();
194     }
195 
196     /**
197      * Create an artifact based on configuration from Mojo.
198      *
199      * @param paramArtifact an artifact configuration
200      * @return new artifact
201      */
202     public Artifact createArtifactFromParams(ParamArtifact paramArtifact) {
203         Objects.requireNonNull(paramArtifact);
204         if (paramArtifact.getArtifact() != null) {
205             return createArtifactFromString(paramArtifact.getArtifact());
206         } else {
207             ArtifactType artifactType = getArtifactType(paramArtifact.getPackaging());
208             return new DefaultArtifact(
209                     paramArtifact.getGroupId(),
210                     paramArtifact.getArtifactId(),
211                     paramArtifact.getClassifier(),
212                     artifactType.getExtension(),
213                     paramArtifact.getVersion(),
214                     artifactType);
215         }
216     }
217 
218     private Artifact createArtifactFromString(String artifact) {
219         // groupId:artifactId:version[:packaging[:classifier]].
220         String[] items = artifact.split(":");
221         if (items.length < 3) {
222             throw new IllegalArgumentException("Invalid artifact format: " + artifact);
223         }
224 
225         ArtifactType artifactType = getArtifactType(items.length > 3 ? items[3] : null);
226         String classifier = items.length > 4 ? items[4] : null;
227 
228         return new DefaultArtifact(items[0], items[1], classifier, artifactType.getExtension(), items[2], artifactType);
229     }
230 
231     private ArtifactType getArtifactType(String packaging) {
232         ArtifactTypeRegistry artifactTypeRegistry =
233                 mavenSessionProvider.get().getRepositorySession().getArtifactTypeRegistry();
234         return artifactTypeRegistry.get(packaging != null ? packaging : "jar");
235     }
236 }