KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > maven > artifact > resolver > DefaultArtifactCollector


1 package org.apache.maven.artifact.resolver;
2
3 /*
4  * Copyright 2001-2005 The Apache Software Foundation.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */

18
19 import org.apache.maven.artifact.Artifact;
20 import org.apache.maven.artifact.metadata.ArtifactMetadataRetrievalException;
21 import org.apache.maven.artifact.metadata.ArtifactMetadataSource;
22 import org.apache.maven.artifact.metadata.ResolutionGroup;
23 import org.apache.maven.artifact.repository.ArtifactRepository;
24 import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
25 import org.apache.maven.artifact.versioning.ArtifactVersion;
26 import org.apache.maven.artifact.versioning.OverConstrainedVersionException;
27 import org.apache.maven.artifact.versioning.VersionRange;
28
29 import java.util.ArrayList JavaDoc;
30 import java.util.Collections JavaDoc;
31 import java.util.HashMap JavaDoc;
32 import java.util.HashSet JavaDoc;
33 import java.util.Iterator JavaDoc;
34 import java.util.List JavaDoc;
35 import java.util.Map JavaDoc;
36 import java.util.Set JavaDoc;
37
38 /**
39  * Default implementation of the artifact collector.
40  *
41  * @author <a HREF="mailto:brett@apache.org">Brett Porter</a>
42  * @version $Id: DefaultArtifactCollector.java 379648 2006-02-22 01:55:47Z brett $
43  */

