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