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