1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.internal.impl.resolver;
20
21 import java.util.HashMap;
22 import java.util.LinkedHashSet;
23 import java.util.Map;
24 import java.util.Objects;
25
26 import org.apache.maven.api.Session;
27 import org.apache.maven.api.di.Inject;
28 import org.apache.maven.api.di.Named;
29 import org.apache.maven.api.di.Singleton;
30 import org.apache.maven.api.model.Model;
31 import org.apache.maven.api.services.ModelBuilder;
32 import org.apache.maven.api.services.ModelBuilderException;
33 import org.apache.maven.api.services.ModelBuilderRequest;
34 import org.apache.maven.api.services.ModelProblem;
35 import org.apache.maven.api.services.ModelRepositoryHolder;
36 import org.apache.maven.api.services.ModelResolver;
37 import org.apache.maven.api.services.ModelResolverException;
38 import org.apache.maven.api.services.ModelSource;
39 import org.apache.maven.internal.impl.InternalSession;
40 import org.eclipse.aether.RepositoryEvent;
41 import org.eclipse.aether.RepositoryEvent.EventType;
42 import org.eclipse.aether.RepositoryException;
43 import org.eclipse.aether.RepositorySystemSession;
44 import org.eclipse.aether.RequestTrace;
45 import org.eclipse.aether.artifact.Artifact;
46 import org.eclipse.aether.impl.ArtifactDescriptorReader;
47 import org.eclipse.aether.impl.ArtifactResolver;
48 import org.eclipse.aether.impl.RemoteRepositoryManager;
49 import org.eclipse.aether.impl.RepositoryEventDispatcher;
50 import org.eclipse.aether.impl.VersionRangeResolver;
51 import org.eclipse.aether.impl.VersionResolver;
52 import org.eclipse.aether.repository.WorkspaceReader;
53 import org.eclipse.aether.resolution.ArtifactDescriptorException;
54 import org.eclipse.aether.resolution.ArtifactDescriptorPolicy;
55 import org.eclipse.aether.resolution.ArtifactDescriptorPolicyRequest;
56 import org.eclipse.aether.resolution.ArtifactDescriptorRequest;
57 import org.eclipse.aether.resolution.ArtifactDescriptorResult;
58 import org.eclipse.aether.resolution.ArtifactRequest;
59 import org.eclipse.aether.resolution.ArtifactResolutionException;
60 import org.eclipse.aether.resolution.ArtifactResult;
61 import org.eclipse.aether.resolution.VersionRequest;
62 import org.eclipse.aether.resolution.VersionResolutionException;
63 import org.eclipse.aether.resolution.VersionResult;
64 import org.eclipse.aether.transfer.ArtifactNotFoundException;
65
66
67
68
69 @Named
70 @Singleton
71 public class DefaultArtifactDescriptorReader implements ArtifactDescriptorReader {
72 private final RemoteRepositoryManager remoteRepositoryManager;
73 private final VersionResolver versionResolver;
74 private final VersionRangeResolver versionRangeResolver;
75 private final ArtifactResolver artifactResolver;
76 private final RepositoryEventDispatcher repositoryEventDispatcher;
77 private final ModelBuilder modelBuilder;
78 private final Map<String, MavenArtifactRelocationSource> artifactRelocationSources;
79 private final ArtifactDescriptorReaderDelegate delegate;
80
81 @Inject
82 public DefaultArtifactDescriptorReader(
83 RemoteRepositoryManager remoteRepositoryManager,
84 VersionResolver versionResolver,
85 VersionRangeResolver versionRangeResolver,
86 ArtifactResolver artifactResolver,
87 ModelBuilder modelBuilder,
88 RepositoryEventDispatcher repositoryEventDispatcher,
89 Map<String, MavenArtifactRelocationSource> artifactRelocationSources) {
90 this.remoteRepositoryManager =
91 Objects.requireNonNull(remoteRepositoryManager, "remoteRepositoryManager cannot be null");
92 this.versionResolver = Objects.requireNonNull(versionResolver, "versionResolver cannot be null");
93 this.versionRangeResolver = Objects.requireNonNull(versionRangeResolver, "versionRangeResolver cannot be null");
94 this.artifactResolver = Objects.requireNonNull(artifactResolver, "artifactResolver cannot be null");
95 this.modelBuilder = Objects.requireNonNull(modelBuilder, "modelBuilder cannot be null");
96 this.repositoryEventDispatcher =
97 Objects.requireNonNull(repositoryEventDispatcher, "repositoryEventDispatcher cannot be null");
98 this.artifactRelocationSources =
99 Objects.requireNonNull(artifactRelocationSources, "artifactRelocationSources cannot be null");
100 this.delegate = new ArtifactDescriptorReaderDelegate();
101 }
102
103 @Override
104 public ArtifactDescriptorResult readArtifactDescriptor(
105 RepositorySystemSession session, ArtifactDescriptorRequest request) throws ArtifactDescriptorException {
106 ArtifactDescriptorResult result = new ArtifactDescriptorResult(request);
107
108 Model model = loadPom(session, request, result);
109 if (model != null) {
110 Map<String, Object> config = session.getConfigProperties();
111 ArtifactDescriptorReaderDelegate delegate =
112 (ArtifactDescriptorReaderDelegate) config.get(ArtifactDescriptorReaderDelegate.class.getName());
113
114 if (delegate == null) {
115 delegate = this.delegate;
116 }
117
118 delegate.populateResult(InternalSession.from(session), result, model);
119 }
120
121 return result;
122 }
123
124 private Model loadPom(
125 RepositorySystemSession session, ArtifactDescriptorRequest request, ArtifactDescriptorResult result)
126 throws ArtifactDescriptorException {
127 RequestTrace trace = RequestTrace.newChild(request.getTrace(), request);
128
129 LinkedHashSet<String> visited = new LinkedHashSet<>();
130 for (Artifact a = request.getArtifact(); ; ) {
131 Artifact pomArtifact = ArtifactDescriptorUtils.toPomArtifactUnconditionally(a);
132 try {
133 VersionRequest versionRequest =
134 new VersionRequest(a, request.getRepositories(), request.getRequestContext());
135 versionRequest.setTrace(trace);
136 VersionResult versionResult = versionResolver.resolveVersion(session, versionRequest);
137
138 a = a.setVersion(versionResult.getVersion());
139
140 versionRequest =
141 new VersionRequest(pomArtifact, request.getRepositories(), request.getRequestContext());
142 versionRequest.setTrace(trace);
143 versionResult = versionResolver.resolveVersion(session, versionRequest);
144
145 pomArtifact = pomArtifact.setVersion(versionResult.getVersion());
146 } catch (VersionResolutionException e) {
147 result.addException(e);
148 throw new ArtifactDescriptorException(result);
149 }
150
151 if (!visited.add(a.getGroupId() + ':' + a.getArtifactId() + ':' + a.getBaseVersion())) {
152 RepositoryException exception =
153 new RepositoryException("Artifact relocations form a cycle: " + visited);
154 invalidDescriptor(session, trace, a, exception);
155 if ((getPolicy(session, a, request) & ArtifactDescriptorPolicy.IGNORE_INVALID) != 0) {
156 return null;
157 }
158 result.addException(exception);
159 throw new ArtifactDescriptorException(result);
160 }
161
162 ArtifactResult resolveResult;
163 try {
164 ArtifactRequest resolveRequest =
165 new ArtifactRequest(pomArtifact, request.getRepositories(), request.getRequestContext());
166 resolveRequest.setTrace(trace);
167 resolveResult = artifactResolver.resolveArtifact(session, resolveRequest);
168 pomArtifact = resolveResult.getArtifact();
169 result.setRepository(resolveResult.getRepository());
170 } catch (ArtifactResolutionException e) {
171 if (e.getCause() instanceof ArtifactNotFoundException) {
172 missingDescriptor(session, trace, a, (Exception) e.getCause());
173 if ((getPolicy(session, a, request) & ArtifactDescriptorPolicy.IGNORE_MISSING) != 0) {
174 return null;
175 }
176 }
177 result.addException(e);
178 throw new ArtifactDescriptorException(result);
179 }
180
181 Model model;
182
183
184 final WorkspaceReader workspace = session.getWorkspaceReader();
185 if (workspace instanceof MavenWorkspaceReader) {
186 model = ((MavenWorkspaceReader) workspace).findModel(pomArtifact);
187 if (model != null) {
188 return model;
189 }
190 }
191
192 try {
193 InternalSession iSession = InternalSession.from(session);
194 Session iSessionWithRepos = iSession.withRemoteRepositories(request.getRepositories().stream()
195 .map(iSession::getRemoteRepository)
196 .toList());
197 String gav =
198 pomArtifact.getGroupId() + ":" + pomArtifact.getArtifactId() + ":" + pomArtifact.getVersion();
199 ModelResolver modelResolver = new DefaultModelResolver();
200 ModelRepositoryHolder modelRepositoryHolder = new DefaultModelRepositoryHolder(
201 iSessionWithRepos,
202 DefaultModelRepositoryHolder.RepositoryMerging.REQUEST_DOMINANT,
203 iSessionWithRepos.getRemoteRepositories());
204 ModelBuilderRequest modelRequest = ModelBuilderRequest.builder()
205 .session(iSessionWithRepos)
206 .projectBuild(false)
207 .processPlugins(false)
208 .twoPhaseBuilding(false)
209 .source(ModelSource.fromPath(pomArtifact.getPath(), gav))
210
211
212 .systemProperties(toProperties(session.getUserProperties(), session.getSystemProperties()))
213 .userProperties(Map.of())
214 .modelResolver(modelResolver)
215 .modelRepositoryHolder(modelRepositoryHolder)
216 .modelCache(DefaultModelCache.newInstance(session, false))
217 .build();
218
219 model = modelBuilder.build(modelRequest).getEffectiveModel();
220 } catch (ModelBuilderException e) {
221 for (ModelProblem problem : e.getResult().getProblems()) {
222 if (problem.getException() instanceof ModelResolverException) {
223 result.addException(problem.getException());
224 throw new ArtifactDescriptorException(result);
225 }
226 }
227 invalidDescriptor(session, trace, a, e);
228 if ((getPolicy(session, a, request) & ArtifactDescriptorPolicy.IGNORE_INVALID) != 0) {
229 return null;
230 }
231 result.addException(e);
232 throw new ArtifactDescriptorException(result);
233 }
234
235 Artifact relocatedArtifact = getRelocation(session, result, model);
236 if (relocatedArtifact != null) {
237 if (withinSameGav(relocatedArtifact, a)) {
238 result.setArtifact(relocatedArtifact);
239 return model;
240 } else {
241 result.addRelocation(a);
242 a = relocatedArtifact;
243 result.setArtifact(a);
244 }
245 } else {
246 return model;
247 }
248 }
249 }
250
251 private boolean withinSameGav(Artifact a1, Artifact a2) {
252 return Objects.equals(a1.getGroupId(), a2.getGroupId())
253 && Objects.equals(a1.getArtifactId(), a2.getArtifactId())
254 && Objects.equals(a1.getVersion(), a2.getVersion());
255 }
256
257 private Map<String, String> toProperties(Map<String, String> dominant, Map<String, String> recessive) {
258 Map<String, String> props = new HashMap<>();
259 if (recessive != null) {
260 props.putAll(recessive);
261 }
262 if (dominant != null) {
263 props.putAll(dominant);
264 }
265 return props;
266 }
267
268 private Artifact getRelocation(
269 RepositorySystemSession session, ArtifactDescriptorResult artifactDescriptorResult, Model model)
270 throws ArtifactDescriptorException {
271 Artifact result = null;
272 for (MavenArtifactRelocationSource source : artifactRelocationSources.values()) {
273 result = source.relocatedTarget(session, artifactDescriptorResult, model);
274 if (result != null) {
275 break;
276 }
277 }
278 return result;
279 }
280
281 private void missingDescriptor(
282 RepositorySystemSession session, RequestTrace trace, Artifact artifact, Exception exception) {
283 RepositoryEvent.Builder event = new RepositoryEvent.Builder(session, EventType.ARTIFACT_DESCRIPTOR_MISSING);
284 event.setTrace(trace);
285 event.setArtifact(artifact);
286 event.setException(exception);
287
288 repositoryEventDispatcher.dispatch(event.build());
289 }
290
291 private void invalidDescriptor(
292 RepositorySystemSession session, RequestTrace trace, Artifact artifact, Exception exception) {
293 RepositoryEvent.Builder event = new RepositoryEvent.Builder(session, EventType.ARTIFACT_DESCRIPTOR_INVALID);
294 event.setTrace(trace);
295 event.setArtifact(artifact);
296 event.setException(exception);
297
298 repositoryEventDispatcher.dispatch(event.build());
299 }
300
301 private int getPolicy(RepositorySystemSession session, Artifact a, ArtifactDescriptorRequest request) {
302 ArtifactDescriptorPolicy policy = session.getArtifactDescriptorPolicy();
303 if (policy == null) {
304 return ArtifactDescriptorPolicy.STRICT;
305 }
306 return policy.getPolicy(session, new ArtifactDescriptorPolicyRequest(a, request.getRequestContext()));
307 }
308 }