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