44 public class DefaultArtifactCollector
45     implements ArtifactCollector
46 {
47     public ArtifactResolutionResult collect( Set JavaDoc artifacts, Artifact originatingArtifact,
48                                              ArtifactRepository localRepository, List JavaDoc remoteRepositories,
49                                              ArtifactMetadataSource source, ArtifactFilter filter, List JavaDoc listeners )
50         throws ArtifactResolutionException
51     {
52         return collect( artifacts, originatingArtifact, Collections.EMPTY_MAP, localRepository, remoteRepositories,
53                         source, filter, listeners );
54     }
55
56     public ArtifactResolutionResult collect( Set JavaDoc artifacts, Artifact originatingArtifact, Map JavaDoc managedVersions,
57                                              ArtifactRepository localRepository, List JavaDoc remoteRepositories,
58                                              ArtifactMetadataSource source, ArtifactFilter filter, List JavaDoc listeners )
59         throws ArtifactResolutionException
60     {
61         Map JavaDoc resolvedArtifacts = new HashMap JavaDoc();
62
63         ResolutionNode root = new ResolutionNode( originatingArtifact, remoteRepositories );
64
65         root.addDependencies( artifacts, remoteRepositories, filter );
66
67         recurse( root, resolvedArtifacts, managedVersions, localRepository, remoteRepositories, source, filter,
68                  listeners );
69
70         Set JavaDoc set = new HashSet JavaDoc();
71
72         for ( Iterator JavaDoc i = resolvedArtifacts.values().iterator(); i.hasNext(); )
73         {
74             List JavaDoc nodes = (List JavaDoc) i.next();
75             for ( Iterator JavaDoc j = nodes.iterator(); j.hasNext(); )
76             {
77                 ResolutionNode node = (ResolutionNode) j.next();
78                 if ( !node.equals( root ) && node.isActive() )
79                 {
80                     Artifact artifact = node.getArtifact();
81
82                     if ( node.filterTrail( filter ) )
83                     {
84                         // If it was optional and not a direct dependency,
85
// we don't add it or its children, just allow the update of the version and scope
86
if ( node.isChildOfRootNode() || !artifact.isOptional() )
87                         {
88                             artifact.setDependencyTrail( node.getDependencyTrail() );
89
90                             set.add( node );
91                         }
92                     }
93                 }
94             }
95         }
96
97         ArtifactResolutionResult result = new ArtifactResolutionResult();
98         result.setArtifactResolutionNodes( set );
99         return result;
100     }
101
102     private void recurse( ResolutionNode node, Map JavaDoc resolvedArtifacts, Map JavaDoc managedVersions,
103                           ArtifactRepository localRepository, List JavaDoc remoteRepositories, ArtifactMetadataSource source,
104                           ArtifactFilter filter, List JavaDoc listeners )
105         throws CyclicDependencyException, ArtifactResolutionException, OverConstrainedVersionException
106     {
107         fireEvent( ResolutionListener.TEST_ARTIFACT, listeners, node );
108
109         // TODO: use as a conflict resolver
110
Object JavaDoc key = node.getKey();
111         if ( managedVersions.containsKey( key ) )
112         {
113             Artifact artifact = (Artifact) managedVersions.get( key );
114
115             fireEvent( ResolutionListener.MANAGE_ARTIFACT, listeners, node, artifact );
116
117             if ( artifact.getVersion() != null )
118             {
119                 node.getArtifact().setVersion( artifact.getVersion() );
120             }
121             if ( artifact.getScope() != null )
122             {
123                 node.getArtifact().setScope( artifact.getScope() );
124             }
125         }
126
127         List JavaDoc previousNodes = (List JavaDoc) resolvedArtifacts.get( key );
128         if ( previousNodes != null )
129         {
130             for ( Iterator JavaDoc i = previousNodes.iterator(); i.hasNext(); )
131             {
132                 ResolutionNode previous = (ResolutionNode) i.next();
133
134                 if ( previous.isActive() )
135                 {
136                     // Version mediation
137
VersionRange previousRange = previous.getArtifact().getVersionRange();
138                     VersionRange currentRange = node.getArtifact().getVersionRange();
139
140                     if ( previousRange != null && currentRange != null )
141                     {
142                         // TODO: shouldn't need to double up on this work, only done for simplicity of handling recommended
143
// version but the restriction is identical
144
VersionRange newRange = previousRange.restrict( currentRange );
145                         // TODO: ick. this forces the OCE that should have come from the previous call. It is still correct
146
if ( newRange.isSelectedVersionKnown( previous.getArtifact() ) )
147                         {
148                             fireEvent( ResolutionListener.RESTRICT_RANGE, listeners, node, previous.getArtifact(),
149                                        newRange );
150                         }
151                         previous.getArtifact().setVersionRange( newRange );
152                         node.getArtifact().setVersionRange( currentRange.restrict( previousRange ) );
153
154                         //Select an appropriate available version from the (now restricted) range
155
//Note this version was selected before to get the appropriate POM
156
//But it was reset by the call to setVersionRange on restricting the version
157
ResolutionNode[] resetNodes = {previous, node};
158                         for ( int j = 0; j < 2; j++ )
159                         {
160                             Artifact resetArtifact = resetNodes[j].getArtifact();
161                             if ( resetArtifact.getVersion() == null && resetArtifact.getVersionRange() != null &&
162                                 resetArtifact.getAvailableVersions() != null )
163                             {
164
165                                 resetArtifact.selectVersion( resetArtifact.getVersionRange().matchVersion(
166                                     resetArtifact.getAvailableVersions() ).toString() );
167                                 fireEvent( ResolutionListener.SELECT_VERSION_FROM_RANGE, listeners, resetNodes[j] );
168                             }
169                         }
170                     }
171
172                     // Conflict Resolution
173
// TODO: use as conflict resolver(s), chain
174

175                     // TODO: should this be part of mediation?
176
// previous one is more dominant
177
ResolutionNode nearest;
178                     ResolutionNode farthest;
179                     if ( previous.getDepth() <= node.getDepth() )
180                     {
181                         nearest = previous;
182                         farthest = node;
183                     }
184                     else
185                     {
186                         nearest = node;
187                         farthest = previous;
188                     }
189
190                     if ( checkScopeUpdate( farthest, nearest, listeners ) )
191                     {
192                         // if we need to update scope of nearest to use farthest scope, use the nearest version, but farthest scope
193
nearest.disable();
194                         farthest.getArtifact().setVersion( nearest.getArtifact().getVersion() );
195                     }
196                     else
197                     {
198                         farthest.disable();
199                     }
200                     fireEvent( ResolutionListener.OMIT_FOR_NEARER, listeners, farthest, nearest.getArtifact() );
201                 }
202             }
203         }
204         else
205         {
206             previousNodes = new ArrayList JavaDoc();
207             resolvedArtifacts.put( key, previousNodes );
208         }
209         previousNodes.add( node );
210
211         if ( node.isActive() )
212         {
213             fireEvent( ResolutionListener.INCLUDE_ARTIFACT, listeners, node );
214         }
215
216         // don't pull in the transitive deps of a system-scoped dependency.
217
if ( node.isActive() && !Artifact.SCOPE_SYSTEM.equals( node.getArtifact().getScope() ) )
218         {
219             fireEvent( ResolutionListener.PROCESS_CHILDREN, listeners, node );
220
221             for ( Iterator JavaDoc i = node.getChildrenIterator(); i.hasNext(); )
222             {
223                 ResolutionNode child = (ResolutionNode) i.next();
224                 // We leave in optional ones, but don't pick up its dependencies
225
if ( !child.isResolved() && ( !child.getArtifact().isOptional() || child.isChildOfRootNode() ) )
226                 {
227                     Artifact artifact = child.getArtifact();
228                     try
229                     {
230                         if ( artifact.getVersion() == null )
231                         {
232                             // set the recommended version
233
// TODO: maybe its better to just pass the range through to retrieval and use a transformation?
234
ArtifactVersion version;
235                             if ( !artifact.isSelectedVersionKnown() )
236                             {
237                                 List JavaDoc versions = artifact.getAvailableVersions();
238                                 if ( versions == null )
239                                 {
240                                     versions = source.retrieveAvailableVersions( artifact, localRepository,
241                                                                                  remoteRepositories );
242                                     artifact.setAvailableVersions( versions );
243                                 }
244
245                                 VersionRange versionRange = artifact.getVersionRange();
246
247                                 version = versionRange.matchVersion( versions );
248
249                                 if ( version == null )
250                                 {
251                                     if ( versions.isEmpty() )
252                                     {
253                                         throw new OverConstrainedVersionException(
254                                             "No versions are present in the repository for the artifact with a range " +
255                                                 versionRange, artifact, remoteRepositories );
256                                     }
257                                     else
258                                     {
259                                         throw new OverConstrainedVersionException( "Couldn't find a version in " +
260                                             versions + " to match range " + versionRange, artifact,
261                                                                                           remoteRepositories );
262                                     }
263                                 }
264                             }
265                             else
266                             {
267                                 version = artifact.getSelectedVersion();
268                             }
269
270                             artifact.selectVersion( version.toString() );
271                             fireEvent( ResolutionListener.SELECT_VERSION_FROM_RANGE, listeners, child );
272                         }
273
274                         artifact.setDependencyTrail( node.getDependencyTrail() );
275                         ResolutionGroup rGroup = source.retrieve( artifact, localRepository, remoteRepositories );
276
277                         //TODO might be better to have source.retreive() throw a specific exception for this situation
278
//and catch here rather than have it return null
279
if ( rGroup == null )
280                         {
281                             //relocated dependency artifact is declared excluded, no need to add and recurse further
282
continue;
283                         }
284
285                         child.addDependencies( rGroup.getArtifacts(), rGroup.getResolutionRepositories(), filter );
286                     }
287                     catch ( CyclicDependencyException e )
288                     {
289                         // would like to throw this, but we have crappy stuff in the repo
290

291                         fireEvent( ResolutionListener.OMIT_FOR_CYCLE, listeners,
292                                    new ResolutionNode( e.getArtifact(), remoteRepositories, child ) );
293                     }
294                     catch ( ArtifactMetadataRetrievalException e )
295                     {
296                         artifact.setDependencyTrail( node.getDependencyTrail() );
297                         throw new ArtifactResolutionException(
298                             "Unable to get dependency information: " + e.getMessage(), artifact, remoteRepositories,
299                             e );
300                     }
301
302                     recurse( child, resolvedArtifacts, managedVersions, localRepository, remoteRepositories, source,
303                              filter, listeners );
304                 }
305             }
306
307             fireEvent( ResolutionListener.FINISH_PROCESSING_CHILDREN, listeners, node );
308         }
309     }
310
311     /**
312      * Check if the scope needs to be updated.
313      * <a HREF="http://docs.codehaus.org/x/IGU#DependencyMediationandConflictResolution-Scoperesolution">More info</a>.
314      *
315      * @param farthest farthest resolution node
316      * @param nearest nearest resolution node
317      * @param listeners
318      */

319     boolean checkScopeUpdate( ResolutionNode farthest, ResolutionNode nearest, List JavaDoc listeners )
320     {
321         boolean updateScope = false;
322         Artifact farthestArtifact = farthest.getArtifact();
323         Artifact nearestArtifact = nearest.getArtifact();
324
325         if ( Artifact.SCOPE_RUNTIME.equals( farthestArtifact.getScope() ) && (
326             Artifact.SCOPE_TEST.equals( nearestArtifact.getScope() ) ||
327                 Artifact.SCOPE_PROVIDED.equals( nearestArtifact.getScope() ) ) )
328         {
329             updateScope = true;
330         }
331
332         if ( Artifact.SCOPE_COMPILE.equals( farthestArtifact.getScope() ) &&
333             !Artifact.SCOPE_COMPILE.equals( nearestArtifact.getScope() ) )
334         {
335             updateScope = true;
336         }
337
338         // current POM rules all
339
if ( nearest.getDepth() < 2 && updateScope )
340         {
341             updateScope = false;
342
343             fireEvent( ResolutionListener.UPDATE_SCOPE_CURRENT_POM, listeners, nearest, farthestArtifact );
344         }
345
346         if ( updateScope )
347         {
348             fireEvent( ResolutionListener.UPDATE_SCOPE, listeners, nearest, farthestArtifact );
349
350             // previously we cloned the artifact, but it is more effecient to just update the scope
351
// if problems are later discovered that the original object needs its original scope value, cloning may
352
// again be appropriate
353
nearestArtifact.setScope( farthestArtifact.getScope() );
354         }
355
356         return updateScope;
357     }
358
359     private void fireEvent( int event, List JavaDoc listeners, ResolutionNode node )
360     {
361         fireEvent( event, listeners, node, null );
362     }
363
364     private void fireEvent( int event, List JavaDoc listeners, ResolutionNode node, Artifact replacement )
365     {
366         fireEvent( event, listeners, node, replacement, null );
367     }
368
369     private void fireEvent( int event, List JavaDoc listeners, ResolutionNode node, Artifact replacement,
370                             VersionRange newRange )
371     {
372         for ( Iterator JavaDoc i = listeners.iterator(); i.hasNext(); )
373         {
374             ResolutionListener listener = (ResolutionListener) i.next();
375
376             switch ( event )
377             {
378                 case ResolutionListener.TEST_ARTIFACT:
379                     listener.testArtifact( node.getArtifact() );
380                     break;
381                 case ResolutionListener.PROCESS_CHILDREN:
382                     listener.startProcessChildren( node.getArtifact() );
383                     break;
384                 case ResolutionListener.FINISH_PROCESSING_CHILDREN:
385                     listener.endProcessChildren( node.getArtifact() );
386                     break;
387                 case ResolutionListener.INCLUDE_ARTIFACT:
388                     listener.includeArtifact( node.getArtifact() );
389                     break;
390                 case ResolutionListener.OMIT_FOR_NEARER:
391                     String JavaDoc version = node.getArtifact().getVersion();
392                     String JavaDoc replacementVersion = replacement.getVersion();
393                     if ( version != null ? !version.equals( replacementVersion ) : replacementVersion != null )
394                     {
395                         listener.omitForNearer( node.getArtifact(), replacement );
396                     }
397                     break;
398                 case ResolutionListener.OMIT_FOR_CYCLE:
399                     listener.omitForCycle( node.getArtifact() );
400                     break;
401                 case ResolutionListener.UPDATE_SCOPE:
402                     listener.updateScope( node.getArtifact(), replacement.getScope() );
403                     break;
404                 case ResolutionListener.UPDATE_SCOPE_CURRENT_POM:
405                     listener.updateScopeCurrentPom( node.getArtifact(), replacement.getScope() );
406                     break;
407                 case ResolutionListener.MANAGE_ARTIFACT:
408                     listener.manageArtifact( node.getArtifact(), replacement );
409                     break;
410                 case ResolutionListener.SELECT_VERSION_FROM_RANGE:
411                     listener.selectVersionFromRange( node.getArtifact() );
412                     break;
413                 case ResolutionListener.RESTRICT_RANGE:
414                     if ( node.getArtifact().getVersionRange().hasRestrictions() ||
415                         replacement.getVersionRange().hasRestrictions() )
416                     {
417                         listener.restrictRange( node.getArtifact(), replacement, newRange );
418                     }
419                     break;
420                 default:
421                     throw new IllegalStateException JavaDoc( "Unknown event: " + event );
422             }
423         }
424     }
425
426 }
427
Popular Tags