1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.repository.internal;
20
21 import javax.inject.Inject;
22 import javax.inject.Named;
23 import javax.inject.Singleton;
24
25 import java.io.FileInputStream;
26 import java.io.InputStream;
27 import java.util.ArrayList;
28 import java.util.Collections;
29 import java.util.HashMap;
30 import java.util.List;
31 import java.util.Locale;
32 import java.util.Map;
33 import java.util.Objects;
34
35 import org.apache.maven.artifact.ArtifactUtils;
36 import org.apache.maven.artifact.repository.metadata.Versioning;
37 import org.apache.maven.artifact.repository.metadata.io.xpp3.MetadataXpp3Reader;
38 import org.eclipse.aether.RepositoryEvent;
39 import org.eclipse.aether.RepositoryEvent.EventType;
40 import org.eclipse.aether.RepositorySystemSession;
41 import org.eclipse.aether.RequestTrace;
42 import org.eclipse.aether.SyncContext;
43 import org.eclipse.aether.impl.MetadataResolver;
44 import org.eclipse.aether.impl.RepositoryEventDispatcher;
45 import org.eclipse.aether.impl.VersionRangeResolver;
46 import org.eclipse.aether.metadata.DefaultMetadata;
47 import org.eclipse.aether.metadata.Metadata;
48 import org.eclipse.aether.repository.ArtifactRepository;
49 import org.eclipse.aether.repository.RemoteRepository;
50 import org.eclipse.aether.repository.WorkspaceReader;
51 import org.eclipse.aether.resolution.MetadataRequest;
52 import org.eclipse.aether.resolution.MetadataResult;
53 import org.eclipse.aether.resolution.VersionRangeRequest;
54 import org.eclipse.aether.resolution.VersionRangeResolutionException;
55 import org.eclipse.aether.resolution.VersionRangeResult;
56 import org.eclipse.aether.spi.locator.Service;
57 import org.eclipse.aether.spi.locator.ServiceLocator;
58 import org.eclipse.aether.spi.synccontext.SyncContextFactory;
59 import org.eclipse.aether.util.ConfigUtils;
60 import org.eclipse.aether.util.version.GenericVersionScheme;
61 import org.eclipse.aether.version.InvalidVersionSpecificationException;
62 import org.eclipse.aether.version.Version;
63 import org.eclipse.aether.version.VersionConstraint;
64 import org.eclipse.aether.version.VersionRange;
65 import org.eclipse.aether.version.VersionScheme;
66
67
68
69
70 @Named
71 @Singleton
72 public class DefaultVersionRangeResolver implements VersionRangeResolver, Service {
73
74
75
76
77
78
79
80
81
82 public static final String MAVEN_VERSION_RANGE_RESOLUTION_NATURE = "maven.versionRangeResolutionNature";
83
84 private static final String MAVEN_METADATA_XML = "maven-metadata.xml";
85
86 private MetadataResolver metadataResolver;
87
88 private SyncContextFactory syncContextFactory;
89
90 private RepositoryEventDispatcher repositoryEventDispatcher;
91
92 @Deprecated
93 public DefaultVersionRangeResolver() {
94
95 }
96
97 @Inject
98 public DefaultVersionRangeResolver(
99 MetadataResolver metadataResolver,
100 SyncContextFactory syncContextFactory,
101 RepositoryEventDispatcher repositoryEventDispatcher) {
102 setMetadataResolver(metadataResolver);
103 setSyncContextFactory(syncContextFactory);
104 setRepositoryEventDispatcher(repositoryEventDispatcher);
105 }
106
107 @Deprecated
108 public void initService(ServiceLocator locator) {
109 setMetadataResolver(locator.getService(MetadataResolver.class));
110 setSyncContextFactory(locator.getService(SyncContextFactory.class));
111 setRepositoryEventDispatcher(locator.getService(RepositoryEventDispatcher.class));
112 }
113
114 public DefaultVersionRangeResolver setMetadataResolver(MetadataResolver metadataResolver) {
115 this.metadataResolver = Objects.requireNonNull(metadataResolver, "metadataResolver cannot be null");
116 return this;
117 }
118
119 public DefaultVersionRangeResolver setSyncContextFactory(SyncContextFactory syncContextFactory) {
120 this.syncContextFactory = Objects.requireNonNull(syncContextFactory, "syncContextFactory cannot be null");
121 return this;
122 }
123
124 public DefaultVersionRangeResolver setRepositoryEventDispatcher(
125 RepositoryEventDispatcher repositoryEventDispatcher) {
126 this.repositoryEventDispatcher =
127 Objects.requireNonNull(repositoryEventDispatcher, "repositoryEventDispatcher cannot be null");
128 return this;
129 }
130
131 @Override
132 public VersionRangeResult resolveVersionRange(RepositorySystemSession session, VersionRangeRequest request)
133 throws VersionRangeResolutionException {
134 VersionRangeResult result = new VersionRangeResult(request);
135
136 VersionScheme versionScheme = new GenericVersionScheme();
137
138 VersionConstraint versionConstraint;
139 try {
140 versionConstraint =
141 versionScheme.parseVersionConstraint(request.getArtifact().getVersion());
142 } catch (InvalidVersionSpecificationException e) {
143 result.addException(e);
144 throw new VersionRangeResolutionException(result);
145 }
146
147 result.setVersionConstraint(versionConstraint);
148
149 if (versionConstraint.getRange() == null) {
150 result.addVersion(versionConstraint.getVersion());
151 } else {
152 VersionRange.Bound lowerBound = versionConstraint.getRange().getLowerBound();
153 VersionRange.Bound upperBound = versionConstraint.getRange().getUpperBound();
154 if (lowerBound != null && lowerBound.equals(upperBound)) {
155 result.addVersion(lowerBound.getVersion());
156 } else {
157 Metadata.Nature wantedNature;
158 String natureString = ConfigUtils.getString(
159 session, Metadata.Nature.RELEASE_OR_SNAPSHOT.name(), MAVEN_VERSION_RANGE_RESOLUTION_NATURE);
160 if ("auto".equals(natureString)) {
161 org.eclipse.aether.artifact.Artifact lowerArtifact = lowerBound != null
162 ? request.getArtifact()
163 .setVersion(lowerBound.getVersion().toString())
164 : null;
165 org.eclipse.aether.artifact.Artifact upperArtifact = upperBound != null
166 ? request.getArtifact()
167 .setVersion(upperBound.getVersion().toString())
168 : null;
169
170 if (lowerArtifact != null && lowerArtifact.isSnapshot()
171 || upperArtifact != null && upperArtifact.isSnapshot()) {
172 wantedNature = Metadata.Nature.RELEASE_OR_SNAPSHOT;
173 } else {
174 wantedNature = Metadata.Nature.RELEASE;
175 }
176 } else {
177 wantedNature = Metadata.Nature.valueOf(natureString.toUpperCase(Locale.ROOT));
178 }
179
180 Map<String, ArtifactRepository> versionIndex = getVersions(session, result, request, wantedNature);
181
182 List<Version> versions = new ArrayList<>();
183 for (Map.Entry<String, ArtifactRepository> v : versionIndex.entrySet()) {
184 try {
185 Version ver = versionScheme.parseVersion(v.getKey());
186 if (versionConstraint.containsVersion(ver)) {
187 versions.add(ver);
188 result.setRepository(ver, v.getValue());
189 }
190 } catch (InvalidVersionSpecificationException e) {
191 result.addException(e);
192 }
193 }
194
195 Collections.sort(versions);
196 result.setVersions(versions);
197 }
198 }
199
200 return result;
201 }
202
203 private Map<String, ArtifactRepository> getVersions(
204 RepositorySystemSession session,
205 VersionRangeResult result,
206 VersionRangeRequest request,
207 Metadata.Nature wantedNature) {
208 RequestTrace trace = RequestTrace.newChild(request.getTrace(), request);
209
210 Map<String, ArtifactRepository> versionIndex = new HashMap<>();
211
212 Metadata metadata = new DefaultMetadata(
213 request.getArtifact().getGroupId(),
214 request.getArtifact().getArtifactId(),
215 MAVEN_METADATA_XML,
216 wantedNature);
217
218 List<MetadataRequest> metadataRequests =
219 new ArrayList<>(request.getRepositories().size());
220
221 metadataRequests.add(new MetadataRequest(metadata, null, request.getRequestContext()));
222
223 for (RemoteRepository repository : request.getRepositories()) {
224 MetadataRequest metadataRequest = new MetadataRequest(metadata, repository, request.getRequestContext());
225 metadataRequest.setDeleteLocalCopyIfMissing(true);
226 metadataRequest.setTrace(trace);
227 metadataRequests.add(metadataRequest);
228 }
229
230 List<MetadataResult> metadataResults = metadataResolver.resolveMetadata(session, metadataRequests);
231
232 WorkspaceReader workspace = session.getWorkspaceReader();
233 if (workspace != null) {
234 List<String> versions = workspace.findVersions(request.getArtifact());
235 for (String version : versions) {
236 versionIndex.put(version, workspace.getRepository());
237 }
238 }
239
240 for (MetadataResult metadataResult : metadataResults) {
241 result.addException(metadataResult.getException());
242
243 ArtifactRepository repository = metadataResult.getRequest().getRepository();
244 if (repository == null) {
245 repository = session.getLocalRepository();
246 }
247
248 Versioning versioning = readVersions(session, trace, metadataResult.getMetadata(), repository, result);
249
250 versioning = filterVersionsByRepositoryType(
251 versioning, metadataResult.getRequest().getRepository());
252
253 for (String version : versioning.getVersions()) {
254 if (!versionIndex.containsKey(version)) {
255 versionIndex.put(version, repository);
256 }
257 }
258 }
259
260 return versionIndex;
261 }
262
263 private Versioning readVersions(
264 RepositorySystemSession session,
265 RequestTrace trace,
266 Metadata metadata,
267 ArtifactRepository repository,
268 VersionRangeResult result) {
269 Versioning versioning = null;
270 try {
271 if (metadata != null) {
272 try (SyncContext syncContext = syncContextFactory.newInstance(session, true)) {
273 syncContext.acquire(null, Collections.singleton(metadata));
274
275 if (metadata.getFile() != null && metadata.getFile().exists()) {
276 try (InputStream in = new FileInputStream(metadata.getFile())) {
277 versioning =
278 new MetadataXpp3Reader().read(in, false).getVersioning();
279 }
280 }
281 }
282 }
283 } catch (Exception e) {
284 invalidMetadata(session, trace, metadata, repository, e);
285 result.addException(e);
286 }
287
288 return (versioning != null) ? versioning : new Versioning();
289 }
290
291 private Versioning filterVersionsByRepositoryType(Versioning versioning, RemoteRepository remoteRepository) {
292 if (remoteRepository == null) {
293 return versioning;
294 }
295
296 Versioning filteredVersions = versioning.clone();
297
298 for (String version : versioning.getVersions()) {
299 if (!remoteRepository.getPolicy(ArtifactUtils.isSnapshot(version)).isEnabled()) {
300 filteredVersions.removeVersion(version);
301 }
302 }
303
304 return filteredVersions;
305 }
306
307 private void invalidMetadata(
308 RepositorySystemSession session,
309 RequestTrace trace,
310 Metadata metadata,
311 ArtifactRepository repository,
312 Exception exception) {
313 RepositoryEvent.Builder event = new RepositoryEvent.Builder(session, EventType.METADATA_INVALID);
314 event.setTrace(trace);
315 event.setMetadata(metadata);
316 event.setException(exception);
317 event.setRepository(repository);
318
319 repositoryEventDispatcher.dispatch(event.build());
320 }
321 }