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.maven.model.DistributionManagement; 031import org.apache.maven.model.Model; 032import org.apache.maven.model.Relocation; 033import org.apache.maven.model.building.DefaultModelBuilderFactory; 034import org.apache.maven.model.building.DefaultModelBuildingRequest; 035import org.apache.maven.model.building.FileModelSource; 036import org.apache.maven.model.building.ModelBuilder; 037import org.apache.maven.model.building.ModelBuildingException; 038import org.apache.maven.model.building.ModelBuildingRequest; 039import org.apache.maven.model.building.ModelProblem; 040import org.apache.maven.model.resolution.UnresolvableModelException; 041import org.codehaus.plexus.component.annotations.Component; 042import org.codehaus.plexus.component.annotations.Requirement; 043import org.eclipse.aether.RepositoryEvent; 044import org.eclipse.aether.RepositoryEvent.EventType; 045import org.eclipse.aether.RepositoryException; 046import org.eclipse.aether.RepositorySystemSession; 047import org.eclipse.aether.RequestTrace; 048import org.eclipse.aether.artifact.Artifact; 049import org.eclipse.aether.impl.ArtifactDescriptorReader; 050import org.eclipse.aether.impl.ArtifactResolver; 051import org.eclipse.aether.impl.RemoteRepositoryManager; 052import org.eclipse.aether.impl.RepositoryEventDispatcher; 053import org.eclipse.aether.impl.VersionRangeResolver; 054import org.eclipse.aether.impl.VersionResolver; 055import org.eclipse.aether.repository.WorkspaceReader; 056import org.eclipse.aether.repository.WorkspaceRepository; 057import org.eclipse.aether.resolution.ArtifactDescriptorException; 058import org.eclipse.aether.resolution.ArtifactDescriptorPolicy; 059import org.eclipse.aether.resolution.ArtifactDescriptorPolicyRequest; 060import org.eclipse.aether.resolution.ArtifactDescriptorRequest; 061import org.eclipse.aether.resolution.ArtifactDescriptorResult; 062import org.eclipse.aether.resolution.ArtifactRequest; 063import org.eclipse.aether.resolution.ArtifactResolutionException; 064import org.eclipse.aether.resolution.ArtifactResult; 065import org.eclipse.aether.resolution.VersionRequest; 066import org.eclipse.aether.resolution.VersionResolutionException; 067import org.eclipse.aether.resolution.VersionResult; 068import org.eclipse.aether.spi.locator.Service; 069import org.eclipse.aether.spi.locator.ServiceLocator; 070import org.eclipse.aether.spi.log.Logger; 071import org.eclipse.aether.spi.log.LoggerFactory; 072import org.eclipse.aether.spi.log.NullLoggerFactory; 073import org.eclipse.aether.transfer.ArtifactNotFoundException; 074 075/** 076 * @author Benjamin Bentmann 077 */ 078@Named 079@Component( role = ArtifactDescriptorReader.class ) 080public class DefaultArtifactDescriptorReader 081 implements ArtifactDescriptorReader, Service 082{ 083 084 @SuppressWarnings( "unused" ) 085 @Requirement( role = LoggerFactory.class ) 086 private Logger logger = NullLoggerFactory.LOGGER; 087 088 @Requirement 089 private RemoteRepositoryManager remoteRepositoryManager; 090 091 @Requirement 092 private VersionResolver versionResolver; 093 094 @Requirement 095 private VersionRangeResolver versionRangeResolver; 096 097 @Requirement 098 private ArtifactResolver artifactResolver; 099 100 @Requirement 101 private RepositoryEventDispatcher repositoryEventDispatcher; 102 103 @Requirement 104 private ModelBuilder modelBuilder; 105 106 public DefaultArtifactDescriptorReader() 107 { 108 // enable no-arg constructor 109 } 110 111 @Inject 112 DefaultArtifactDescriptorReader( RemoteRepositoryManager remoteRepositoryManager, VersionResolver versionResolver, 113 ArtifactResolver artifactResolver, ModelBuilder modelBuilder, 114 RepositoryEventDispatcher repositoryEventDispatcher, LoggerFactory loggerFactory ) 115 { 116 setRemoteRepositoryManager( remoteRepositoryManager ); 117 setVersionResolver( versionResolver ); 118 setArtifactResolver( artifactResolver ); 119 setModelBuilder( modelBuilder ); 120 setLoggerFactory( loggerFactory ); 121 setRepositoryEventDispatcher( repositoryEventDispatcher ); 122 } 123 124 public void initService( ServiceLocator locator ) 125 { 126 setLoggerFactory( locator.getService( LoggerFactory.class ) ); 127 setRemoteRepositoryManager( locator.getService( RemoteRepositoryManager.class ) ); 128 setVersionResolver( locator.getService( VersionResolver.class ) ); 129 setVersionRangeResolver( locator.getService( VersionRangeResolver.class ) ); 130 setArtifactResolver( locator.getService( ArtifactResolver.class ) ); 131 setRepositoryEventDispatcher( locator.getService( RepositoryEventDispatcher.class ) ); 132 modelBuilder = locator.getService( ModelBuilder.class ); 133 if ( modelBuilder == null ) 134 { 135 setModelBuilder( new DefaultModelBuilderFactory().newInstance() ); 136 } 137 } 138 139 public DefaultArtifactDescriptorReader setLoggerFactory( LoggerFactory loggerFactory ) 140 { 141 this.logger = NullLoggerFactory.getSafeLogger( loggerFactory, getClass() ); 142 return this; 143 } 144 145 void setLogger( LoggerFactory loggerFactory ) 146 { 147 // plexus support 148 setLoggerFactory( loggerFactory ); 149 } 150 151 public DefaultArtifactDescriptorReader setRemoteRepositoryManager( RemoteRepositoryManager remoteRepositoryManager ) 152 { 153 if ( remoteRepositoryManager == null ) 154 { 155 throw new IllegalArgumentException( "remote repository manager has not been specified" ); 156 } 157 this.remoteRepositoryManager = remoteRepositoryManager; 158 return this; 159 } 160 161 public DefaultArtifactDescriptorReader setVersionResolver( VersionResolver versionResolver ) 162 { 163 if ( versionResolver == null ) 164 { 165 throw new IllegalArgumentException( "version resolver has not been specified" ); 166 } 167 this.versionResolver = versionResolver; 168 return this; 169 } 170 171 /** @since 3.2.2 */ 172 public DefaultArtifactDescriptorReader setVersionRangeResolver( VersionRangeResolver versionRangeResolver ) 173 { 174 if ( versionRangeResolver == null ) 175 { 176 throw new IllegalArgumentException( "version range resolver has not been specified" ); 177 } 178 this.versionRangeResolver = versionRangeResolver; 179 return this; 180 } 181 182 public DefaultArtifactDescriptorReader setArtifactResolver( ArtifactResolver artifactResolver ) 183 { 184 if ( artifactResolver == null ) 185 { 186 throw new IllegalArgumentException( "artifact resolver has not been specified" ); 187 } 188 this.artifactResolver = artifactResolver; 189 return this; 190 } 191 192 public DefaultArtifactDescriptorReader setRepositoryEventDispatcher( RepositoryEventDispatcher red ) 193 { 194 if ( red == null ) 195 { 196 throw new IllegalArgumentException( "repository event dispatcher has not been specified" ); 197 } 198 this.repositoryEventDispatcher = red; 199 return this; 200 } 201 202 public DefaultArtifactDescriptorReader setModelBuilder( ModelBuilder modelBuilder ) 203 { 204 if ( modelBuilder == null ) 205 { 206 throw new IllegalArgumentException( "model builder has not been specified" ); 207 } 208 this.modelBuilder = modelBuilder; 209 return this; 210 } 211 212 public ArtifactDescriptorResult readArtifactDescriptor( RepositorySystemSession session, 213 ArtifactDescriptorRequest request ) 214 throws ArtifactDescriptorException 215 { 216 ArtifactDescriptorResult result = new ArtifactDescriptorResult( request ); 217 218 Model model = loadPom( session, request, result ); 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 307 // hack: don't rebuild model if it was already loaded during reactor resolution 308 final WorkspaceReader workspace = session.getWorkspaceReader(); 309 if ( workspace instanceof MavenWorkspaceReader ) 310 { 311 model = ( (MavenWorkspaceReader) workspace ).findModel( pomArtifact ); 312 if ( model != null ) 313 { 314 return model; 315 } 316 } 317 318 try 319 { 320 ModelBuildingRequest modelRequest = new DefaultModelBuildingRequest(); 321 modelRequest.setValidationLevel( ModelBuildingRequest.VALIDATION_LEVEL_MINIMAL ); 322 modelRequest.setProcessPlugins( false ); 323 modelRequest.setTwoPhaseBuilding( false ); 324 modelRequest.setSystemProperties( toProperties( session.getUserProperties(), 325 session.getSystemProperties() ) ); 326 modelRequest.setModelCache( DefaultModelCache.newInstance( session ) ); 327 modelRequest.setModelResolver( new DefaultModelResolver( session, trace.newChild( modelRequest ), 328 request.getRequestContext(), artifactResolver, 329 versionRangeResolver, remoteRepositoryManager, 330 request.getRepositories() ) ); 331 if ( resolveResult.getRepository() instanceof WorkspaceRepository ) 332 { 333 modelRequest.setPomFile( pomArtifact.getFile() ); 334 } 335 else 336 { 337 modelRequest.setModelSource( new FileModelSource( pomArtifact.getFile() ) ); 338 } 339 340 model = modelBuilder.build( modelRequest ).getEffectiveModel(); 341 } 342 catch ( ModelBuildingException e ) 343 { 344 for ( ModelProblem problem : e.getProblems() ) 345 { 346 if ( problem.getException() instanceof UnresolvableModelException ) 347 { 348 result.addException( problem.getException() ); 349 throw new ArtifactDescriptorException( result ); 350 } 351 } 352 invalidDescriptor( session, trace, a, e ); 353 if ( ( getPolicy( session, a, request ) & ArtifactDescriptorPolicy.IGNORE_INVALID ) != 0 ) 354 { 355 return null; 356 } 357 result.addException( e ); 358 throw new ArtifactDescriptorException( result ); 359 } 360 361 Relocation relocation = getRelocation( model ); 362 363 if ( relocation != null ) 364 { 365 result.addRelocation( a ); 366 a = 367 new RelocatedArtifact( a, relocation.getGroupId(), relocation.getArtifactId(), 368 relocation.getVersion() ); 369 result.setArtifact( a ); 370 } 371 else 372 { 373 return model; 374 } 375 } 376 } 377 378 private Properties toProperties( Map<String, String> dominant, Map<String, String> recessive ) 379 { 380 Properties props = new Properties(); 381 if ( recessive != null ) 382 { 383 props.putAll( recessive ); 384 } 385 if ( dominant != null ) 386 { 387 props.putAll( dominant ); 388 } 389 return props; 390 } 391 392 private Relocation getRelocation( Model model ) 393 { 394 Relocation relocation = null; 395 DistributionManagement distMngt = model.getDistributionManagement(); 396 if ( distMngt != null ) 397 { 398 relocation = distMngt.getRelocation(); 399 } 400 return relocation; 401 } 402 403 private void missingDescriptor( RepositorySystemSession session, RequestTrace trace, Artifact artifact, 404 Exception exception ) 405 { 406 RepositoryEvent.Builder event = new RepositoryEvent.Builder( session, EventType.ARTIFACT_DESCRIPTOR_MISSING ); 407 event.setTrace( trace ); 408 event.setArtifact( artifact ); 409 event.setException( exception ); 410 411 repositoryEventDispatcher.dispatch( event.build() ); 412 } 413 414 private void invalidDescriptor( RepositorySystemSession session, RequestTrace trace, Artifact artifact, 415 Exception exception ) 416 { 417 RepositoryEvent.Builder event = new RepositoryEvent.Builder( session, EventType.ARTIFACT_DESCRIPTOR_INVALID ); 418 event.setTrace( trace ); 419 event.setArtifact( artifact ); 420 event.setException( exception ); 421 422 repositoryEventDispatcher.dispatch( event.build() ); 423 } 424 425 private int getPolicy( RepositorySystemSession session, Artifact a, ArtifactDescriptorRequest request ) 426 { 427 ArtifactDescriptorPolicy policy = session.getArtifactDescriptorPolicy(); 428 if ( policy == null ) 429 { 430 return ArtifactDescriptorPolicy.STRICT; 431 } 432 return policy.getPolicy( session, new ArtifactDescriptorPolicyRequest( a, request.getRequestContext() ) ); 433 } 434 435}