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.repository.internal;
20  
21  import java.util.ArrayList;
22  import java.util.Collections;
23  import java.util.HashSet;
24  import java.util.Iterator;
25  import java.util.List;
26  import java.util.Set;
27  import java.util.concurrent.atomic.AtomicReference;
28  
29  import org.apache.maven.api.model.Dependency;
30  import org.apache.maven.api.model.Parent;
31  import org.apache.maven.api.model.Repository;
32  import org.apache.maven.model.building.ArtifactModelSource;
33  import org.apache.maven.model.building.ModelSource;
34  import org.apache.maven.model.resolution.InvalidRepositoryException;
35  import org.apache.maven.model.resolution.ModelResolver;
36  import org.apache.maven.model.resolution.UnresolvableModelException;
37  import org.eclipse.aether.RepositorySystemSession;
38  import org.eclipse.aether.RequestTrace;
39  import org.eclipse.aether.artifact.Artifact;
40  import org.eclipse.aether.artifact.DefaultArtifact;
41  import org.eclipse.aether.impl.ArtifactResolver;
42  import org.eclipse.aether.impl.RemoteRepositoryManager;
43  import org.eclipse.aether.impl.VersionRangeResolver;
44  import org.eclipse.aether.repository.RemoteRepository;
45  import org.eclipse.aether.resolution.ArtifactRequest;
46  import org.eclipse.aether.resolution.ArtifactResolutionException;
47  import org.eclipse.aether.resolution.VersionRangeRequest;
48  import org.eclipse.aether.resolution.VersionRangeResolutionException;
49  import org.eclipse.aether.resolution.VersionRangeResult;
50  
51  /**
52   * A model resolver to assist building of dependency POMs. This resolver gives priority to those repositories that have
53   * been initially specified and repositories discovered in dependency POMs are recessively merged into the search chain.
54   *
55   * @see DefaultArtifactDescriptorReader
56   * @deprecated since 4.0.0, use {@code maven-api-impl} jar instead
57   */
58  @Deprecated(since = "4.0.0")
59  class DefaultModelResolver implements ModelResolver {
60  
61      private final RepositorySystemSession session;
62  
63      private final RequestTrace trace;
64  
65      private final String context;
66  
67      private List<RemoteRepository> repositories;
68  
69      private final List<RemoteRepository> externalRepositories;
70  
71      private final ArtifactResolver resolver;
72  
73      private final VersionRangeResolver versionRangeResolver;
74  
75      private final RemoteRepositoryManager remoteRepositoryManager;
76  
77      private final Set<String> repositoryIds;
78  
79      DefaultModelResolver(
80              RepositorySystemSession session,
81              RequestTrace trace,
82              String context,
83              ArtifactResolver resolver,
84              VersionRangeResolver versionRangeResolver,
85              RemoteRepositoryManager remoteRepositoryManager,
86              List<RemoteRepository> repositories) {
87          this.session = session;
88          this.trace = trace;
89          this.context = context;
90          this.resolver = resolver;
91          this.versionRangeResolver = versionRangeResolver;
92          this.remoteRepositoryManager = remoteRepositoryManager;
93          this.repositories = repositories;
94          this.externalRepositories = Collections.unmodifiableList(new ArrayList<>(repositories));
95  
96          this.repositoryIds = new HashSet<>();
97      }
98  
99      private DefaultModelResolver(DefaultModelResolver original) {
100         this.session = original.session;
101         this.trace = original.trace;
102         this.context = original.context;
103         this.resolver = original.resolver;
104         this.versionRangeResolver = original.versionRangeResolver;
105         this.remoteRepositoryManager = original.remoteRepositoryManager;
106         this.repositories = new ArrayList<>(original.repositories);
107         this.externalRepositories = original.externalRepositories;
108         this.repositoryIds = new HashSet<>(original.repositoryIds);
109     }
110 
111     @Override
112     public void addRepository(Repository repository) throws InvalidRepositoryException {
113         addRepository(repository, false);
114     }
115 
116     @Override
117     public void addRepository(final Repository repository, boolean replace) throws InvalidRepositoryException {
118         if (session.isIgnoreArtifactDescriptorRepositories()) {
119             return;
120         }
121 
122         if (!repositoryIds.add(repository.getId())) {
123             if (!replace) {
124                 return;
125             }
126 
127             removeMatchingRepository(repositories, repository.getId());
128         }
129 
130         List<RemoteRepository> newRepositories = Collections.singletonList(
131                 ArtifactDescriptorUtils.toRemoteRepository(new org.apache.maven.model.Repository(repository)));
132 
133         this.repositories = remoteRepositoryManager.aggregateRepositories(session, repositories, newRepositories, true);
134     }
135 
136     private static void removeMatchingRepository(Iterable<RemoteRepository> repositories, final String id) {
137         Iterator<RemoteRepository> iterator = repositories.iterator();
138         while (iterator.hasNext()) {
139             RemoteRepository remoteRepository = iterator.next();
140             if (remoteRepository.getId().equals(id)) {
141                 iterator.remove();
142             }
143         }
144     }
145 
146     @Override
147     public ModelResolver newCopy() {
148         return new DefaultModelResolver(this);
149     }
150 
151     @Override
152     public ModelSource resolveModel(String groupId, String artifactId, String version)
153             throws UnresolvableModelException {
154         Artifact pomArtifact = new DefaultArtifact(groupId, artifactId, "", "pom", version);
155 
156         try {
157             ArtifactRequest request = new ArtifactRequest(pomArtifact, repositories, context);
158             request.setTrace(trace);
159             pomArtifact = resolver.resolveArtifact(session, request).getArtifact();
160         } catch (ArtifactResolutionException e) {
161             throw new UnresolvableModelException(e.getMessage(), groupId, artifactId, version, e);
162         }
163 
164         return new ArtifactModelSource(pomArtifact.getPath(), groupId, artifactId, version);
165     }
166 
167     @Override
168     public ModelSource resolveModel(final Parent parent, final AtomicReference<Parent> modified)
169             throws UnresolvableModelException {
170         try {
171             final Artifact artifact =
172                     new DefaultArtifact(parent.getGroupId(), parent.getArtifactId(), "", "pom", parent.getVersion());
173 
174             final VersionRangeRequest versionRangeRequest = new VersionRangeRequest(artifact, repositories, context);
175             versionRangeRequest.setTrace(trace);
176 
177             final VersionRangeResult versionRangeResult =
178                     versionRangeResolver.resolveVersionRange(session, versionRangeRequest);
179 
180             if (versionRangeResult.getHighestVersion() == null) {
181                 throw new UnresolvableModelException(
182                         String.format(
183                                 "No versions matched the requested parent version range '%s'", parent.getVersion()),
184                         parent.getGroupId(),
185                         parent.getArtifactId(),
186                         parent.getVersion());
187             }
188 
189             if (versionRangeResult.getVersionConstraint() != null
190                     && versionRangeResult.getVersionConstraint().getRange() != null
191                     && versionRangeResult.getVersionConstraint().getRange().getUpperBound() == null) {
192                 // Message below is checked for in the MNG-2199 core IT.
193                 throw new UnresolvableModelException(
194                         String.format(
195                                 "The requested parent version range '%s' does not specify an upper bound",
196                                 parent.getVersion()),
197                         parent.getGroupId(),
198                         parent.getArtifactId(),
199                         parent.getVersion());
200             }
201 
202             String newVersion = versionRangeResult.getHighestVersion().toString();
203             if (!parent.getVersion().equals(newVersion)) {
204                 modified.set(parent.withVersion(newVersion));
205             }
206 
207             return resolveModel(parent.getGroupId(), parent.getArtifactId(), newVersion);
208         } catch (final VersionRangeResolutionException e) {
209             throw new UnresolvableModelException(
210                     e.getMessage(), parent.getGroupId(), parent.getArtifactId(), parent.getVersion(), e);
211         }
212     }
213 
214     @Override
215     public ModelSource resolveModel(final Dependency dependency, AtomicReference<Dependency> modified)
216             throws UnresolvableModelException {
217         try {
218             final Artifact artifact = new DefaultArtifact(
219                     dependency.getGroupId(), dependency.getArtifactId(), "", "pom", dependency.getVersion());
220 
221             final VersionRangeRequest versionRangeRequest = new VersionRangeRequest(artifact, repositories, context);
222             versionRangeRequest.setTrace(trace);
223 
224             final VersionRangeResult versionRangeResult =
225                     versionRangeResolver.resolveVersionRange(session, versionRangeRequest);
226 
227             if (versionRangeResult.getHighestVersion() == null) {
228                 throw new UnresolvableModelException(
229                         String.format(
230                                 "No versions matched the requested dependency version range '%s'",
231                                 dependency.getVersion()),
232                         dependency.getGroupId(),
233                         dependency.getArtifactId(),
234                         dependency.getVersion());
235             }
236 
237             if (versionRangeResult.getVersionConstraint() != null
238                     && versionRangeResult.getVersionConstraint().getRange() != null
239                     && versionRangeResult.getVersionConstraint().getRange().getUpperBound() == null) {
240                 // Message below is checked for in the MNG-4463 core IT.
241                 throw new UnresolvableModelException(
242                         String.format(
243                                 "The requested dependency version range '%s' does not specify an upper bound",
244                                 dependency.getVersion()),
245                         dependency.getGroupId(),
246                         dependency.getArtifactId(),
247                         dependency.getVersion());
248             }
249 
250             String newVersion = versionRangeResult.getHighestVersion().toString();
251             if (!dependency.getVersion().equals(newVersion)) {
252                 modified.set(dependency.withVersion(newVersion));
253             }
254 
255             return resolveModel(dependency.getGroupId(), dependency.getArtifactId(), newVersion);
256         } catch (VersionRangeResolutionException e) {
257             throw new UnresolvableModelException(
258                     e.getMessage(), dependency.getGroupId(), dependency.getArtifactId(), dependency.getVersion(), e);
259         }
260     }
261 
262     @Override
263     public ModelSource resolveModel(org.apache.maven.model.Parent parent) throws UnresolvableModelException {
264         AtomicReference<org.apache.maven.api.model.Parent> resolvedParent = new AtomicReference<>();
265         ModelSource result = resolveModel(parent.getDelegate(), resolvedParent);
266         if (resolvedParent.get() != null) {
267             parent.setVersion(resolvedParent.get().getVersion());
268         }
269         return result;
270     }
271 
272     @Override
273     public ModelSource resolveModel(org.apache.maven.model.Dependency dependency) throws UnresolvableModelException {
274         AtomicReference<org.apache.maven.api.model.Dependency> resolvedDependency = new AtomicReference<>();
275         ModelSource result = resolveModel(dependency.getDelegate(), resolvedDependency);
276         if (resolvedDependency.get() != null) {
277             dependency.setVersion(resolvedDependency.get().getVersion());
278         }
279         return result;
280     }
281 
282     @Override
283     public void addRepository(org.apache.maven.model.Repository repository) throws InvalidRepositoryException {
284         addRepository(repository.getDelegate());
285     }
286 
287     @Override
288     public void addRepository(org.apache.maven.model.Repository repository, boolean replace)
289             throws InvalidRepositoryException {
290         addRepository(repository.getDelegate(), replace);
291     }
292 }