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