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