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.ArtifactModelSource;
36  import org.apache.maven.model.building.DefaultModelBuildingRequest;
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.eclipse.aether.RepositoryEvent;
43  import org.eclipse.aether.RepositoryEvent.EventType;
44  import org.eclipse.aether.RepositoryException;
45  import org.eclipse.aether.RepositorySystemSession;
46  import org.eclipse.aether.RequestTrace;
47  import org.eclipse.aether.artifact.Artifact;
48  import org.eclipse.aether.impl.ArtifactDescriptorReader;
49  import org.eclipse.aether.impl.ArtifactResolver;
50  import org.eclipse.aether.impl.RemoteRepositoryManager;
51  import org.eclipse.aether.impl.RepositoryEventDispatcher;
52  import org.eclipse.aether.impl.VersionRangeResolver;
53  import org.eclipse.aether.impl.VersionResolver;
54  import org.eclipse.aether.repository.WorkspaceReader;
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.transfer.ArtifactNotFoundException;
68  import org.slf4j.Logger;
69  import org.slf4j.LoggerFactory;
70  
71  /**
72   * @author Benjamin Bentmann
73   */
74  @Named
75  @Singleton
76  public class DefaultArtifactDescriptorReader implements ArtifactDescriptorReader
77  {
78      private static final Logger LOGGER = LoggerFactory.getLogger( DefaultArtifactDescriptorReader.class );
79  
80      private final RemoteRepositoryManager remoteRepositoryManager;
81      private final VersionResolver versionResolver;
82      private final VersionRangeResolver versionRangeResolver;
83      private final ArtifactResolver artifactResolver;
84      private final RepositoryEventDispatcher repositoryEventDispatcher;
85      private final ModelBuilder modelBuilder;
86      private final ModelCacheFactory modelCacheFactory;
87  
88      @Inject
89      public DefaultArtifactDescriptorReader(
90              RemoteRepositoryManager remoteRepositoryManager,
91              VersionResolver versionResolver,
92              VersionRangeResolver versionRangeResolver,
93              ArtifactResolver artifactResolver,
94              ModelBuilder modelBuilder,
95              RepositoryEventDispatcher repositoryEventDispatcher,
96              ModelCacheFactory modelCacheFactory )
97      {
98          this.remoteRepositoryManager = Objects.requireNonNull( remoteRepositoryManager,
99                  "remoteRepositoryManager cannot be null" );
100         this.versionResolver = Objects.requireNonNull( versionResolver, "versionResolver cannot be null" );
101         this.versionRangeResolver =
102                 Objects.requireNonNull( versionRangeResolver, "versionRangeResolver cannot be null" );
103         this.artifactResolver = Objects.requireNonNull( artifactResolver, "artifactResolver cannot be null" );
104         this.modelBuilder = Objects.requireNonNull( modelBuilder, "modelBuilder cannot be null" );
105         this.repositoryEventDispatcher = Objects.requireNonNull( repositoryEventDispatcher,
106                 "repositoryEventDispatcher cannot be null" );
107         this.modelCacheFactory = Objects.requireNonNull( modelCacheFactory,
108                 "modelCacheFactory cannot be null" );
109     }
110 
111     public ArtifactDescriptorResult readArtifactDescriptor( RepositorySystemSession session,
112                                                             ArtifactDescriptorRequest request )
113         throws ArtifactDescriptorException
114     {
115         ArtifactDescriptorResult result = new ArtifactDescriptorResult( request );
116 
117         Model model = loadPom( session, request, result );
118         if ( model != null )
119         {
120             Map<String, Object> config = session.getConfigProperties();
121             ArtifactDescriptorReaderDelegate delegate =
122                 (ArtifactDescriptorReaderDelegate) config.get( ArtifactDescriptorReaderDelegate.class.getName() );
123 
124             if ( delegate == null )
125             {
126                 delegate = new ArtifactDescriptorReaderDelegate();
127             }
128 
129             delegate.populateResult( session, result, model );
130         }
131 
132         return result;
133     }
134 
135     private Model loadPom( RepositorySystemSession session, ArtifactDescriptorRequest request,
136                            ArtifactDescriptorResult result )
137         throws ArtifactDescriptorException
138     {
139         RequestTrace trace = RequestTrace.newChild( request.getTrace(), request );
140 
141         Set<String> visited = new LinkedHashSet<>();
142         for ( Artifact a = request.getArtifact();; )
143         {
144             Artifact pomArtifact = ArtifactDescriptorUtils.toPomArtifact( a );
145             try
146             {
147                 VersionRequest versionRequest =
148                     new VersionRequest( a, request.getRepositories(), request.getRequestContext() );
149                 versionRequest.setTrace( trace );
150                 VersionResult versionResult = versionResolver.resolveVersion( session, versionRequest );
151 
152                 a = a.setVersion( versionResult.getVersion() );
153 
154                 versionRequest =
155                     new VersionRequest( pomArtifact, request.getRepositories(), request.getRequestContext() );
156                 versionRequest.setTrace( trace );
157                 versionResult = versionResolver.resolveVersion( session, versionRequest );
158 
159                 pomArtifact = pomArtifact.setVersion( versionResult.getVersion() );
160             }
161             catch ( VersionResolutionException e )
162             {
163                 result.addException( e );
164                 throw new ArtifactDescriptorException( result );
165             }
166 
167             if ( !visited.add( a.getGroupId() + ':' + a.getArtifactId() + ':' + a.getBaseVersion() ) )
168             {
169                 RepositoryException exception =
170                     new RepositoryException( "Artifact relocations form a cycle: " + visited );
171                 invalidDescriptor( session, trace, a, exception );
172                 if ( ( getPolicy( session, a, request ) & ArtifactDescriptorPolicy.IGNORE_INVALID ) != 0 )
173                 {
174                     return null;
175                 }
176                 result.addException( exception );
177                 throw new ArtifactDescriptorException( result );
178             }
179 
180             ArtifactResult resolveResult;
181             try
182             {
183                 ArtifactRequest resolveRequest =
184                     new ArtifactRequest( pomArtifact, request.getRepositories(), request.getRequestContext() );
185                 resolveRequest.setTrace( trace );
186                 resolveResult = artifactResolver.resolveArtifact( session, resolveRequest );
187                 pomArtifact = resolveResult.getArtifact();
188                 result.setRepository( resolveResult.getRepository() );
189             }
190             catch ( ArtifactResolutionException e )
191             {
192                 if ( e.getCause() instanceof ArtifactNotFoundException )
193                 {
194                     missingDescriptor( session, trace, a, (Exception) e.getCause() );
195                     if ( ( getPolicy( session, a, request ) & ArtifactDescriptorPolicy.IGNORE_MISSING ) != 0 )
196                     {
197                         return null;
198                     }
199                 }
200                 result.addException( e );
201                 throw new ArtifactDescriptorException( result );
202             }
203 
204             Model model;
205 
206             // TODO hack: don't rebuild model if it was already loaded during reactor resolution
207             final WorkspaceReader workspace = session.getWorkspaceReader();
208             if ( workspace instanceof MavenWorkspaceReader )
209             {
210                 model = ( (MavenWorkspaceReader) workspace ).findModel( pomArtifact );
211                 if ( model != null )
212                 {
213                     return model;
214                 }
215             }
216 
217             try
218             {
219                 ModelBuildingRequest modelRequest = new DefaultModelBuildingRequest();
220                 modelRequest.setValidationLevel( ModelBuildingRequest.VALIDATION_LEVEL_MINIMAL );
221                 modelRequest.setProcessPlugins( false );
222                 modelRequest.setTwoPhaseBuilding( false );
223                 modelRequest.setSystemProperties( toProperties( session.getSystemProperties() ) );
224                 modelRequest.setUserProperties( toProperties( session.getUserProperties() ) );
225                 modelRequest.setModelCache( modelCacheFactory.createCache( session ) );
226                 modelRequest.setModelResolver( new DefaultModelResolver( session, trace.newChild( modelRequest ),
227                                                                          request.getRequestContext(), artifactResolver,
228                                                                          versionRangeResolver, remoteRepositoryManager,
229                                                                          request.getRepositories() ) );
230                 if ( resolveResult.getRepository() instanceof WorkspaceRepository )
231                 {
232                     modelRequest.setPomFile( pomArtifact.getFile() );
233                 }
234                 else
235                 {
236                     modelRequest.setModelSource( new ArtifactModelSource( pomArtifact.getFile(),
237                                                                           pomArtifact.getGroupId(),
238                                                                           pomArtifact.getArtifactId(),
239                                                                           pomArtifact.getVersion() ) );
240                 }
241 
242                 model = modelBuilder.build( modelRequest ).getEffectiveModel();
243             }
244             catch ( ModelBuildingException e )
245             {
246                 for ( ModelProblem problem : e.getProblems() )
247                 {
248                     if ( problem.getException() instanceof UnresolvableModelException )
249                     {
250                         result.addException( problem.getException() );
251                         throw new ArtifactDescriptorException( result );
252                     }
253                 }
254                 invalidDescriptor( session, trace, a, e );
255                 if ( ( getPolicy( session, a, request ) & ArtifactDescriptorPolicy.IGNORE_INVALID ) != 0 )
256                 {
257                     return null;
258                 }
259                 result.addException( e );
260                 throw new ArtifactDescriptorException( result );
261             }
262 
263             Relocation relocation = getRelocation( model );
264 
265             if ( relocation != null )
266             {
267                 result.addRelocation( a );
268                 a =
269                     new RelocatedArtifact( a, relocation.getGroupId(), relocation.getArtifactId(),
270                                            relocation.getVersion(), relocation.getMessage() );
271                 result.setArtifact( a );
272             }
273             else
274             {
275                 return model;
276             }
277         }
278     }
279 
280     private Properties toProperties( Map<String, String> map )
281     {
282         Properties props = new Properties();
283         props.putAll( map );
284         return props;
285     }
286 
287     private Relocation getRelocation( Model model )
288     {
289         Relocation relocation = null;
290         DistributionManagement distMgmt = model.getDistributionManagement();
291         if ( distMgmt != null )
292         {
293             relocation = distMgmt.getRelocation();
294         }
295         return relocation;
296     }
297 
298     private void missingDescriptor( RepositorySystemSession session, RequestTrace trace, Artifact artifact,
299                                     Exception exception )
300     {
301         RepositoryEvent.Builder event = new RepositoryEvent.Builder( session, EventType.ARTIFACT_DESCRIPTOR_MISSING );
302         event.setTrace( trace );
303         event.setArtifact( artifact );
304         event.setException( exception );
305 
306         repositoryEventDispatcher.dispatch( event.build() );
307     }
308 
309     private void invalidDescriptor( RepositorySystemSession session, RequestTrace trace, Artifact artifact,
310                                     Exception exception )
311     {
312         RepositoryEvent.Builder event = new RepositoryEvent.Builder( session, EventType.ARTIFACT_DESCRIPTOR_INVALID );
313         event.setTrace( trace );
314         event.setArtifact( artifact );
315         event.setException( exception );
316 
317         repositoryEventDispatcher.dispatch( event.build() );
318     }
319 
320     private int getPolicy( RepositorySystemSession session, Artifact a, ArtifactDescriptorRequest request )
321     {
322         ArtifactDescriptorPolicy policy = session.getArtifactDescriptorPolicy();
323         if ( policy == null )
324         {
325             return ArtifactDescriptorPolicy.STRICT;
326         }
327         return policy.getPolicy( session, new ArtifactDescriptorPolicyRequest( a, request.getRequestContext() ) );
328     }
329 
330 }