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             final WorkspaceReader workspace = session.getWorkspaceReader();
261             if ( workspace instanceof MavenWorkspaceReader )
262             {
263                 model = ( (MavenWorkspaceReader) workspace ).findModel( pomArtifact );
264                 if ( model != null )
265                 {
266                     return model;
267                 }
268             }
269 
270             try
271             {
272                 ModelBuildingRequest modelRequest = new DefaultModelBuildingRequest();
273                 modelRequest.setValidationLevel( ModelBuildingRequest.VALIDATION_LEVEL_MINIMAL );
274                 modelRequest.setProcessPlugins( false );
275                 modelRequest.setTwoPhaseBuilding( false );
276                 modelRequest.setSystemProperties( toProperties( session.getUserProperties(),
277                                                                 session.getSystemProperties() ) );
278                 modelRequest.setModelCache( DefaultModelCache.newInstance( session ) );
279                 modelRequest.setModelResolver( new DefaultModelResolver( session, trace.newChild( modelRequest ),
280                                                                          request.getRequestContext(), artifactResolver,
281                                                                          versionRangeResolver, remoteRepositoryManager,
282                                                                          request.getRepositories() ) );
283                 if ( resolveResult.getRepository() instanceof WorkspaceRepository )
284                 {
285                     modelRequest.setPomFile( pomArtifact.getFile() );
286                 }
287                 else
288                 {
289                     modelRequest.setModelSource( new FileModelSource( pomArtifact.getFile() ) );
290                 }
291 
292                 model = modelBuilder.build( modelRequest ).getEffectiveModel();
293             }
294             catch ( ModelBuildingException e )
295             {
296                 for ( ModelProblem problem : e.getProblems() )
297                 {
298                     if ( problem.getException() instanceof UnresolvableModelException )
299                     {
300                         result.addException( problem.getException() );
301                         throw new ArtifactDescriptorException( result );
302                     }
303                 }
304                 invalidDescriptor( session, trace, a, e );
305                 if ( ( getPolicy( session, a, request ) & ArtifactDescriptorPolicy.IGNORE_INVALID ) != 0 )
306                 {
307                     return null;
308                 }
309                 result.addException( e );
310                 throw new ArtifactDescriptorException( result );
311             }
312 
313             Relocation relocation = getRelocation( model );
314 
315             if ( relocation != null )
316             {
317                 result.addRelocation( a );
318                 a =
319                     new RelocatedArtifact( a, relocation.getGroupId(), relocation.getArtifactId(),
320                                            relocation.getVersion() );
321                 result.setArtifact( a );
322             }
323             else
324             {
325                 return model;
326             }
327         }
328     }
329 
330     private Properties toProperties( Map<String, String> dominant, Map<String, String> recessive )
331     {
332         Properties props = new Properties();
333         if ( recessive != null )
334         {
335             props.putAll( recessive );
336         }
337         if ( dominant != null )
338         {
339             props.putAll( dominant );
340         }
341         return props;
342     }
343 
344     private Relocation getRelocation( Model model )
345     {
346         Relocation relocation = null;
347         DistributionManagement distMgmt = model.getDistributionManagement();
348         if ( distMgmt != null )
349         {
350             relocation = distMgmt.getRelocation();
351         }
352         return relocation;
353     }
354 
355     private void missingDescriptor( RepositorySystemSession session, RequestTrace trace, Artifact artifact,
356                                     Exception exception )
357     {
358         RepositoryEvent.Builder event = new RepositoryEvent.Builder( session, EventType.ARTIFACT_DESCRIPTOR_MISSING );
359         event.setTrace( trace );
360         event.setArtifact( artifact );
361         event.setException( exception );
362 
363         repositoryEventDispatcher.dispatch( event.build() );
364     }
365 
366     private void invalidDescriptor( RepositorySystemSession session, RequestTrace trace, Artifact artifact,
367                                     Exception exception )
368     {
369         RepositoryEvent.Builder event = new RepositoryEvent.Builder( session, EventType.ARTIFACT_DESCRIPTOR_INVALID );
370         event.setTrace( trace );
371         event.setArtifact( artifact );
372         event.setException( exception );
373 
374         repositoryEventDispatcher.dispatch( event.build() );
375     }
376 
377     private int getPolicy( RepositorySystemSession session, Artifact a, ArtifactDescriptorRequest request )
378     {
379         ArtifactDescriptorPolicy policy = session.getArtifactDescriptorPolicy();
380         if ( policy == null )
381         {
382             return ArtifactDescriptorPolicy.STRICT;
383         }
384         return policy.getPolicy( session, new ArtifactDescriptorPolicyRequest( a, request.getRequestContext() ) );
385     }
386 
387 }