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