1 package org.apache.maven.project.artifact;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import org.apache.maven.artifact.Artifact;
23 import org.apache.maven.artifact.factory.ArtifactFactory;
24 import org.apache.maven.artifact.metadata.ArtifactMetadataRetrievalException;
25 import org.apache.maven.artifact.metadata.ArtifactMetadataSource;
26 import org.apache.maven.artifact.metadata.ResolutionGroup;
27 import org.apache.maven.artifact.repository.ArtifactRepository;
28 import org.apache.maven.artifact.repository.metadata.ArtifactRepositoryMetadata;
29 import org.apache.maven.artifact.repository.metadata.Metadata;
30 import org.apache.maven.artifact.repository.metadata.RepositoryMetadata;
31 import org.apache.maven.artifact.repository.metadata.RepositoryMetadataManager;
32 import org.apache.maven.artifact.repository.metadata.RepositoryMetadataResolutionException;
33 import org.apache.maven.artifact.resolver.filter.AndArtifactFilter;
34 import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
35 import org.apache.maven.artifact.resolver.filter.ExcludesArtifactFilter;
36 import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
37 import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
38 import org.apache.maven.artifact.versioning.VersionRange;
39 import org.apache.maven.model.Dependency;
40 import org.apache.maven.model.DistributionManagement;
41 import org.apache.maven.model.Exclusion;
42 import org.apache.maven.model.Relocation;
43 import org.apache.maven.project.DefaultProjectBuilderConfiguration;
44 import org.apache.maven.project.InvalidProjectModelException;
45 import org.apache.maven.project.MavenProject;
46 import org.apache.maven.project.MavenProjectBuilder;
47 import org.apache.maven.project.ProjectBuildingException;
48 import org.apache.maven.project.validation.ModelValidationResult;
49 import org.codehaus.plexus.logging.AbstractLogEnabled;
50 import org.codehaus.plexus.util.StringUtils;
51
52 import java.io.File;
53 import java.util.ArrayList;
54 import java.util.Collections;
55 import java.util.Iterator;
56 import java.util.LinkedHashSet;
57 import java.util.List;
58 import java.util.Set;
59
60
61
62
63
64
65 public class MavenMetadataSource
66 extends AbstractLogEnabled
67 implements ArtifactMetadataSource
68 {
69 public static final String ROLE_HINT = "maven";
70
71 private MavenProjectBuilder mavenProjectBuilder;
72
73 private ArtifactFactory artifactFactory;
74
75 private RepositoryMetadataManager repositoryMetadataManager;
76
77
78 private MavenProject superProject;
79
80
81
82
83 public Artifact retrieveRelocatedArtifact( Artifact artifact, ArtifactRepository localRepository, List remoteRepositories )
84 throws ArtifactMetadataRetrievalException
85 {
86 if ( artifact instanceof ActiveProjectArtifact )
87 {
88 return artifact;
89 }
90
91 MavenProject project = retrieveRelocatedProject( artifact, localRepository, remoteRepositories );
92
93 if ( project == null || getRelocationKey( artifact ).equals( getRelocationKey( project.getArtifact() ) ) )
94 {
95 return artifact;
96 }
97
98
99
100
101
102
103
104
105 Artifact result = null;
106 if ( artifact.getClassifier() != null )
107 {
108 result = artifactFactory.createArtifactWithClassifier( artifact.getGroupId(), artifact.getArtifactId(), artifact.getVersion(), artifact.getType(), artifact.getClassifier() );
109 }
110 else
111 {
112 result = artifactFactory.createArtifact( artifact.getGroupId(), artifact.getArtifactId(), artifact.getVersion(), artifact.getScope(), artifact.getType() );
113 }
114
115 result.setResolved( artifact.isResolved() );
116 result.setFile( artifact.getFile() );
117
118 result.setScope( artifact.getScope() );
119 result.setArtifactHandler( artifact.getArtifactHandler() );
120 result.setDependencyFilter( artifact.getDependencyFilter() );
121 result.setDependencyTrail( artifact.getDependencyTrail() );
122 result.setOptional( artifact.isOptional() );
123 result.setRelease( artifact.isRelease() );
124
125 return result;
126 }
127
128 private String getRelocationKey( Artifact artifact )
129 {
130 return artifact.getGroupId() + ":" + artifact.getArtifactId() + ":" + artifact.getVersion();
131 }
132
133 private MavenProject retrieveRelocatedProject( Artifact artifact, ArtifactRepository localRepository, List remoteRepositories )
134 throws ArtifactMetadataRetrievalException
135 {
136 MavenProject project = null;
137
138 Artifact pomArtifact;
139 boolean done = false;
140 do
141 {
142
143 pomArtifact = artifactFactory.createProjectArtifact( artifact.getGroupId(), artifact.getArtifactId(),
144 artifact.getVersion(), artifact.getScope() );
145
146 if ( Artifact.SCOPE_SYSTEM.equals( artifact.getScope() ) )
147 {
148 done = true;
149 }
150 else
151 {
152 try
153 {
154 project = mavenProjectBuilder.buildFromRepository( pomArtifact, remoteRepositories, localRepository,
155 true );
156 }
157 catch ( InvalidProjectModelException e )
158 {
159 getLogger().warn( "POM for \'" + pomArtifact +
160 "\' is invalid. It will be ignored for artifact resolution. Reason: " + e.getMessage() );
161
162 if ( getLogger().isDebugEnabled() )
163 {
164 getLogger().debug( "Reason: " + e.getMessage() );
165
166 ModelValidationResult validationResult = e.getValidationResult();
167
168 if ( validationResult != null )
169 {
170 getLogger().debug( "\nValidation Errors:" );
171 for ( Iterator i = validationResult.getMessages().iterator(); i.hasNext(); )
172 {
173 getLogger().debug( i.next().toString() );
174 }
175 getLogger().debug( "\n" );
176 }
177 }
178
179 project = null;
180 }
181 catch ( ProjectBuildingException e )
182 {
183 throw new ArtifactMetadataRetrievalException( "Unable to read the metadata file for artifact '" +
184 artifact.getDependencyConflictId() + "': " + e.getMessage(), e, artifact );
185 }
186
187 if ( project != null )
188 {
189 Relocation relocation = null;
190
191 DistributionManagement distMgmt = project.getDistributionManagement();
192 if ( distMgmt != null )
193 {
194 relocation = distMgmt.getRelocation();
195
196 artifact.setDownloadUrl( distMgmt.getDownloadUrl() );
197 pomArtifact.setDownloadUrl( distMgmt.getDownloadUrl() );
198 }
199
200 if ( relocation != null )
201 {
202 if ( relocation.getGroupId() != null )
203 {
204 artifact.setGroupId( relocation.getGroupId() );
205 project.setGroupId( relocation.getGroupId() );
206 }
207 if ( relocation.getArtifactId() != null )
208 {
209 artifact.setArtifactId( relocation.getArtifactId() );
210 project.setArtifactId( relocation.getArtifactId() );
211 }
212 if ( relocation.getVersion() != null )
213 {
214
215 artifact.setVersionRange( VersionRange.createFromVersion( relocation.getVersion() ) );
216 project.setVersion( relocation.getVersion() );
217 }
218
219 if ( artifact.getDependencyFilter() != null &&
220 !artifact.getDependencyFilter().include( artifact ) )
221 {
222 return null;
223 }
224
225
226
227 List available = artifact.getAvailableVersions();
228 if ( available != null && !available.isEmpty() )
229 {
230 artifact.setAvailableVersions( retrieveAvailableVersions( artifact, localRepository,
231 remoteRepositories ) );
232
233 }
234
235 String message = "\n This artifact has been relocated to " + artifact.getGroupId() + ":" +
236 artifact.getArtifactId() + ":" + artifact.getVersion() + ".\n";
237
238 if ( relocation.getMessage() != null )
239 {
240 message += " " + relocation.getMessage() + "\n";
241 }
242
243 if ( artifact.getDependencyTrail() != null && artifact.getDependencyTrail().size() == 1 )
244 {
245 getLogger().warn( "While downloading " + pomArtifact.getGroupId() + ":" +
246 pomArtifact.getArtifactId() + ":" + pomArtifact.getVersion() + message + "\n" );
247 }
248 else
249 {
250 getLogger().debug( "While downloading " + pomArtifact.getGroupId() + ":" +
251 pomArtifact.getArtifactId() + ":" + pomArtifact.getVersion() + message + "\n" );
252 }
253 }
254 else
255 {
256 done = true;
257 }
258 }
259 else
260 {
261 done = true;
262 }
263 }
264 }
265 while ( !done );
266
267 return project;
268 }
269
270
271
272
273
274
275 public ResolutionGroup retrieve( Artifact artifact, ArtifactRepository localRepository, List remoteRepositories )
276 throws ArtifactMetadataRetrievalException
277 {
278 MavenProject project = retrieveRelocatedProject( artifact, localRepository, remoteRepositories );
279 Artifact pomArtifact;
280 if ( project != null )
281 {
282 pomArtifact = project.getArtifact();
283 }
284 else
285 {
286 pomArtifact = artifactFactory.createProjectArtifact( artifact.getGroupId(),
287 artifact.getArtifactId(),
288 artifact.getVersion(),
289 artifact.getScope() );
290 }
291
292
293
294 if ( artifact.getDownloadUrl() == null && pomArtifact != null )
295 {
296
297 artifact.setDownloadUrl( pomArtifact.getDownloadUrl() );
298 }
299
300 ResolutionGroup result;
301
302 if ( project == null )
303 {
304
305
306
307 result = new ResolutionGroup( pomArtifact, Collections.EMPTY_SET, Collections.EMPTY_LIST );
308 }
309 else
310 {
311 Set artifacts = Collections.EMPTY_SET;
312 if ( !artifact.getArtifactHandler().isIncludesDependencies() )
313 {
314
315
316 try
317 {
318 artifacts = project.createArtifacts( artifactFactory, artifact.getScope(),
319 artifact.getDependencyFilter() );
320 }
321 catch ( InvalidDependencyVersionException e )
322 {
323 throw new ArtifactMetadataRetrievalException( "Error in metadata for artifact '" +
324 artifact.getDependencyConflictId() + "': " + e.getMessage(), e );
325 }
326 }
327
328 List repositories = aggregateRepositoryLists( remoteRepositories, project.getRemoteArtifactRepositories() );
329
330 result = new ResolutionGroup( pomArtifact, artifacts, repositories );
331 }
332
333 return result;
334 }
335
336 private List aggregateRepositoryLists( List remoteRepositories, List remoteArtifactRepositories )
337 throws ArtifactMetadataRetrievalException
338 {
339 if ( superProject == null )
340 {
341 try
342 {
343 superProject = mavenProjectBuilder.buildStandaloneSuperProject( new DefaultProjectBuilderConfiguration() );
344 }
345 catch ( ProjectBuildingException e )
346 {
347 throw new ArtifactMetadataRetrievalException(
348 "Unable to parse the Maven built-in model: " + e.getMessage(), e );
349 }
350 }
351
352 List repositories = new ArrayList();
353
354 repositories.addAll( remoteRepositories );
355
356
357 for ( Iterator it = superProject.getRemoteArtifactRepositories().iterator(); it.hasNext(); )
358 {
359 ArtifactRepository superRepo = (ArtifactRepository) it.next();
360
361 for ( Iterator aggregatedIterator = repositories.iterator(); aggregatedIterator.hasNext(); )
362 {
363 ArtifactRepository repo = (ArtifactRepository) aggregatedIterator.next();
364
365
366
367
368
369 if ( repo.getId().equals( superRepo.getId() ) && repo.getUrl().equals( superRepo.getUrl() ) )
370 {
371 aggregatedIterator.remove();
372 }
373 }
374 }
375
376
377 for ( Iterator it = remoteArtifactRepositories.iterator(); it.hasNext(); )
378 {
379 ArtifactRepository repository = (ArtifactRepository) it.next();
380
381 if ( !repositories.contains( repository ) )
382 {
383 repositories.add( repository );
384 }
385 }
386
387 return repositories;
388 }
389
390
391
392
393
394 public static Set createArtifacts( ArtifactFactory artifactFactory, List dependencies, String inheritedScope,
395 ArtifactFilter dependencyFilter, MavenProject project )
396 throws InvalidDependencyVersionException
397 {
398 Set projectArtifacts = new LinkedHashSet( dependencies.size() );
399
400 for ( Iterator i = dependencies.iterator(); i.hasNext(); )
401 {
402 Dependency d = (Dependency) i.next();
403
404 String scope = d.getScope();
405
406 if ( StringUtils.isEmpty( scope ) )
407 {
408 scope = Artifact.SCOPE_COMPILE;
409
410 d.setScope( scope );
411 }
412
413 VersionRange versionRange;
414 try
415 {
416 versionRange = VersionRange.createFromVersionSpec( d.getVersion() );
417 }
418 catch ( InvalidVersionSpecificationException e )
419 {
420 throw new InvalidDependencyVersionException( "Unable to parse version '" + d.getVersion() +
421 "' for dependency '" + d.getManagementKey() + "': " + e.getMessage(), e );
422 }
423 Artifact artifact = artifactFactory.createDependencyArtifact( d.getGroupId(), d.getArtifactId(),
424 versionRange, d.getType(), d.getClassifier(),
425 scope, inheritedScope, d.isOptional() );
426
427 if ( Artifact.SCOPE_SYSTEM.equals( scope ) )
428 {
429 artifact.setFile( new File( d.getSystemPath() ) );
430 }
431
432 ArtifactFilter artifactFilter = dependencyFilter;
433
434
435
436
437
438
439 if ( artifact != null && ( artifactFilter == null || artifactFilter.include( artifact ) ) )
440 {
441 if ( d.getExclusions() != null && !d.getExclusions().isEmpty() )
442 {
443 List exclusions = new ArrayList();
444 for ( Iterator j = d.getExclusions().iterator(); j.hasNext(); )
445 {
446 Exclusion e = (Exclusion) j.next();
447 exclusions.add( e.getGroupId() + ":" + e.getArtifactId() );
448 }
449
450 ArtifactFilter newFilter = new ExcludesArtifactFilter( exclusions );
451
452 if ( artifactFilter != null )
453 {
454 AndArtifactFilter filter = new AndArtifactFilter();
455 filter.add( artifactFilter );
456 filter.add( newFilter );
457 artifactFilter = filter;
458 }
459 else
460 {
461 artifactFilter = newFilter;
462 }
463 }
464
465 artifact.setDependencyFilter( artifactFilter );
466
467 if ( project != null )
468 {
469 artifact = project.replaceWithActiveArtifact( artifact );
470 }
471
472 projectArtifacts.add( artifact );
473 }
474 }
475
476 return projectArtifacts;
477 }
478
479 public List retrieveAvailableVersions( Artifact artifact, ArtifactRepository localRepository,
480 List remoteRepositories )
481 throws ArtifactMetadataRetrievalException
482 {
483 RepositoryMetadata metadata = new ArtifactRepositoryMetadata( artifact );
484 try
485 {
486 repositoryMetadataManager.resolve( metadata, remoteRepositories, localRepository );
487 }
488 catch ( RepositoryMetadataResolutionException e )
489 {
490 throw new ArtifactMetadataRetrievalException( e.getMessage(), e );
491 }
492
493 List versions;
494 Metadata repoMetadata = metadata.getMetadata();
495 if ( repoMetadata != null && repoMetadata.getVersioning() != null )
496 {
497 List metadataVersions = repoMetadata.getVersioning().getVersions();
498 versions = new ArrayList( metadataVersions.size() );
499 for ( Iterator i = metadataVersions.iterator(); i.hasNext(); )
500 {
501 String version = (String) i.next();
502 versions.add( new DefaultArtifactVersion( version ) );
503 }
504 }
505 else
506 {
507 versions = Collections.EMPTY_LIST;
508 }
509
510 return versions;
511 }
512 }