1 package org.apache.maven.artifact.resolver;
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.io.IOException;
24 import java.util.ArrayList;
25 import java.util.Collections;
26 import java.util.Date;
27 import java.util.HashMap;
28 import java.util.Iterator;
29 import java.util.List;
30 import java.util.Map;
31 import java.util.Set;
32
33 import org.apache.maven.artifact.Artifact;
34 import org.apache.maven.artifact.factory.ArtifactFactory;
35 import org.apache.maven.artifact.manager.WagonManager;
36 import org.apache.maven.artifact.metadata.ArtifactMetadata;
37 import org.apache.maven.artifact.metadata.ArtifactMetadataSource;
38 import org.apache.maven.artifact.repository.ArtifactRepository;
39 import org.apache.maven.artifact.repository.ArtifactRepositoryPolicy;
40 import org.apache.maven.artifact.repository.metadata.Metadata;
41 import org.apache.maven.artifact.repository.metadata.Snapshot;
42 import org.apache.maven.artifact.repository.metadata.SnapshotArtifactRepositoryMetadata;
43 import org.apache.maven.artifact.repository.metadata.Versioning;
44 import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
45 import org.apache.maven.artifact.transform.ArtifactTransformationManager;
46 import org.apache.maven.wagon.ResourceDoesNotExistException;
47 import org.apache.maven.wagon.TransferFailedException;
48 import org.codehaus.plexus.logging.AbstractLogEnabled;
49 import org.codehaus.plexus.util.FileUtils;
50
51 import edu.emory.mathcs.backport.java.util.concurrent.CountDownLatch;
52 import edu.emory.mathcs.backport.java.util.concurrent.LinkedBlockingQueue;
53 import edu.emory.mathcs.backport.java.util.concurrent.ThreadPoolExecutor;
54 import edu.emory.mathcs.backport.java.util.concurrent.TimeUnit;
55
56 public class DefaultArtifactResolver
57 extends AbstractLogEnabled
58 implements ArtifactResolver
59 {
60
61
62
63
64 private static final int DEFAULT_POOL_SIZE = 5;
65
66 private WagonManager wagonManager;
67
68 private ArtifactTransformationManager transformationManager;
69
70 protected ArtifactFactory artifactFactory;
71
72 private ArtifactCollector artifactCollector;
73 private final ThreadPoolExecutor resolveArtifactPool;
74
75 public DefaultArtifactResolver()
76 {
77 super();
78 resolveArtifactPool =
79 new ThreadPoolExecutor( DEFAULT_POOL_SIZE, DEFAULT_POOL_SIZE, 3, TimeUnit.SECONDS,
80 new LinkedBlockingQueue() );
81 }
82
83
84
85
86
87 public void resolve( Artifact artifact, List remoteRepositories, ArtifactRepository localRepository )
88 throws ArtifactResolutionException, ArtifactNotFoundException
89 {
90 resolve( artifact, remoteRepositories, localRepository, false );
91 }
92
93 public void resolveAlways( Artifact artifact, List remoteRepositories, ArtifactRepository localRepository )
94 throws ArtifactResolutionException, ArtifactNotFoundException
95 {
96 resolve( artifact, remoteRepositories, localRepository, true );
97 }
98
99 private void resolve( Artifact artifact, List remoteRepositories, ArtifactRepository localRepository,
100 boolean force )
101 throws ArtifactResolutionException, ArtifactNotFoundException
102 {
103 if ( artifact == null )
104 {
105 return;
106 }
107
108 if ( Artifact.SCOPE_SYSTEM.equals( artifact.getScope() ) )
109 {
110 File systemFile = artifact.getFile();
111
112 if ( systemFile == null )
113 {
114 throw new ArtifactNotFoundException(
115 "System artifact: " + artifact + " has no file attached", artifact );
116 }
117
118 if ( !systemFile.isFile() )
119 {
120 throw new ArtifactNotFoundException( "System artifact: " + artifact
121 + " is not a file: " + systemFile, artifact );
122 }
123
124 if ( !systemFile.exists() )
125 {
126 throw new ArtifactNotFoundException(
127 "System artifact: " + artifact + " not found in path: " + systemFile,
128 artifact );
129 }
130
131 artifact.setResolved( true );
132 }
133 else if ( !artifact.isResolved() )
134 {
135
136
137
138
139
140
141 String localPath = localRepository.pathOf( artifact );
142
143 artifact.setFile( new File( localRepository.getBasedir(), localPath ) );
144
145 transformationManager.transformForResolve( artifact, remoteRepositories, localRepository );
146
147 boolean localCopy = false;
148 for ( Iterator i = artifact.getMetadataList().iterator(); i.hasNext(); )
149 {
150 ArtifactMetadata m = (ArtifactMetadata) i.next();
151 if ( m instanceof SnapshotArtifactRepositoryMetadata )
152 {
153 SnapshotArtifactRepositoryMetadata snapshotMetadata = (SnapshotArtifactRepositoryMetadata) m;
154
155 Metadata metadata = snapshotMetadata.getMetadata();
156 if ( metadata != null )
157 {
158 Versioning versioning = metadata.getVersioning();
159 if ( versioning != null )
160 {
161 Snapshot snapshot = versioning.getSnapshot();
162 if ( snapshot != null )
163 {
164 localCopy = snapshot.isLocalCopy();
165 }
166 }
167 }
168 }
169 }
170
171 File destination = artifact.getFile();
172 List repositories = remoteRepositories;
173
174
175 if ( artifact.isSnapshot() && artifact.getBaseVersion().equals( artifact.getVersion() ) &&
176 destination.exists() && !localCopy && wagonManager.isOnline() )
177 {
178 Date comparisonDate = new Date( destination.lastModified() );
179
180
181 repositories = new ArrayList( remoteRepositories );
182 for ( Iterator i = repositories.iterator(); i.hasNext(); )
183 {
184 ArtifactRepository repository = (ArtifactRepository) i.next();
185 ArtifactRepositoryPolicy policy = repository.getSnapshots();
186 if ( !policy.isEnabled() || !policy.checkOutOfDate( comparisonDate ) )
187 {
188 i.remove();
189 }
190 }
191
192 if ( !repositories.isEmpty() )
193 {
194
195 force = true;
196 }
197 }
198 boolean resolved = false;
199 if ( !destination.exists() || force )
200 {
201 if ( !wagonManager.isOnline() )
202 {
203 throw new ArtifactNotFoundException( "System is offline.", artifact );
204 }
205
206 try
207 {
208
209 if ( artifact.getRepository() != null )
210 {
211
212 wagonManager.getArtifact( artifact, artifact.getRepository() );
213 }
214 else
215 {
216 wagonManager.getArtifact( artifact, repositories );
217 }
218
219 if ( !artifact.isResolved() && !destination.exists() )
220 {
221 throw new ArtifactResolutionException(
222 "Failed to resolve artifact, possibly due to a repository list that is not appropriately equipped for this artifact's metadata.",
223 artifact, getMirroredRepositories( remoteRepositories ) );
224 }
225 }
226 catch ( ResourceDoesNotExistException e )
227 {
228 throw new ArtifactNotFoundException( e.getMessage(), artifact,
229 getMirroredRepositories( remoteRepositories ), e );
230 }
231 catch ( TransferFailedException e )
232 {
233 throw new ArtifactResolutionException( e.getMessage(), artifact,
234 getMirroredRepositories( remoteRepositories ), e );
235 }
236
237 resolved = true;
238 }
239 else if ( destination.exists() )
240 {
241
242 artifact.setResolved( true );
243 }
244
245 if ( artifact.isSnapshot() && !artifact.getBaseVersion().equals( artifact.getVersion() ) )
246 {
247 String version = artifact.getVersion();
248 artifact.selectVersion( artifact.getBaseVersion() );
249 File copy = new File( localRepository.getBasedir(), localRepository.pathOf( artifact ) );
250 if ( resolved || !copy.exists() )
251 {
252
253 try
254 {
255 FileUtils.copyFile( destination, copy );
256 }
257 catch ( IOException e )
258 {
259 throw new ArtifactResolutionException(
260 "Unable to copy resolved artifact for local use: " + e.getMessage(), artifact,
261 getMirroredRepositories( remoteRepositories ), e );
262 }
263 }
264 artifact.setFile( copy );
265 artifact.selectVersion( version );
266 }
267 }
268 }
269
270 public ArtifactResolutionResult resolveTransitively( Set artifacts, Artifact originatingArtifact,
271 ArtifactRepository localRepository, List remoteRepositories,
272 ArtifactMetadataSource source, ArtifactFilter filter )
273 throws ArtifactResolutionException, ArtifactNotFoundException
274 {
275 return resolveTransitively( artifacts, originatingArtifact, Collections.EMPTY_MAP, localRepository,
276 remoteRepositories, source, filter );
277
278 }
279
280 public ArtifactResolutionResult resolveTransitively( Set artifacts, Artifact originatingArtifact,
281 Map managedVersions, ArtifactRepository localRepository,
282 List remoteRepositories, ArtifactMetadataSource source )
283 throws ArtifactResolutionException, ArtifactNotFoundException
284 {
285 return resolveTransitively( artifacts, originatingArtifact, managedVersions, localRepository,
286 remoteRepositories, source, null );
287 }
288
289 public ArtifactResolutionResult resolveTransitively( Set artifacts, Artifact originatingArtifact,
290 Map managedVersions, ArtifactRepository localRepository,
291 List remoteRepositories, ArtifactMetadataSource source,
292 ArtifactFilter filter )
293 throws ArtifactResolutionException, ArtifactNotFoundException
294 {
295
296 List listeners = new ArrayList();
297 if ( getLogger().isDebugEnabled() )
298 {
299 listeners.add( new DebugResolutionListener( getLogger() ) );
300 }
301
302 listeners.add( new WarningResolutionListener( getLogger() ) );
303
304 return resolveTransitively( artifacts, originatingArtifact, managedVersions, localRepository,
305 remoteRepositories, source, filter, listeners );
306
307 }
308
309 public ArtifactResolutionResult resolveTransitively( Set artifacts, Artifact originatingArtifact,
310 Map managedVersions, ArtifactRepository localRepository,
311 List remoteRepositories, ArtifactMetadataSource source,
312 ArtifactFilter filter, List listeners )
313 throws ArtifactResolutionException, ArtifactNotFoundException
314 {
315 ArtifactResolutionResult artifactResolutionResult;
316 artifactResolutionResult =
317 artifactCollector.collect( artifacts, originatingArtifact, managedVersions, localRepository,
318 remoteRepositories, source, filter, listeners );
319
320 List resolvedArtifacts = Collections.synchronizedList( new ArrayList() );
321 List missingArtifacts = Collections.synchronizedList( new ArrayList() );
322 CountDownLatch latch = new CountDownLatch( artifactResolutionResult.getArtifactResolutionNodes().size() );
323 Map nodesByGroupId = new HashMap();
324 for ( Iterator i = artifactResolutionResult.getArtifactResolutionNodes().iterator(); i.hasNext(); )
325 {
326 ResolutionNode node = (ResolutionNode) i.next();
327 List nodes = (List) nodesByGroupId.get( node.getArtifact().getGroupId() );
328 if ( nodes == null )
329 {
330 nodes = new ArrayList();
331 nodesByGroupId.put( node.getArtifact().getGroupId(), nodes );
332 }
333 nodes.add( node );
334 }
335
336 List resolutionExceptions = Collections.synchronizedList( new ArrayList() );
337 try
338 {
339 for ( Iterator i = nodesByGroupId.values().iterator(); i.hasNext(); )
340 {
341 List nodes = (List) i.next();
342 resolveArtifactPool.execute( new ResolveArtifactTask( resolveArtifactPool, latch, nodes,
343 localRepository, resolvedArtifacts,
344 missingArtifacts, resolutionExceptions ) );
345 }
346 latch.await();
347 }
348 catch ( InterruptedException e )
349 {
350 throw new ArtifactResolutionException( "Resolution interrupted", null, e );
351 }
352
353 if ( !resolutionExceptions.isEmpty() )
354 {
355 throw (ArtifactResolutionException) resolutionExceptions.get( 0 );
356 }
357
358 if ( missingArtifacts.size() > 0 )
359 {
360 throw new MultipleArtifactsNotFoundException( originatingArtifact, resolvedArtifacts, missingArtifacts,
361 getMirroredRepositories( remoteRepositories ) );
362 }
363
364 return artifactResolutionResult;
365 }
366
367 private List getMirroredRepositories( List remoteRepositories )
368 {
369 Map repos = new HashMap();
370 for ( Iterator i = remoteRepositories.iterator(); i.hasNext(); )
371 {
372 ArtifactRepository repository = (ArtifactRepository) i.next();
373 ArtifactRepository repo = wagonManager.getMirrorRepository( repository );
374 repos.put( repo.getId(), repo );
375 }
376 return new ArrayList( repos.values() );
377 }
378
379 public ArtifactResolutionResult resolveTransitively( Set artifacts, Artifact originatingArtifact,
380 List remoteRepositories, ArtifactRepository localRepository,
381 ArtifactMetadataSource source )
382 throws ArtifactResolutionException, ArtifactNotFoundException
383 {
384 return resolveTransitively( artifacts, originatingArtifact, localRepository, remoteRepositories, source, null );
385 }
386
387 public ArtifactResolutionResult resolveTransitively( Set artifacts, Artifact originatingArtifact,
388 List remoteRepositories, ArtifactRepository localRepository,
389 ArtifactMetadataSource source, List listeners )
390 throws ArtifactResolutionException, ArtifactNotFoundException
391 {
392 return resolveTransitively( artifacts, originatingArtifact, Collections.EMPTY_MAP, localRepository,
393 remoteRepositories, source, null, listeners );
394 }
395
396 private class ResolveArtifactTask
397 implements Runnable
398 {
399 private List nodes;
400
401 private ArtifactRepository localRepository;
402
403 private List resolvedArtifacts;
404
405 private List missingArtifacts;
406
407 private CountDownLatch latch;
408
409 private ThreadPoolExecutor pool;
410
411 private List resolutionExceptions;
412
413 public ResolveArtifactTask( ThreadPoolExecutor pool, CountDownLatch latch, List nodes,
414 ArtifactRepository localRepository, List resolvedArtifacts, List missingArtifacts,
415 List resolutionExceptions )
416 {
417 this.nodes = nodes;
418 this.localRepository = localRepository;
419 this.resolvedArtifacts = resolvedArtifacts;
420 this.missingArtifacts = missingArtifacts;
421 this.latch = latch;
422 this.pool = pool;
423 this.resolutionExceptions = resolutionExceptions;
424 }
425
426 public void run()
427 {
428 Iterator i = nodes.iterator();
429 ResolutionNode node = (ResolutionNode) i.next();
430 i.remove();
431 try
432 {
433 resolveArtifact( node );
434 if ( i.hasNext() )
435 {
436 pool.execute( new ResolveArtifactTask( pool, latch, nodes, localRepository, resolvedArtifacts,
437 missingArtifacts, resolutionExceptions ) );
438 }
439 }
440 catch ( ArtifactResolutionException e )
441 {
442 resolutionExceptions.add( e );
443 }
444 finally
445 {
446 latch.countDown();
447 }
448 }
449
450 private void resolveArtifact( ResolutionNode node )
451 throws ArtifactResolutionException
452 {
453 try
454 {
455 resolve( node.getArtifact(), node.getRemoteRepositories(), localRepository );
456 resolvedArtifacts.add( node.getArtifact() );
457 }
458 catch ( ArtifactNotFoundException anfe )
459 {
460 getLogger().debug( anfe.getMessage(), anfe );
461
462 missingArtifacts.add( node.getArtifact() );
463 }
464 }
465 }
466
467 public synchronized void configureNumberOfThreads( int threads )
468 {
469 resolveArtifactPool.setCorePoolSize( threads );
470 resolveArtifactPool.setMaximumPoolSize( threads );
471 }
472
473 void setWagonManager( WagonManager wagonManager )
474 {
475 this.wagonManager = wagonManager;
476 }
477 }