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.ArrayList; 023import java.util.Collections; 024import java.util.HashMap; 025import java.util.LinkedHashMap; 026import java.util.LinkedHashSet; 027import java.util.List; 028import java.util.Map; 029import java.util.Properties; 030import java.util.Set; 031import javax.inject.Inject; 032import javax.inject.Named; 033import org.apache.maven.model.DependencyManagement; 034import org.apache.maven.model.DistributionManagement; 035import org.apache.maven.model.License; 036import org.apache.maven.model.Model; 037import org.apache.maven.model.Prerequisites; 038import org.apache.maven.model.Relocation; 039import org.apache.maven.model.Repository; 040import org.apache.maven.model.building.DefaultModelBuilderFactory; 041import org.apache.maven.model.building.DefaultModelBuildingRequest; 042import org.apache.maven.model.building.FileModelSource; 043import org.apache.maven.model.building.ModelBuilder; 044import org.apache.maven.model.building.ModelBuildingException; 045import org.apache.maven.model.building.ModelBuildingRequest; 046import org.apache.maven.model.building.ModelProblem; 047import org.apache.maven.model.resolution.UnresolvableModelException; 048import org.codehaus.plexus.component.annotations.Component; 049import org.codehaus.plexus.component.annotations.Requirement; 050import org.eclipse.aether.RepositoryEvent; 051import org.eclipse.aether.RepositoryEvent.EventType; 052import org.eclipse.aether.RepositoryException; 053import org.eclipse.aether.RepositorySystemSession; 054import org.eclipse.aether.RequestTrace; 055import org.eclipse.aether.artifact.Artifact; 056import org.eclipse.aether.artifact.ArtifactProperties; 057import org.eclipse.aether.artifact.ArtifactType; 058import org.eclipse.aether.artifact.ArtifactTypeRegistry; 059import org.eclipse.aether.artifact.DefaultArtifact; 060import org.eclipse.aether.artifact.DefaultArtifactType; 061import org.eclipse.aether.graph.Dependency; 062import org.eclipse.aether.graph.Exclusion; 063import org.eclipse.aether.impl.ArtifactDescriptorReader; 064import org.eclipse.aether.impl.ArtifactResolver; 065import org.eclipse.aether.impl.RemoteRepositoryManager; 066import org.eclipse.aether.impl.RepositoryEventDispatcher; 067import org.eclipse.aether.impl.VersionRangeResolver; 068import org.eclipse.aether.impl.VersionResolver; 069import org.eclipse.aether.repository.WorkspaceRepository; 070import org.eclipse.aether.resolution.ArtifactDescriptorException; 071import org.eclipse.aether.resolution.ArtifactDescriptorPolicy; 072import org.eclipse.aether.resolution.ArtifactDescriptorPolicyRequest; 073import org.eclipse.aether.resolution.ArtifactDescriptorRequest; 074import org.eclipse.aether.resolution.ArtifactDescriptorResult; 075import org.eclipse.aether.resolution.ArtifactRequest; 076import org.eclipse.aether.resolution.ArtifactResolutionException; 077import org.eclipse.aether.resolution.ArtifactResult; 078import org.eclipse.aether.resolution.VersionRequest; 079import org.eclipse.aether.resolution.VersionResolutionException; 080import org.eclipse.aether.resolution.VersionResult; 081import org.eclipse.aether.spi.locator.Service; 082import org.eclipse.aether.spi.locator.ServiceLocator; 083import org.eclipse.aether.spi.log.Logger; 084import org.eclipse.aether.spi.log.LoggerFactory; 085import org.eclipse.aether.spi.log.NullLoggerFactory; 086import org.eclipse.aether.transfer.ArtifactNotFoundException; 087 088/** 089 * @author Benjamin Bentmann 090 */ 091@Named 092@Component( role = ArtifactDescriptorReader.class ) 093public class DefaultArtifactDescriptorReader 094 implements ArtifactDescriptorReader, Service 095{ 096 097 @SuppressWarnings( "unused" ) 098 @Requirement( role = LoggerFactory.class ) 099 private Logger logger = NullLoggerFactory.LOGGER; 100 101 @Requirement 102 private RemoteRepositoryManager remoteRepositoryManager; 103 104 @Requirement 105 private VersionResolver versionResolver; 106 107 @Requirement 108 private VersionRangeResolver versionRangeResolver; 109 110 @Requirement 111 private ArtifactResolver artifactResolver; 112 113 @Requirement 114 private RepositoryEventDispatcher repositoryEventDispatcher; 115 116 @Requirement 117 private ModelBuilder modelBuilder; 118 119 public DefaultArtifactDescriptorReader() 120 { 121 // enable no-arg constructor 122 } 123 124 @Inject 125 DefaultArtifactDescriptorReader( RemoteRepositoryManager remoteRepositoryManager, VersionResolver versionResolver, 126 ArtifactResolver artifactResolver, ModelBuilder modelBuilder, 127 RepositoryEventDispatcher repositoryEventDispatcher, LoggerFactory loggerFactory ) 128 { 129 setRemoteRepositoryManager( remoteRepositoryManager ); 130 setVersionResolver( versionResolver ); 131 setArtifactResolver( artifactResolver ); 132 setModelBuilder( modelBuilder ); 133 setLoggerFactory( loggerFactory ); 134 setRepositoryEventDispatcher( repositoryEventDispatcher ); 135 } 136 137 public void initService( ServiceLocator locator ) 138 { 139 setLoggerFactory( locator.getService( LoggerFactory.class ) ); 140 setRemoteRepositoryManager( locator.getService( RemoteRepositoryManager.class ) ); 141 setVersionResolver( locator.getService( VersionResolver.class ) ); 142 setVersionRangeResolver( locator.getService( VersionRangeResolver.class ) ); 143 setArtifactResolver( locator.getService( ArtifactResolver.class ) ); 144 setRepositoryEventDispatcher( locator.getService( RepositoryEventDispatcher.class ) ); 145 modelBuilder = locator.getService( ModelBuilder.class ); 146 if ( modelBuilder == null ) 147 { 148 setModelBuilder( new DefaultModelBuilderFactory().newInstance() ); 149 } 150 } 151 152 public DefaultArtifactDescriptorReader setLoggerFactory( LoggerFactory loggerFactory ) 153 { 154 this.logger = NullLoggerFactory.getSafeLogger( loggerFactory, getClass() ); 155 return this; 156 } 157 158 void setLogger( LoggerFactory loggerFactory ) 159 { 160 // plexus support 161 setLoggerFactory( loggerFactory ); 162 } 163 164 public DefaultArtifactDescriptorReader setRemoteRepositoryManager( RemoteRepositoryManager remoteRepositoryManager ) 165 { 166 if ( remoteRepositoryManager == null ) 167 { 168 throw new IllegalArgumentException( "remote repository manager has not been specified" ); 169 } 170 this.remoteRepositoryManager = remoteRepositoryManager; 171 return this; 172 } 173 174 public DefaultArtifactDescriptorReader setVersionResolver( VersionResolver versionResolver ) 175 { 176 if ( versionResolver == null ) 177 { 178 throw new IllegalArgumentException( "version resolver has not been specified" ); 179 } 180 this.versionResolver = versionResolver; 181 return this; 182 } 183 184 /** @since 3.2.2 */ 185 public DefaultArtifactDescriptorReader setVersionRangeResolver( VersionRangeResolver versionRangeResolver ) 186 { 187 if ( versionRangeResolver == null ) 188 { 189 throw new IllegalArgumentException( "version range resolver has not been specified" ); 190 } 191 this.versionRangeResolver = versionRangeResolver; 192 return this; 193 } 194 195 public DefaultArtifactDescriptorReader setArtifactResolver( ArtifactResolver artifactResolver ) 196 { 197 if ( artifactResolver == null ) 198 { 199 throw new IllegalArgumentException( "artifact resolver has not been specified" ); 200 } 201 this.artifactResolver = artifactResolver; 202 return this; 203 } 204 205 public DefaultArtifactDescriptorReader setRepositoryEventDispatcher( RepositoryEventDispatcher repositoryEventDispatcher ) 206 { 207 if ( repositoryEventDispatcher == null ) 208 { 209 throw new IllegalArgumentException( "repository event dispatcher has not been specified" ); 210 } 211 this.repositoryEventDispatcher = repositoryEventDispatcher; 212 return this; 213 } 214 215 public DefaultArtifactDescriptorReader setModelBuilder( ModelBuilder modelBuilder ) 216 { 217 if ( modelBuilder == null ) 218 { 219 throw new IllegalArgumentException( "model builder has not been specified" ); 220 } 221 this.modelBuilder = modelBuilder; 222 return this; 223 } 224 225 public ArtifactDescriptorResult readArtifactDescriptor( RepositorySystemSession session, 226 ArtifactDescriptorRequest request ) 227 throws ArtifactDescriptorException 228 { 229 ArtifactDescriptorResult result = new ArtifactDescriptorResult( request ); 230 231 Model model = loadPom( session, request, result ); 232 233 if ( model != null ) 234 { 235 ArtifactTypeRegistry stereotypes = session.getArtifactTypeRegistry(); 236 237 for ( Repository r : model.getRepositories() ) 238 { 239 result.addRepository( ArtifactDescriptorUtils.toRemoteRepository( r ) ); 240 } 241 242 for ( org.apache.maven.model.Dependency dependency : model.getDependencies() ) 243 { 244 result.addDependency( convert( dependency, stereotypes ) ); 245 } 246 247 DependencyManagement mngt = model.getDependencyManagement(); 248 if ( mngt != null ) 249 { 250 for ( org.apache.maven.model.Dependency dependency : mngt.getDependencies() ) 251 { 252 result.addManagedDependency( convert( dependency, stereotypes ) ); 253 } 254 } 255 256 Map<String, Object> properties = new LinkedHashMap<String, Object>(); 257 258 Prerequisites prerequisites = model.getPrerequisites(); 259 if ( prerequisites != null ) 260 { 261 properties.put( "prerequisites.maven", prerequisites.getMaven() ); 262 } 263 264 List<License> licenses = model.getLicenses(); 265 properties.put( "license.count", licenses.size() ); 266 for ( int i = 0; i < licenses.size(); i++ ) 267 { 268 License license = licenses.get( i ); 269 properties.put( "license." + i + ".name", license.getName() ); 270 properties.put( "license." + i + ".url", license.getUrl() ); 271 properties.put( "license." + i + ".comments", license.getComments() ); 272 properties.put( "license." + i + ".distribution", license.getDistribution() ); 273 } 274 275 result.setProperties( properties ); 276 277 setArtifactProperties( result, model ); 278 } 279 280 return result; 281 } 282 283 private Model loadPom( RepositorySystemSession session, ArtifactDescriptorRequest request, 284 ArtifactDescriptorResult result ) 285 throws ArtifactDescriptorException 286 { 287 RequestTrace trace = RequestTrace.newChild( request.getTrace(), request ); 288 289 Set<String> visited = new LinkedHashSet<String>(); 290 for ( Artifact artifact = request.getArtifact();; ) 291 { 292 Artifact pomArtifact = ArtifactDescriptorUtils.toPomArtifact( artifact ); 293 try 294 { 295 VersionRequest versionRequest = 296 new VersionRequest( artifact, request.getRepositories(), request.getRequestContext() ); 297 versionRequest.setTrace( trace ); 298 VersionResult versionResult = versionResolver.resolveVersion( session, versionRequest ); 299 300 artifact = artifact.setVersion( versionResult.getVersion() ); 301 302 versionRequest = 303 new VersionRequest( pomArtifact, request.getRepositories(), request.getRequestContext() ); 304 versionRequest.setTrace( trace ); 305 versionResult = versionResolver.resolveVersion( session, versionRequest ); 306 307 pomArtifact = pomArtifact.setVersion( versionResult.getVersion() ); 308 } 309 catch ( VersionResolutionException e ) 310 { 311 result.addException( e ); 312 throw new ArtifactDescriptorException( result ); 313 } 314 315 if ( !visited.add( artifact.getGroupId() + ':' + artifact.getArtifactId() + ':' + artifact.getBaseVersion() ) ) 316 { 317 RepositoryException exception = 318 new RepositoryException( "Artifact relocations form a cycle: " + visited ); 319 invalidDescriptor( session, trace, artifact, exception ); 320 if ( ( getPolicy( session, artifact, request ) & ArtifactDescriptorPolicy.IGNORE_INVALID ) != 0 ) 321 { 322 return null; 323 } 324 result.addException( exception ); 325 throw new ArtifactDescriptorException( result ); 326 } 327 328 ArtifactResult resolveResult; 329 try 330 { 331 ArtifactRequest resolveRequest = 332 new ArtifactRequest( pomArtifact, request.getRepositories(), request.getRequestContext() ); 333 resolveRequest.setTrace( trace ); 334 resolveResult = artifactResolver.resolveArtifact( session, resolveRequest ); 335 pomArtifact = resolveResult.getArtifact(); 336 result.setRepository( resolveResult.getRepository() ); 337 } 338 catch ( ArtifactResolutionException e ) 339 { 340 if ( e.getCause() instanceof ArtifactNotFoundException ) 341 { 342 missingDescriptor( session, trace, artifact, (Exception) e.getCause() ); 343 if ( ( getPolicy( session, artifact, request ) & ArtifactDescriptorPolicy.IGNORE_MISSING ) != 0 ) 344 { 345 return null; 346 } 347 } 348 result.addException( e ); 349 throw new ArtifactDescriptorException( result ); 350 } 351 352 Model model; 353 try 354 { 355 ModelBuildingRequest modelRequest = new DefaultModelBuildingRequest(); 356 modelRequest.setValidationLevel( ModelBuildingRequest.VALIDATION_LEVEL_MINIMAL ); 357 modelRequest.setProcessPlugins( false ); 358 modelRequest.setTwoPhaseBuilding( false ); 359 modelRequest.setSystemProperties( toProperties( session.getUserProperties(), 360 session.getSystemProperties() ) ); 361 modelRequest.setModelCache( DefaultModelCache.newInstance( session ) ); 362 modelRequest.setModelResolver( new DefaultModelResolver( session, trace.newChild( modelRequest ), 363 request.getRequestContext(), artifactResolver, 364 versionRangeResolver, remoteRepositoryManager, 365 request.getRepositories() ) ); 366 if ( resolveResult.getRepository() instanceof WorkspaceRepository ) 367 { 368 modelRequest.setPomFile( pomArtifact.getFile() ); 369 } 370 else 371 { 372 modelRequest.setModelSource( new FileModelSource( pomArtifact.getFile() ) ); 373 } 374 375 model = modelBuilder.build( modelRequest ).getEffectiveModel(); 376 } 377 catch ( ModelBuildingException e ) 378 { 379 for ( ModelProblem problem : e.getProblems() ) 380 { 381 if ( problem.getException() instanceof UnresolvableModelException ) 382 { 383 result.addException( problem.getException() ); 384 throw new ArtifactDescriptorException( result ); 385 } 386 } 387 invalidDescriptor( session, trace, artifact, e ); 388 if ( ( getPolicy( session, artifact, request ) & ArtifactDescriptorPolicy.IGNORE_INVALID ) != 0 ) 389 { 390 return null; 391 } 392 result.addException( e ); 393 throw new ArtifactDescriptorException( result ); 394 } 395 396 Relocation relocation = getRelocation( model ); 397 398 if ( relocation != null ) 399 { 400 result.addRelocation( artifact ); 401 artifact = 402 new RelocatedArtifact( artifact, relocation.getGroupId(), relocation.getArtifactId(), 403 relocation.getVersion() ); 404 result.setArtifact( artifact ); 405 } 406 else 407 { 408 return model; 409 } 410 } 411 } 412 413 private Properties toProperties( Map<String, String> dominant, Map<String, String> recessive ) 414 { 415 Properties props = new Properties(); 416 if ( recessive != null ) 417 { 418 props.putAll( recessive ); 419 } 420 if ( dominant != null ) 421 { 422 props.putAll( dominant ); 423 } 424 return props; 425 } 426 427 private Relocation getRelocation( Model model ) 428 { 429 Relocation relocation = null; 430 DistributionManagement distMngt = model.getDistributionManagement(); 431 if ( distMngt != null ) 432 { 433 relocation = distMngt.getRelocation(); 434 } 435 return relocation; 436 } 437 438 private void setArtifactProperties( ArtifactDescriptorResult result, Model model ) 439 { 440 String downloadUrl = null; 441 DistributionManagement distMngt = model.getDistributionManagement(); 442 if ( distMngt != null ) 443 { 444 downloadUrl = distMngt.getDownloadUrl(); 445 } 446 if ( downloadUrl != null && downloadUrl.length() > 0 ) 447 { 448 Artifact artifact = result.getArtifact(); 449 Map<String, String> props = new HashMap<String, String>( artifact.getProperties() ); 450 props.put( ArtifactProperties.DOWNLOAD_URL, downloadUrl ); 451 result.setArtifact( artifact.setProperties( props ) ); 452 } 453 } 454 455 private Dependency convert( org.apache.maven.model.Dependency dependency, ArtifactTypeRegistry stereotypes ) 456 { 457 ArtifactType stereotype = stereotypes.get( dependency.getType() ); 458 if ( stereotype == null ) 459 { 460 stereotype = new DefaultArtifactType( dependency.getType() ); 461 } 462 463 boolean system = dependency.getSystemPath() != null && dependency.getSystemPath().length() > 0; 464 465 Map<String, String> props = null; 466 if ( system ) 467 { 468 props = Collections.singletonMap( ArtifactProperties.LOCAL_PATH, dependency.getSystemPath() ); 469 } 470 471 Artifact artifact = 472 new DefaultArtifact( dependency.getGroupId(), dependency.getArtifactId(), dependency.getClassifier(), null, 473 dependency.getVersion(), props, stereotype ); 474 475 List<Exclusion> exclusions = new ArrayList<Exclusion>( dependency.getExclusions().size() ); 476 for ( org.apache.maven.model.Exclusion exclusion : dependency.getExclusions() ) 477 { 478 exclusions.add( convert( exclusion ) ); 479 } 480 481 Dependency result = new Dependency( artifact, dependency.getScope(), dependency.isOptional(), exclusions ); 482 483 return result; 484 } 485 486 private Exclusion convert( org.apache.maven.model.Exclusion exclusion ) 487 { 488 return new Exclusion( exclusion.getGroupId(), exclusion.getArtifactId(), "*", "*" ); 489 } 490 491 private void missingDescriptor( RepositorySystemSession session, RequestTrace trace, Artifact artifact, 492 Exception exception ) 493 { 494 RepositoryEvent.Builder event = new RepositoryEvent.Builder( session, EventType.ARTIFACT_DESCRIPTOR_MISSING ); 495 event.setTrace( trace ); 496 event.setArtifact( artifact ); 497 event.setException( exception ); 498 499 repositoryEventDispatcher.dispatch( event.build() ); 500 } 501 502 private void invalidDescriptor( RepositorySystemSession session, RequestTrace trace, Artifact artifact, 503 Exception exception ) 504 { 505 RepositoryEvent.Builder event = new RepositoryEvent.Builder( session, EventType.ARTIFACT_DESCRIPTOR_INVALID ); 506 event.setTrace( trace ); 507 event.setArtifact( artifact ); 508 event.setException( exception ); 509 510 repositoryEventDispatcher.dispatch( event.build() ); 511 } 512 513 private int getPolicy( RepositorySystemSession session, Artifact artifact, ArtifactDescriptorRequest request ) 514 { 515 ArtifactDescriptorPolicy policy = session.getArtifactDescriptorPolicy(); 516 if ( policy == null ) 517 { 518 return ArtifactDescriptorPolicy.STRICT; 519 } 520 return policy.getPolicy( session, new ArtifactDescriptorPolicyRequest( artifact, request.getRequestContext() ) ); 521 } 522 523}