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