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.WorkspaceRepository;
56  import org.eclipse.aether.resolution.ArtifactDescriptorException;
57  import org.eclipse.aether.resolution.ArtifactDescriptorPolicy;
58  import org.eclipse.aether.resolution.ArtifactDescriptorPolicyRequest;
59  import org.eclipse.aether.resolution.ArtifactDescriptorRequest;
60  import org.eclipse.aether.resolution.ArtifactDescriptorResult;
61  import org.eclipse.aether.resolution.ArtifactRequest;
62  import org.eclipse.aether.resolution.ArtifactResolutionException;
63  import org.eclipse.aether.resolution.ArtifactResult;
64  import org.eclipse.aether.resolution.VersionRequest;
65  import org.eclipse.aether.resolution.VersionResolutionException;
66  import org.eclipse.aether.resolution.VersionResult;
67  import org.eclipse.aether.spi.locator.Service;
68  import org.eclipse.aether.spi.locator.ServiceLocator;
69  import org.eclipse.aether.spi.log.Logger;
70  import org.eclipse.aether.spi.log.LoggerFactory;
71  import org.eclipse.aether.spi.log.NullLoggerFactory;
72  import org.eclipse.aether.transfer.ArtifactNotFoundException;
73  
74  /**
75   * @author Benjamin Bentmann
76   */
77  @Named
78  @Component( role = ArtifactDescriptorReader.class )
79  public class DefaultArtifactDescriptorReader
80      implements ArtifactDescriptorReader, Service
81  {
82  
83      @SuppressWarnings( "unused" )
84      @Requirement( role = LoggerFactory.class )
85      private Logger logger = NullLoggerFactory.LOGGER;
86  
87      @Requirement
88      private RemoteRepositoryManager remoteRepositoryManager;
89  
90      @Requirement
91      private VersionResolver versionResolver;
92  
93      @Requirement
94      private VersionRangeResolver versionRangeResolver;
95  
96      @Requirement
97      private ArtifactResolver artifactResolver;
98  
99      @Requirement
100     private RepositoryEventDispatcher repositoryEventDispatcher;
101 
102     @Requirement
103     private ModelBuilder modelBuilder;
104 
105     public DefaultArtifactDescriptorReader()
106     {
107         // enable no-arg constructor
108     }
109 
110     @Inject
111     DefaultArtifactDescriptorReader( RemoteRepositoryManager remoteRepositoryManager, VersionResolver versionResolver,
112                                      ArtifactResolver artifactResolver, ModelBuilder modelBuilder,
113                                      RepositoryEventDispatcher repositoryEventDispatcher, LoggerFactory loggerFactory )
114     {
115         setRemoteRepositoryManager( remoteRepositoryManager );
116         setVersionResolver( versionResolver );
117         setArtifactResolver( artifactResolver );
118         setModelBuilder( modelBuilder );
119         setLoggerFactory( loggerFactory );
120         setRepositoryEventDispatcher( repositoryEventDispatcher );
121     }
122 
123     public void initService( ServiceLocator locator )
124     {
125         setLoggerFactory( locator.getService( LoggerFactory.class ) );
126         setRemoteRepositoryManager( locator.getService( RemoteRepositoryManager.class ) );
127         setVersionResolver( locator.getService( VersionResolver.class ) );
128         setVersionRangeResolver( locator.getService( VersionRangeResolver.class ) );
129         setArtifactResolver( locator.getService( ArtifactResolver.class ) );
130         setRepositoryEventDispatcher( locator.getService( RepositoryEventDispatcher.class ) );
131         modelBuilder = locator.getService( ModelBuilder.class );
132         if ( modelBuilder == null )
133         {
134             setModelBuilder( new DefaultModelBuilderFactory().newInstance() );
135         }
136     }
137 
138     public DefaultArtifactDescriptorReader setLoggerFactory( LoggerFactory loggerFactory )
139     {
140         this.logger = NullLoggerFactory.getSafeLogger( loggerFactory, getClass() );
141         return this;
142     }
143 
144     void setLogger( LoggerFactory loggerFactory )
145     {
146         // plexus support
147         setLoggerFactory( loggerFactory );
148     }
149 
150     public DefaultArtifactDescriptorReader setRemoteRepositoryManager( RemoteRepositoryManager remoteRepositoryManager )
151     {
152         if ( remoteRepositoryManager == null )
153         {
154             throw new IllegalArgumentException( "remote repository manager has not been specified" );
155         }
156         this.remoteRepositoryManager = remoteRepositoryManager;
157         return this;
158     }
159 
160     public DefaultArtifactDescriptorReader setVersionResolver( VersionResolver versionResolver )
161     {
162         if ( versionResolver == null )
163         {
164             throw new IllegalArgumentException( "version resolver has not been specified" );
165         }
166         this.versionResolver = versionResolver;
167         return this;
168     }
169 
170     /** @since 3.2.2 */
171     public DefaultArtifactDescriptorReader setVersionRangeResolver( VersionRangeResolver versionRangeResolver )
172     {
173         if ( versionRangeResolver == null )
174         {
175             throw new IllegalArgumentException( "version range resolver has not been specified" );
176         }
177         this.versionRangeResolver = versionRangeResolver;
178         return this;
179     }
180 
181     public DefaultArtifactDescriptorReader setArtifactResolver( ArtifactResolver artifactResolver )
182     {
183         if ( artifactResolver == null )
184         {
185             throw new IllegalArgumentException( "artifact resolver has not been specified" );
186         }
187         this.artifactResolver = artifactResolver;
188         return this;
189     }
190 
191     public DefaultArtifactDescriptorReader setRepositoryEventDispatcher( RepositoryEventDispatcher red )
192     {
193         if ( red == null )
194         {
195             throw new IllegalArgumentException( "repository event dispatcher has not been specified" );
196         }
197         this.repositoryEventDispatcher = red;
198         return this;
199     }
200 
201     public DefaultArtifactDescriptorReader setModelBuilder( ModelBuilder modelBuilder )
202     {
203         if ( modelBuilder == null )
204         {
205             throw new IllegalArgumentException( "model builder has not been specified" );
206         }
207         this.modelBuilder = modelBuilder;
208         return this;
209     }
210 
211     public ArtifactDescriptorResult readArtifactDescriptor( RepositorySystemSession session,
212                                                             ArtifactDescriptorRequest request )
213         throws ArtifactDescriptorException
214     {
215         ArtifactDescriptorResult result = new ArtifactDescriptorResult( request );
216 
217         Model model = loadPom( session, request, result );
218 
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             try
307             {
308                 ModelBuildingRequest modelRequest = new DefaultModelBuildingRequest();
309                 modelRequest.setValidationLevel( ModelBuildingRequest.VALIDATION_LEVEL_MINIMAL );
310                 modelRequest.setProcessPlugins( false );
311                 modelRequest.setTwoPhaseBuilding( false );
312                 modelRequest.setSystemProperties( toProperties( session.getUserProperties(),
313                                                                 session.getSystemProperties() ) );
314                 modelRequest.setModelCache( DefaultModelCache.newInstance( session ) );
315                 modelRequest.setModelResolver( new DefaultModelResolver( session, trace.newChild( modelRequest ),
316                                                                          request.getRequestContext(), artifactResolver,
317                                                                          versionRangeResolver, remoteRepositoryManager,
318                                                                          request.getRepositories() ) );
319                 if ( resolveResult.getRepository() instanceof WorkspaceRepository )
320                 {
321                     modelRequest.setPomFile( pomArtifact.getFile() );
322                 }
323                 else
324                 {
325                     modelRequest.setModelSource( new FileModelSource( pomArtifact.getFile() ) );
326                 }
327 
328                 model = modelBuilder.build( modelRequest ).getEffectiveModel();
329             }
330             catch ( ModelBuildingException e )
331             {
332                 for ( ModelProblem problem : e.getProblems() )
333                 {
334                     if ( problem.getException() instanceof UnresolvableModelException )
335                     {
336                         result.addException( problem.getException() );
337                         throw new ArtifactDescriptorException( result );
338                     }
339                 }
340                 invalidDescriptor( session, trace, a, e );
341                 if ( ( getPolicy( session, a, request ) & ArtifactDescriptorPolicy.IGNORE_INVALID ) != 0 )
342                 {
343                     return null;
344                 }
345                 result.addException( e );
346                 throw new ArtifactDescriptorException( result );
347             }
348 
349             Relocation relocation = getRelocation( model );
350 
351             if ( relocation != null )
352             {
353                 result.addRelocation( a );
354                 a =
355                     new RelocatedArtifact( a, relocation.getGroupId(), relocation.getArtifactId(),
356                                            relocation.getVersion() );
357                 result.setArtifact( a );
358             }
359             else
360             {
361                 return model;
362             }
363         }
364     }
365 
366     private Properties toProperties( Map<String, String> dominant, Map<String, String> recessive )
367     {
368         Properties props = new Properties();
369         if ( recessive != null )
370         {
371             props.putAll( recessive );
372         }
373         if ( dominant != null )
374         {
375             props.putAll( dominant );
376         }
377         return props;
378     }
379 
380     private Relocation getRelocation( Model model )
381     {
382         Relocation relocation = null;
383         DistributionManagement distMngt = model.getDistributionManagement();
384         if ( distMngt != null )
385         {
386             relocation = distMngt.getRelocation();
387         }
388         return relocation;
389     }
390 
391     private void missingDescriptor( RepositorySystemSession session, RequestTrace trace, Artifact artifact,
392                                     Exception exception )
393     {
394         RepositoryEvent.Builder event = new RepositoryEvent.Builder( session, EventType.ARTIFACT_DESCRIPTOR_MISSING );
395         event.setTrace( trace );
396         event.setArtifact( artifact );
397         event.setException( exception );
398 
399         repositoryEventDispatcher.dispatch( event.build() );
400     }
401 
402     private void invalidDescriptor( RepositorySystemSession session, RequestTrace trace, Artifact artifact,
403                                     Exception exception )
404     {
405         RepositoryEvent.Builder event = new RepositoryEvent.Builder( session, EventType.ARTIFACT_DESCRIPTOR_INVALID );
406         event.setTrace( trace );
407         event.setArtifact( artifact );
408         event.setException( exception );
409 
410         repositoryEventDispatcher.dispatch( event.build() );
411     }
412 
413     private int getPolicy( RepositorySystemSession session, Artifact a, ArtifactDescriptorRequest request )
414     {
415         ArtifactDescriptorPolicy policy = session.getArtifactDescriptorPolicy();
416         if ( policy == null )
417         {
418             return ArtifactDescriptorPolicy.STRICT;
419         }
420         return policy.getPolicy( session, new ArtifactDescriptorPolicyRequest( a, request.getRequestContext() ) );
421     }
422 
423 }