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