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