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