001package org.apache.maven.repository.internal; 002 003/* 004 * Licensed to the Apache Software Foundation (ASF) under one 005 * or more contributor license agreements. See the NOTICE file 006 * distributed with this work for additional information 007 * regarding copyright ownership. The ASF licenses this file 008 * to you under the Apache License, Version 2.0 (the 009 * "License"); you may not use this file except in compliance 010 * with the License. You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, 015 * software distributed under the License is distributed on an 016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 017 * KIND, either express or implied. See the License for the 018 * specific language governing permissions and limitations 019 * under the License. 020 */ 021 022import java.util.LinkedHashSet; 023import java.util.Map; 024import java.util.Properties; 025import java.util.Set; 026 027import javax.inject.Inject; 028import javax.inject.Named; 029 030import org.apache.commons.lang3.Validate; 031import org.apache.maven.model.DistributionManagement; 032import org.apache.maven.model.Model; 033import org.apache.maven.model.Relocation; 034import org.apache.maven.model.building.DefaultModelBuilderFactory; 035import org.apache.maven.model.building.DefaultModelBuildingRequest; 036import org.apache.maven.model.building.FileModelSource; 037import org.apache.maven.model.building.ModelBuilder; 038import org.apache.maven.model.building.ModelBuildingException; 039import org.apache.maven.model.building.ModelBuildingRequest; 040import org.apache.maven.model.building.ModelProblem; 041import org.apache.maven.model.resolution.UnresolvableModelException; 042import org.codehaus.plexus.component.annotations.Component; 043import org.codehaus.plexus.component.annotations.Requirement; 044import org.eclipse.aether.RepositoryEvent; 045import org.eclipse.aether.RepositoryEvent.EventType; 046import org.eclipse.aether.RepositoryException; 047import org.eclipse.aether.RepositorySystemSession; 048import org.eclipse.aether.RequestTrace; 049import org.eclipse.aether.artifact.Artifact; 050import org.eclipse.aether.impl.ArtifactDescriptorReader; 051import org.eclipse.aether.impl.ArtifactResolver; 052import org.eclipse.aether.impl.RemoteRepositoryManager; 053import org.eclipse.aether.impl.RepositoryEventDispatcher; 054import org.eclipse.aether.impl.VersionRangeResolver; 055import org.eclipse.aether.impl.VersionResolver; 056import org.eclipse.aether.repository.WorkspaceReader; 057import org.eclipse.aether.repository.WorkspaceRepository; 058import org.eclipse.aether.resolution.ArtifactDescriptorException; 059import org.eclipse.aether.resolution.ArtifactDescriptorPolicy; 060import org.eclipse.aether.resolution.ArtifactDescriptorPolicyRequest; 061import org.eclipse.aether.resolution.ArtifactDescriptorRequest; 062import org.eclipse.aether.resolution.ArtifactDescriptorResult; 063import org.eclipse.aether.resolution.ArtifactRequest; 064import org.eclipse.aether.resolution.ArtifactResolutionException; 065import org.eclipse.aether.resolution.ArtifactResult; 066import org.eclipse.aether.resolution.VersionRequest; 067import org.eclipse.aether.resolution.VersionResolutionException; 068import org.eclipse.aether.resolution.VersionResult; 069import org.eclipse.aether.spi.locator.Service; 070import org.eclipse.aether.spi.locator.ServiceLocator; 071import org.eclipse.aether.spi.log.Logger; 072import org.eclipse.aether.spi.log.LoggerFactory; 073import org.eclipse.aether.spi.log.NullLoggerFactory; 074import org.eclipse.aether.transfer.ArtifactNotFoundException; 075 076/** 077 * @author Benjamin Bentmann 078 */ 079@Named 080@Component( role = ArtifactDescriptorReader.class ) 081public class DefaultArtifactDescriptorReader 082 implements ArtifactDescriptorReader, Service 083{ 084 085 @SuppressWarnings( "unused" ) 086 @Requirement( role = LoggerFactory.class ) 087 private Logger logger = NullLoggerFactory.LOGGER; 088 089 @Requirement 090 private RemoteRepositoryManager remoteRepositoryManager; 091 092 @Requirement 093 private VersionResolver versionResolver; 094 095 @Requirement 096 private VersionRangeResolver versionRangeResolver; 097 098 @Requirement 099 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}