View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.maven.repository.internal;
20  
21  import java.util.LinkedHashSet;
22  import java.util.Map;
23  import java.util.Objects;
24  import java.util.Properties;
25  import java.util.Set;
26  import javax.inject.Inject;
27  import javax.inject.Named;
28  import javax.inject.Singleton;
29  import org.apache.maven.model.DistributionManagement;
30  import org.apache.maven.model.Model;
31  import org.apache.maven.model.Relocation;
32  import org.apache.maven.model.building.ArtifactModelSource;
33  import org.apache.maven.model.building.DefaultModelBuildingRequest;
34  import org.apache.maven.model.building.ModelBuilder;
35  import org.apache.maven.model.building.ModelBuildingException;
36  import org.apache.maven.model.building.ModelBuildingRequest;
37  import org.apache.maven.model.building.ModelProblem;
38  import org.apache.maven.model.resolution.UnresolvableModelException;
39  import org.eclipse.aether.RepositoryEvent;
40  import org.eclipse.aether.RepositoryEvent.EventType;
41  import org.eclipse.aether.RepositoryException;
42  import org.eclipse.aether.RepositorySystemSession;
43  import org.eclipse.aether.RequestTrace;
44  import org.eclipse.aether.artifact.Artifact;
45  import org.eclipse.aether.impl.ArtifactDescriptorReader;
46  import org.eclipse.aether.impl.ArtifactResolver;
47  import org.eclipse.aether.impl.RemoteRepositoryManager;
48  import org.eclipse.aether.impl.RepositoryEventDispatcher;
49  import org.eclipse.aether.impl.VersionRangeResolver;
50  import org.eclipse.aether.impl.VersionResolver;
51  import org.eclipse.aether.repository.WorkspaceReader;
52  import org.eclipse.aether.repository.WorkspaceRepository;
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  import org.slf4j.Logger;
66  import org.slf4j.LoggerFactory;
67  
68  /**
69   * @author Benjamin Bentmann
70   */
71  @Named
72  @Singleton
73  public class DefaultArtifactDescriptorReader implements ArtifactDescriptorReader {
74      private static final Logger LOGGER = LoggerFactory.getLogger(DefaultArtifactDescriptorReader.class);
75  
76      private final RemoteRepositoryManager remoteRepositoryManager;
77      private final VersionResolver versionResolver;
78      private final VersionRangeResolver versionRangeResolver;
79      private final ArtifactResolver artifactResolver;
80      private final RepositoryEventDispatcher repositoryEventDispatcher;
81      private final ModelBuilder modelBuilder;
82      private final ModelCacheFactory modelCacheFactory;
83  
84      @Inject
85      public DefaultArtifactDescriptorReader(
86              RemoteRepositoryManager remoteRepositoryManager,
87              VersionResolver versionResolver,
88              VersionRangeResolver versionRangeResolver,
89              ArtifactResolver artifactResolver,
90              ModelBuilder modelBuilder,
91              RepositoryEventDispatcher repositoryEventDispatcher,
92              ModelCacheFactory modelCacheFactory) {
93          this.remoteRepositoryManager =
94                  Objects.requireNonNull(remoteRepositoryManager, "remoteRepositoryManager cannot be null");
95          this.versionResolver = Objects.requireNonNull(versionResolver, "versionResolver cannot be null");
96          this.versionRangeResolver = Objects.requireNonNull(versionRangeResolver, "versionRangeResolver cannot be null");
97          this.artifactResolver = Objects.requireNonNull(artifactResolver, "artifactResolver cannot be null");
98          this.modelBuilder = Objects.requireNonNull(modelBuilder, "modelBuilder cannot be null");
99          this.repositoryEventDispatcher =
100                 Objects.requireNonNull(repositoryEventDispatcher, "repositoryEventDispatcher cannot be null");
101         this.modelCacheFactory = Objects.requireNonNull(modelCacheFactory, "modelCacheFactory cannot be null");
102     }
103 
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 = new ArtifactDescriptorReaderDelegate();
116             }
117 
118             delegate.populateResult(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         Set<String> visited = new LinkedHashSet<>();
130         for (Artifact a = request.getArtifact(); ; ) {
131             Artifact pomArtifact = ArtifactDescriptorUtils.toPomArtifact(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             // TODO hack: don't rebuild model if it was already loaded during reactor resolution
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                 ModelBuildingRequest modelRequest = new DefaultModelBuildingRequest();
194                 modelRequest.setValidationLevel(ModelBuildingRequest.VALIDATION_LEVEL_MINIMAL);
195                 modelRequest.setProcessPlugins(false);
196                 modelRequest.setTwoPhaseBuilding(false);
197                 modelRequest.setSystemProperties(toProperties(session.getSystemProperties()));
198                 modelRequest.setUserProperties(toProperties(session.getUserProperties()));
199                 modelRequest.setModelCache(modelCacheFactory.createCache(session));
200                 modelRequest.setModelResolver(new DefaultModelResolver(
201                         session,
202                         trace.newChild(modelRequest),
203                         request.getRequestContext(),
204                         artifactResolver,
205                         versionRangeResolver,
206                         remoteRepositoryManager,
207                         request.getRepositories()));
208                 if (resolveResult.getRepository() instanceof WorkspaceRepository) {
209                     modelRequest.setPomFile(pomArtifact.getFile());
210                 } else {
211                     modelRequest.setModelSource(new ArtifactModelSource(
212                             pomArtifact.getFile(),
213                             pomArtifact.getGroupId(),
214                             pomArtifact.getArtifactId(),
215                             pomArtifact.getVersion()));
216                 }
217 
218                 model = modelBuilder.build(modelRequest).getEffectiveModel();
219             } catch (ModelBuildingException e) {
220                 for (ModelProblem problem : e.getProblems()) {
221                     if (problem.getException() instanceof UnresolvableModelException) {
222                         result.addException(problem.getException());
223                         throw new ArtifactDescriptorException(result);
224                     }
225                 }
226                 invalidDescriptor(session, trace, a, e);
227                 if ((getPolicy(session, a, request) & ArtifactDescriptorPolicy.IGNORE_INVALID) != 0) {
228                     return null;
229                 }
230                 result.addException(e);
231                 throw new ArtifactDescriptorException(result);
232             }
233 
234             Relocation relocation = getRelocation(model);
235 
236             if (relocation != null) {
237                 result.addRelocation(a);
238                 a = new RelocatedArtifact(
239                         a,
240                         relocation.getGroupId(),
241                         relocation.getArtifactId(),
242                         relocation.getVersion(),
243                         relocation.getMessage());
244                 result.setArtifact(a);
245             } else {
246                 return model;
247             }
248         }
249     }
250 
251     private Properties toProperties(Map<String, String> map) {
252         Properties props = new Properties();
253         props.putAll(map);
254         return props;
255     }
256 
257     private Relocation getRelocation(Model model) {
258         Relocation relocation = null;
259         DistributionManagement distMgmt = model.getDistributionManagement();
260         if (distMgmt != null) {
261             relocation = distMgmt.getRelocation();
262         }
263         return relocation;
264     }
265 
266     private void missingDescriptor(
267             RepositorySystemSession session, RequestTrace trace, Artifact artifact, Exception exception) {
268         RepositoryEvent.Builder event = new RepositoryEvent.Builder(session, EventType.ARTIFACT_DESCRIPTOR_MISSING);
269         event.setTrace(trace);
270         event.setArtifact(artifact);
271         event.setException(exception);
272 
273         repositoryEventDispatcher.dispatch(event.build());
274     }
275 
276     private void invalidDescriptor(
277             RepositorySystemSession session, RequestTrace trace, Artifact artifact, Exception exception) {
278         RepositoryEvent.Builder event = new RepositoryEvent.Builder(session, EventType.ARTIFACT_DESCRIPTOR_INVALID);
279         event.setTrace(trace);
280         event.setArtifact(artifact);
281         event.setException(exception);
282 
283         repositoryEventDispatcher.dispatch(event.build());
284     }
285 
286     private int getPolicy(RepositorySystemSession session, Artifact a, ArtifactDescriptorRequest request) {
287         ArtifactDescriptorPolicy policy = session.getArtifactDescriptorPolicy();
288         if (policy == null) {
289             return ArtifactDescriptorPolicy.STRICT;
290         }
291         return policy.getPolicy(session, new ArtifactDescriptorPolicyRequest(a, request.getRequestContext()));
292     }
293 }