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