View Javadoc
1   package org.apache.maven.repository.internal;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.util.LinkedHashSet;
23  import java.util.Map;
24  import java.util.Objects;
25  import java.util.Properties;
26  import java.util.Set;
27  
28  import javax.inject.Inject;
29  import javax.inject.Named;
30  import javax.inject.Singleton;
31  
32  import org.apache.maven.model.DistributionManagement;
33  import org.apache.maven.model.Model;
34  import org.apache.maven.model.Relocation;
35  import org.apache.maven.model.building.DefaultModelBuilderFactory;
36  import org.apache.maven.model.building.DefaultModelBuildingRequest;
37  import org.apache.maven.model.building.FileModelSource;
38  import org.apache.maven.model.building.ModelBuilder;
39  import org.apache.maven.model.building.ModelBuildingException;
40  import org.apache.maven.model.building.ModelBuildingRequest;
41  import org.apache.maven.model.building.ModelProblem;
42  import org.apache.maven.model.resolution.UnresolvableModelException;
43  import org.eclipse.aether.RepositoryEvent;
44  import org.eclipse.aether.RepositoryEvent.EventType;
45  import org.eclipse.aether.RepositoryException;
46  import org.eclipse.aether.RepositorySystemSession;
47  import org.eclipse.aether.RequestTrace;
48  import org.eclipse.aether.artifact.Artifact;
49  import org.eclipse.aether.impl.ArtifactDescriptorReader;
50  import org.eclipse.aether.impl.ArtifactResolver;
51  import org.eclipse.aether.impl.RemoteRepositoryManager;
52  import org.eclipse.aether.impl.RepositoryEventDispatcher;
53  import org.eclipse.aether.impl.VersionRangeResolver;
54  import org.eclipse.aether.impl.VersionResolver;
55  import org.eclipse.aether.repository.WorkspaceReader;
56  import org.eclipse.aether.repository.WorkspaceRepository;
57  import org.eclipse.aether.resolution.ArtifactDescriptorException;
58  import org.eclipse.aether.resolution.ArtifactDescriptorPolicy;
59  import org.eclipse.aether.resolution.ArtifactDescriptorPolicyRequest;
60  import org.eclipse.aether.resolution.ArtifactDescriptorRequest;
61  import org.eclipse.aether.resolution.ArtifactDescriptorResult;
62  import org.eclipse.aether.resolution.ArtifactRequest;
63  import org.eclipse.aether.resolution.ArtifactResolutionException;
64  import org.eclipse.aether.resolution.ArtifactResult;
65  import org.eclipse.aether.resolution.VersionRequest;
66  import org.eclipse.aether.resolution.VersionResolutionException;
67  import org.eclipse.aether.resolution.VersionResult;
68  import org.eclipse.aether.spi.locator.Service;
69  import org.eclipse.aether.spi.locator.ServiceLocator;
70  import org.eclipse.aether.transfer.ArtifactNotFoundException;
71  
72  /**
73   * @author Benjamin Bentmann
74   */
75  @Named
76  @Singleton
77  public class DefaultArtifactDescriptorReader
78      implements ArtifactDescriptorReader, Service
79  {
80      private RemoteRepositoryManager remoteRepositoryManager;
81  
82      private VersionResolver versionResolver;
83  
84      private VersionRangeResolver versionRangeResolver;
85  
86      private ArtifactResolver artifactResolver;
87  
88      private RepositoryEventDispatcher repositoryEventDispatcher;
89  
90      private ModelBuilder modelBuilder;
91  
92      public DefaultArtifactDescriptorReader()
93      {
94          // enable no-arg constructor
95      }
96  
97      @Inject
98      DefaultArtifactDescriptorReader( RemoteRepositoryManager remoteRepositoryManager, VersionResolver versionResolver,
99                                       VersionRangeResolver versionRangeResolver, ArtifactResolver artifactResolver,
100                                      ModelBuilder modelBuilder, RepositoryEventDispatcher repositoryEventDispatcher )
101     {
102         setRemoteRepositoryManager( remoteRepositoryManager );
103         setVersionResolver( versionResolver );
104         setVersionRangeResolver( versionRangeResolver );
105         setArtifactResolver( artifactResolver );
106         setModelBuilder( modelBuilder );
107         setRepositoryEventDispatcher( repositoryEventDispatcher );
108     }
109 
110     public void initService( ServiceLocator locator )
111     {
112         setRemoteRepositoryManager( locator.getService( RemoteRepositoryManager.class ) );
113         setVersionResolver( locator.getService( VersionResolver.class ) );
114         setVersionRangeResolver( locator.getService( VersionRangeResolver.class ) );
115         setArtifactResolver( locator.getService( ArtifactResolver.class ) );
116         modelBuilder = locator.getService( ModelBuilder.class );
117         if ( modelBuilder == null )
118         {
119             setModelBuilder( new DefaultModelBuilderFactory().newInstance() );
120         }
121         setRepositoryEventDispatcher( locator.getService( RepositoryEventDispatcher.class ) );
122     }
123 
124     public DefaultArtifactDescriptorReader setRemoteRepositoryManager( RemoteRepositoryManager remoteRepositoryManager )
125     {
126         this.remoteRepositoryManager = Objects.requireNonNull( remoteRepositoryManager,
127             "remoteRepositoryManager cannot be null" );
128         return this;
129     }
130 
131     public DefaultArtifactDescriptorReader setVersionResolver( VersionResolver versionResolver )
132     {
133         this.versionResolver = Objects.requireNonNull( versionResolver, "versionResolver cannot be null" );
134         return this;
135     }
136 
137     /** @since 3.2.2 */
138     public DefaultArtifactDescriptorReader setVersionRangeResolver( VersionRangeResolver versionRangeResolver )
139     {
140         this.versionRangeResolver =
141             Objects.requireNonNull( versionRangeResolver, "versionRangeResolver cannot be null" );
142         return this;
143     }
144 
145     public DefaultArtifactDescriptorReader setArtifactResolver( ArtifactResolver artifactResolver )
146     {
147         this.artifactResolver = Objects.requireNonNull( artifactResolver, "artifactResolver cannot be null" );
148         return this;
149     }
150 
151     public DefaultArtifactDescriptorReader setRepositoryEventDispatcher(
152         RepositoryEventDispatcher repositoryEventDispatcher )
153     {
154         this.repositoryEventDispatcher = Objects.requireNonNull( repositoryEventDispatcher,
155             "repositoryEventDispatcher cannot be null" );
156         return this;
157     }
158 
159     public DefaultArtifactDescriptorReader setModelBuilder( ModelBuilder modelBuilder )
160     {
161         this.modelBuilder = Objects.requireNonNull( modelBuilder, "modelBuilder cannot be null" );
162         return this;
163     }
164 
165     public ArtifactDescriptorResult readArtifactDescriptor( RepositorySystemSession session,
166                                                             ArtifactDescriptorRequest request )
167         throws ArtifactDescriptorException
168     {
169         ArtifactDescriptorResult result = new ArtifactDescriptorResult( request );
170 
171         Model model = loadPom( session, request, result );
172         if ( model != null )
173         {
174             Map<String, Object> config = session.getConfigProperties();
175             ArtifactDescriptorReaderDelegate delegate =
176                 (ArtifactDescriptorReaderDelegate) config.get( ArtifactDescriptorReaderDelegate.class.getName() );
177 
178             if ( delegate == null )
179             {
180                 delegate = new ArtifactDescriptorReaderDelegate();
181             }
182 
183             delegate.populateResult( session, result, model );
184         }
185 
186         return result;
187     }
188 
189     private Model loadPom( RepositorySystemSession session, ArtifactDescriptorRequest request,
190                            ArtifactDescriptorResult result )
191         throws ArtifactDescriptorException
192     {
193         RequestTrace trace = RequestTrace.newChild( request.getTrace(), request );
194 
195         Set<String> visited = new LinkedHashSet<>();
196         for ( Artifact a = request.getArtifact();; )
197         {
198             Artifact pomArtifact = ArtifactDescriptorUtils.toPomArtifact( a );
199             try
200             {
201                 VersionRequest versionRequest =
202                     new VersionRequest( a, request.getRepositories(), request.getRequestContext() );
203                 versionRequest.setTrace( trace );
204                 VersionResult versionResult = versionResolver.resolveVersion( session, versionRequest );
205 
206                 a = a.setVersion( versionResult.getVersion() );
207 
208                 versionRequest =
209                     new VersionRequest( pomArtifact, request.getRepositories(), request.getRequestContext() );
210                 versionRequest.setTrace( trace );
211                 versionResult = versionResolver.resolveVersion( session, versionRequest );
212 
213                 pomArtifact = pomArtifact.setVersion( versionResult.getVersion() );
214             }
215             catch ( VersionResolutionException e )
216             {
217                 result.addException( e );
218                 throw new ArtifactDescriptorException( result );
219             }
220 
221             if ( !visited.add( a.getGroupId() + ':' + a.getArtifactId() + ':' + a.getBaseVersion() ) )
222             {
223                 RepositoryException exception =
224                     new RepositoryException( "Artifact relocations form a cycle: " + visited );
225                 invalidDescriptor( session, trace, a, exception );
226                 if ( ( getPolicy( session, a, request ) & ArtifactDescriptorPolicy.IGNORE_INVALID ) != 0 )
227                 {
228                     return null;
229                 }
230                 result.addException( exception );
231                 throw new ArtifactDescriptorException( result );
232             }
233 
234             ArtifactResult resolveResult;
235             try
236             {
237                 ArtifactRequest resolveRequest =
238                     new ArtifactRequest( pomArtifact, request.getRepositories(), request.getRequestContext() );
239                 resolveRequest.setTrace( trace );
240                 resolveResult = artifactResolver.resolveArtifact( session, resolveRequest );
241                 pomArtifact = resolveResult.getArtifact();
242                 result.setRepository( resolveResult.getRepository() );
243             }
244             catch ( ArtifactResolutionException e )
245             {
246                 if ( e.getCause() instanceof ArtifactNotFoundException )
247                 {
248                     missingDescriptor( session, trace, a, (Exception) e.getCause() );
249                     if ( ( getPolicy( session, a, request ) & ArtifactDescriptorPolicy.IGNORE_MISSING ) != 0 )
250                     {
251                         return null;
252                     }
253                 }
254                 result.addException( e );
255                 throw new ArtifactDescriptorException( result );
256             }
257 
258             Model model;
259 
260             // hack: don't rebuild model if it was already loaded during reactor resolution
261             final WorkspaceReader workspace = session.getWorkspaceReader();
262             if ( workspace instanceof MavenWorkspaceReader )
263             {
264                 model = ( (MavenWorkspaceReader) workspace ).findModel( pomArtifact );
265                 if ( model != null )
266                 {
267                     return model;
268                 }
269             }
270 
271             try
272             {
273                 ModelBuildingRequest modelRequest = new DefaultModelBuildingRequest();
274                 modelRequest.setValidationLevel( ModelBuildingRequest.VALIDATION_LEVEL_MINIMAL );
275                 modelRequest.setProcessPlugins( false );
276                 modelRequest.setTwoPhaseBuilding( false );
277                 modelRequest.setSystemProperties( toProperties( session.getUserProperties(),
278                                                                 session.getSystemProperties() ) );
279                 modelRequest.setModelCache( DefaultModelCache.newInstance( session ) );
280                 modelRequest.setModelResolver( new DefaultModelResolver( session, trace.newChild( modelRequest ),
281                                                                          request.getRequestContext(), artifactResolver,
282                                                                          versionRangeResolver, remoteRepositoryManager,
283                                                                          request.getRepositories() ) );
284                 if ( resolveResult.getRepository() instanceof WorkspaceRepository )
285                 {
286                     modelRequest.setPomFile( pomArtifact.getFile() );
287                 }
288                 else
289                 {
290                     modelRequest.setModelSource( new FileModelSource( pomArtifact.getFile() ) );
291                 }
292 
293                 model = modelBuilder.build( modelRequest ).getEffectiveModel();
294             }
295             catch ( ModelBuildingException e )
296             {
297                 for ( ModelProblem problem : e.getProblems() )
298                 {
299                     if ( problem.getException() instanceof UnresolvableModelException )
300                     {
301                         result.addException( problem.getException() );
302                         throw new ArtifactDescriptorException( result );
303                     }
304                 }
305                 invalidDescriptor( session, trace, a, e );
306                 if ( ( getPolicy( session, a, request ) & ArtifactDescriptorPolicy.IGNORE_INVALID ) != 0 )
307                 {
308                     return null;
309                 }
310                 result.addException( e );
311                 throw new ArtifactDescriptorException( result );
312             }
313 
314             Relocation relocation = getRelocation( model );
315 
316             if ( relocation != null )
317             {
318                 result.addRelocation( a );
319                 a =
320                     new RelocatedArtifact( a, relocation.getGroupId(), relocation.getArtifactId(),
321                                            relocation.getVersion() );
322                 result.setArtifact( a );
323             }
324             else
325             {
326                 return model;
327             }
328         }
329     }
330 
331     private Properties toProperties( Map<String, String> dominant, Map<String, String> recessive )
332     {
333         Properties props = new Properties();
334         if ( recessive != null )
335         {
336             props.putAll( recessive );
337         }
338         if ( dominant != null )
339         {
340             props.putAll( dominant );
341         }
342         return props;
343     }
344 
345     private Relocation getRelocation( Model model )
346     {
347         Relocation relocation = null;
348         DistributionManagement distMgmt = model.getDistributionManagement();
349         if ( distMgmt != null )
350         {
351             relocation = distMgmt.getRelocation();
352         }
353         return relocation;
354     }
355 
356     private void missingDescriptor( RepositorySystemSession session, RequestTrace trace, Artifact artifact,
357                                     Exception exception )
358     {
359         RepositoryEvent.Builder event = new RepositoryEvent.Builder( session, EventType.ARTIFACT_DESCRIPTOR_MISSING );
360         event.setTrace( trace );
361         event.setArtifact( artifact );
362         event.setException( exception );
363 
364         repositoryEventDispatcher.dispatch( event.build() );
365     }
366 
367     private void invalidDescriptor( RepositorySystemSession session, RequestTrace trace, Artifact artifact,
368                                     Exception exception )
369     {
370         RepositoryEvent.Builder event = new RepositoryEvent.Builder( session, EventType.ARTIFACT_DESCRIPTOR_INVALID );
371         event.setTrace( trace );
372         event.setArtifact( artifact );
373         event.setException( exception );
374 
375         repositoryEventDispatcher.dispatch( event.build() );
376     }
377 
378     private int getPolicy( RepositorySystemSession session, Artifact a, ArtifactDescriptorRequest request )
379     {
380         ArtifactDescriptorPolicy policy = session.getArtifactDescriptorPolicy();
381         if ( policy == null )
382         {
383             return ArtifactDescriptorPolicy.STRICT;
384         }
385         return policy.getPolicy( session, new ArtifactDescriptorPolicyRequest( a, request.getRequestContext() ) );
386     }
387 
388 }