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.Properties;
25  import java.util.Set;
26  
27  import javax.inject.Inject;
28  import javax.inject.Named;
29  
30  import org.apache.maven.model.DistributionManagement;
31  import org.apache.maven.model.Model;
32  import org.apache.maven.model.Relocation;
33  import org.apache.maven.model.building.DefaultModelBuilderFactory;
34  import org.apache.maven.model.building.DefaultModelBuildingRequest;
35  import org.apache.maven.model.building.FileModelSource;
36  import org.apache.maven.model.building.ModelBuilder;
37  import org.apache.maven.model.building.ModelBuildingException;
38  import org.apache.maven.model.building.ModelBuildingRequest;
39  import org.apache.maven.model.building.ModelProblem;
40  import org.apache.maven.model.resolution.UnresolvableModelException;
41  import org.codehaus.plexus.component.annotations.Component;
42  import org.codehaus.plexus.component.annotations.Requirement;
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.spi.log.Logger;
71  import org.eclipse.aether.spi.log.LoggerFactory;
72  import org.eclipse.aether.spi.log.NullLoggerFactory;
73  import org.eclipse.aether.transfer.ArtifactNotFoundException;
74  
75  /**
76   * @author Benjamin Bentmann
77   */
78  @Named
79  @Component( role = ArtifactDescriptorReader.class )
80  public class DefaultArtifactDescriptorReader
81      implements ArtifactDescriptorReader, Service
82  {
83  
84      @SuppressWarnings( "unused" )
85      @Requirement( role = LoggerFactory.class )
86      private Logger logger = NullLoggerFactory.LOGGER;
87  
88      @Requirement
89      private RemoteRepositoryManager remoteRepositoryManager;
90  
91      @Requirement
92      private VersionResolver versionResolver;
93  
94      @Requirement
95      private VersionRangeResolver versionRangeResolver;
96  
97      @Requirement
98      private ArtifactResolver artifactResolver;
99  
100     @Requirement
101     private RepositoryEventDispatcher repositoryEventDispatcher;
102 
103     @Requirement
104     private ModelBuilder modelBuilder;
105 
106     public DefaultArtifactDescriptorReader()
107     {
108         // enable no-arg constructor
109     }
110 
111     @Inject
112     DefaultArtifactDescriptorReader( RemoteRepositoryManager remoteRepositoryManager, VersionResolver versionResolver,
113                                      ArtifactResolver artifactResolver, ModelBuilder modelBuilder,
114                                      RepositoryEventDispatcher repositoryEventDispatcher, LoggerFactory loggerFactory )
115     {
116         setRemoteRepositoryManager( remoteRepositoryManager );
117         setVersionResolver( versionResolver );
118         setArtifactResolver( artifactResolver );
119         setModelBuilder( modelBuilder );
120         setLoggerFactory( loggerFactory );
121         setRepositoryEventDispatcher( repositoryEventDispatcher );
122     }
123 
124     public void initService( ServiceLocator locator )
125     {
126         setLoggerFactory( locator.getService( LoggerFactory.class ) );
127         setRemoteRepositoryManager( locator.getService( RemoteRepositoryManager.class ) );
128         setVersionResolver( locator.getService( VersionResolver.class ) );
129         setVersionRangeResolver( locator.getService( VersionRangeResolver.class ) );
130         setArtifactResolver( locator.getService( ArtifactResolver.class ) );
131         setRepositoryEventDispatcher( locator.getService( RepositoryEventDispatcher.class ) );
132         modelBuilder = locator.getService( ModelBuilder.class );
133         if ( modelBuilder == null )
134         {
135             setModelBuilder( new DefaultModelBuilderFactory().newInstance() );
136         }
137     }
138 
139     public DefaultArtifactDescriptorReader setLoggerFactory( LoggerFactory loggerFactory )
140     {
141         this.logger = NullLoggerFactory.getSafeLogger( loggerFactory, getClass() );
142         return this;
143     }
144 
145     void setLogger( LoggerFactory loggerFactory )
146     {
147         // plexus support
148         setLoggerFactory( loggerFactory );
149     }
150 
151     public DefaultArtifactDescriptorReader setRemoteRepositoryManager( RemoteRepositoryManager remoteRepositoryManager )
152     {
153         if ( remoteRepositoryManager == null )
154         {
155             throw new IllegalArgumentException( "remote repository manager has not been specified" );
156         }
157         this.remoteRepositoryManager = remoteRepositoryManager;
158         return this;
159     }
160 
161     public DefaultArtifactDescriptorReader setVersionResolver( VersionResolver versionResolver )
162     {
163         if ( versionResolver == null )
164         {
165             throw new IllegalArgumentException( "version resolver has not been specified" );
166         }
167         this.versionResolver = versionResolver;
168         return this;
169     }
170 
171     /** @since 3.2.2 */
172     public DefaultArtifactDescriptorReader setVersionRangeResolver( VersionRangeResolver versionRangeResolver )
173     {
174         if ( versionRangeResolver == null )
175         {
176             throw new IllegalArgumentException( "version range resolver has not been specified" );
177         }
178         this.versionRangeResolver = versionRangeResolver;
179         return this;
180     }
181 
182     public DefaultArtifactDescriptorReader setArtifactResolver( ArtifactResolver artifactResolver )
183     {
184         if ( artifactResolver == null )
185         {
186             throw new IllegalArgumentException( "artifact resolver has not been specified" );
187         }
188         this.artifactResolver = artifactResolver;
189         return this;
190     }
191 
192     public DefaultArtifactDescriptorReader setRepositoryEventDispatcher( RepositoryEventDispatcher red )
193     {
194         if ( red == null )
195         {
196             throw new IllegalArgumentException( "repository event dispatcher has not been specified" );
197         }
198         this.repositoryEventDispatcher = red;
199         return this;
200     }
201 
202     public DefaultArtifactDescriptorReader setModelBuilder( ModelBuilder modelBuilder )
203     {
204         if ( modelBuilder == null )
205         {
206             throw new IllegalArgumentException( "model builder has not been specified" );
207         }
208         this.modelBuilder = modelBuilder;
209         return this;
210     }
211 
212     public ArtifactDescriptorResult readArtifactDescriptor( RepositorySystemSession session,
213                                                             ArtifactDescriptorRequest request )
214         throws ArtifactDescriptorException
215     {
216         ArtifactDescriptorResult result = new ArtifactDescriptorResult( request );
217 
218         Model model = loadPom( session, request, result );
219         if ( model != null )
220         {
221             Map<String, Object> config = session.getConfigProperties();
222             ArtifactDescriptorReaderDelegate delegate =
223                 (ArtifactDescriptorReaderDelegate) config.get( ArtifactDescriptorReaderDelegate.class.getName() );
224 
225             if ( delegate == null )
226             {
227                 delegate = new ArtifactDescriptorReaderDelegate();
228             }
229 
230             delegate.populateResult( session, result, model );
231         }
232 
233         return result;
234     }
235 
236     private Model loadPom( RepositorySystemSession session, ArtifactDescriptorRequest request,
237                            ArtifactDescriptorResult result )
238         throws ArtifactDescriptorException
239     {
240         RequestTrace trace = RequestTrace.newChild( request.getTrace(), request );
241 
242         Set<String> visited = new LinkedHashSet<String>();
243         for ( Artifact a = request.getArtifact();; )
244         {
245             Artifact pomArtifact = ArtifactDescriptorUtils.toPomArtifact( a );
246             try
247             {
248                 VersionRequest versionRequest =
249                     new VersionRequest( a, request.getRepositories(), request.getRequestContext() );
250                 versionRequest.setTrace( trace );
251                 VersionResult versionResult = versionResolver.resolveVersion( session, versionRequest );
252 
253                 a = a.setVersion( versionResult.getVersion() );
254 
255                 versionRequest =
256                     new VersionRequest( pomArtifact, request.getRepositories(), request.getRequestContext() );
257                 versionRequest.setTrace( trace );
258                 versionResult = versionResolver.resolveVersion( session, versionRequest );
259 
260                 pomArtifact = pomArtifact.setVersion( versionResult.getVersion() );
261             }
262             catch ( VersionResolutionException e )
263             {
264                 result.addException( e );
265                 throw new ArtifactDescriptorException( result );
266             }
267 
268             if ( !visited.add( a.getGroupId() + ':' + a.getArtifactId() + ':' + a.getBaseVersion() ) )
269             {
270                 RepositoryException exception =
271                     new RepositoryException( "Artifact relocations form a cycle: " + visited );
272                 invalidDescriptor( session, trace, a, exception );
273                 if ( ( getPolicy( session, a, request ) & ArtifactDescriptorPolicy.IGNORE_INVALID ) != 0 )
274                 {
275                     return null;
276                 }
277                 result.addException( exception );
278                 throw new ArtifactDescriptorException( result );
279             }
280 
281             ArtifactResult resolveResult;
282             try
283             {
284                 ArtifactRequest resolveRequest =
285                     new ArtifactRequest( pomArtifact, request.getRepositories(), request.getRequestContext() );
286                 resolveRequest.setTrace( trace );
287                 resolveResult = artifactResolver.resolveArtifact( session, resolveRequest );
288                 pomArtifact = resolveResult.getArtifact();
289                 result.setRepository( resolveResult.getRepository() );
290             }
291             catch ( ArtifactResolutionException e )
292             {
293                 if ( e.getCause() instanceof ArtifactNotFoundException )
294                 {
295                     missingDescriptor( session, trace, a, (Exception) e.getCause() );
296                     if ( ( getPolicy( session, a, request ) & ArtifactDescriptorPolicy.IGNORE_MISSING ) != 0 )
297                     {
298                         return null;
299                     }
300                 }
301                 result.addException( e );
302                 throw new ArtifactDescriptorException( result );
303             }
304 
305             Model model;
306 
307             // hack: don't rebuild model if it was already loaded during reactor resolution
308             final WorkspaceReader workspace = session.getWorkspaceReader();
309             if ( workspace instanceof MavenWorkspaceReader )
310             {
311                 model = ( (MavenWorkspaceReader) workspace ).findModel( pomArtifact );
312                 if ( model != null )
313                 {
314                     return model;
315                 }
316             }
317 
318             try
319             {
320                 ModelBuildingRequest modelRequest = new DefaultModelBuildingRequest();
321                 modelRequest.setValidationLevel( ModelBuildingRequest.VALIDATION_LEVEL_MINIMAL );
322                 modelRequest.setProcessPlugins( false );
323                 modelRequest.setTwoPhaseBuilding( false );
324                 modelRequest.setSystemProperties( toProperties( session.getUserProperties(),
325                                                                 session.getSystemProperties() ) );
326                 modelRequest.setModelCache( DefaultModelCache.newInstance( session ) );
327                 modelRequest.setModelResolver( new DefaultModelResolver( session, trace.newChild( modelRequest ),
328                                                                          request.getRequestContext(), artifactResolver,
329                                                                          versionRangeResolver, remoteRepositoryManager,
330                                                                          request.getRepositories() ) );
331                 if ( resolveResult.getRepository() instanceof WorkspaceRepository )
332                 {
333                     modelRequest.setPomFile( pomArtifact.getFile() );
334                 }
335                 else
336                 {
337                     modelRequest.setModelSource( new FileModelSource( pomArtifact.getFile() ) );
338                 }
339 
340                 model = modelBuilder.build( modelRequest ).getEffectiveModel();
341             }
342             catch ( ModelBuildingException e )
343             {
344                 for ( ModelProblem problem : e.getProblems() )
345                 {
346                     if ( problem.getException() instanceof UnresolvableModelException )
347                     {
348                         result.addException( problem.getException() );
349                         throw new ArtifactDescriptorException( result );
350                     }
351                 }
352                 invalidDescriptor( session, trace, a, e );
353                 if ( ( getPolicy( session, a, request ) & ArtifactDescriptorPolicy.IGNORE_INVALID ) != 0 )
354                 {
355                     return null;
356                 }
357                 result.addException( e );
358                 throw new ArtifactDescriptorException( result );
359             }
360 
361             Relocation relocation = getRelocation( model );
362 
363             if ( relocation != null )
364             {
365                 result.addRelocation( a );
366                 a =
367                     new RelocatedArtifact( a, relocation.getGroupId(), relocation.getArtifactId(),
368                                            relocation.getVersion() );
369                 result.setArtifact( a );
370             }
371             else
372             {
373                 return model;
374             }
375         }
376     }
377 
378     private Properties toProperties( Map<String, String> dominant, Map<String, String> recessive )
379     {
380         Properties props = new Properties();
381         if ( recessive != null )
382         {
383             props.putAll( recessive );
384         }
385         if ( dominant != null )
386         {
387             props.putAll( dominant );
388         }
389         return props;
390     }
391 
392     private Relocation getRelocation( Model model )
393     {
394         Relocation relocation = null;
395         DistributionManagement distMngt = model.getDistributionManagement();
396         if ( distMngt != null )
397         {
398             relocation = distMngt.getRelocation();
399         }
400         return relocation;
401     }
402 
403     private void missingDescriptor( RepositorySystemSession session, RequestTrace trace, Artifact artifact,
404                                     Exception exception )
405     {
406         RepositoryEvent.Builder event = new RepositoryEvent.Builder( session, EventType.ARTIFACT_DESCRIPTOR_MISSING );
407         event.setTrace( trace );
408         event.setArtifact( artifact );
409         event.setException( exception );
410 
411         repositoryEventDispatcher.dispatch( event.build() );
412     }
413 
414     private void invalidDescriptor( RepositorySystemSession session, RequestTrace trace, Artifact artifact,
415                                     Exception exception )
416     {
417         RepositoryEvent.Builder event = new RepositoryEvent.Builder( session, EventType.ARTIFACT_DESCRIPTOR_INVALID );
418         event.setTrace( trace );
419         event.setArtifact( artifact );
420         event.setException( exception );
421 
422         repositoryEventDispatcher.dispatch( event.build() );
423     }
424 
425     private int getPolicy( RepositorySystemSession session, Artifact a, ArtifactDescriptorRequest request )
426     {
427         ArtifactDescriptorPolicy policy = session.getArtifactDescriptorPolicy();
428         if ( policy == null )
429         {
430             return ArtifactDescriptorPolicy.STRICT;
431         }
432         return policy.getPolicy( session, new ArtifactDescriptorPolicyRequest( a, request.getRequestContext() ) );
433     }
434 
435 }