View Javadoc
1   package org.apache.maven.plugin.assembly.artifact;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.util.ArrayList;
23  import java.util.Collections;
24  import java.util.HashSet;
25  import java.util.LinkedHashSet;
26  import java.util.List;
27  import java.util.Set;
28  
29  import org.apache.maven.artifact.Artifact;
30  import org.apache.maven.artifact.factory.ArtifactFactory;
31  import org.apache.maven.artifact.metadata.ArtifactMetadataSource;
32  import org.apache.maven.artifact.repository.ArtifactRepository;
33  import org.apache.maven.artifact.resolver.ArtifactCollector;
34  import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
35  import org.apache.maven.artifact.resolver.ArtifactResolutionException;
36  import org.apache.maven.artifact.resolver.ArtifactResolutionResult;
37  import org.apache.maven.artifact.resolver.ArtifactResolver;
38  import org.apache.maven.artifact.resolver.MultipleArtifactsNotFoundException;
39  import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
40  import org.apache.maven.plugin.assembly.AssemblerConfigurationSource;
41  import org.apache.maven.plugin.assembly.AssemblyContext;
42  import org.apache.maven.plugin.assembly.archive.ArchiveCreationException;
43  import org.apache.maven.plugin.assembly.archive.phase.ModuleSetAssemblyPhase;
44  import org.apache.maven.plugin.assembly.model.Assembly;
45  import org.apache.maven.plugin.assembly.model.DependencySet;
46  import org.apache.maven.plugin.assembly.model.ModuleBinaries;
47  import org.apache.maven.plugin.assembly.model.ModuleSet;
48  import org.apache.maven.plugin.assembly.model.Repository;
49  import org.apache.maven.plugin.assembly.utils.FilterUtils;
50  import org.apache.maven.project.MavenProject;
51  import org.apache.maven.project.artifact.InvalidDependencyVersionException;
52  import org.codehaus.plexus.component.annotations.Component;
53  import org.codehaus.plexus.component.annotations.Requirement;
54  import org.codehaus.plexus.logging.AbstractLogEnabled;
55  import org.codehaus.plexus.logging.Logger;
56  import org.codehaus.plexus.util.StringUtils;
57  
58  /**
59   * @author jdcasey
60   * @version $Id: DefaultDependencyResolver.java 1601216 2014-06-08 11:58:09Z khmarbaise $
61   */
62  @Component( role = DependencyResolver.class )
63  public class DefaultDependencyResolver
64      extends AbstractLogEnabled
65      implements DependencyResolver
66  {
67  
68      @Requirement
69      private ArtifactResolver resolver;
70  
71      @Requirement
72      private ArtifactMetadataSource metadataSource;
73  
74      @Requirement
75      private ArtifactFactory factory;
76  
77      @Requirement
78      private ArtifactCollector collector;
79  
80      public DefaultDependencyResolver()
81      {
82          // for plexus init
83      }
84  
85      protected DefaultDependencyResolver( final ArtifactResolver resolver, final ArtifactMetadataSource metadataSource,
86                                           final ArtifactFactory factory, final ArtifactCollector collector,
87                                           final Logger logger )
88      {
89          this.resolver = resolver;
90          this.metadataSource = metadataSource;
91          this.factory = factory;
92          this.collector = collector;
93  
94          enableLogging( logger );
95      }
96  
97      public void resolve( final Assembly assembly, final AssemblerConfigurationSource configSource,
98                           final AssemblyContext context )
99          throws DependencyResolutionException
100     {
101         final MavenProject currentProject = configSource.getProject();
102 
103         final ResolutionManagementInfo info = new ResolutionManagementInfo( currentProject );
104         getRepositoryResolutionRequirements( assembly, info, currentProject );
105         getDependencySetResolutionRequirements( assembly, assembly.getDependencySets(), info, currentProject );
106         getModuleSetResolutionRequirements( assembly, info, configSource );
107 
108         if ( !info.isResolutionRequired() )
109         {
110             context.setResolvedArtifacts( new HashSet<Artifact>() );
111             return;
112         }
113 
114         final List<ArtifactRepository> repos =
115             aggregateRemoteArtifactRepositories( configSource.getRemoteRepositories(), info.getEnabledProjects() );
116 
117         Set<Artifact> artifacts = info.getArtifacts();
118         if ( info.isResolvedTransitively() )
119         {
120             getLogger().debug( "Resolving project dependencies transitively." );
121             artifacts = resolveTransitively( artifacts, repos, info, configSource );
122         }
123         else
124         {
125             getLogger().debug( "Resolving project dependencies ONLY. Transitive dependencies WILL NOT be included in the results." );
126             artifacts = resolveNonTransitively( assembly, artifacts, configSource, repos );
127         }
128 
129         context.setResolvedArtifacts( artifacts );
130     }
131 
132     protected Set<Artifact> resolveNonTransitively( final Assembly assembly, final Set<Artifact> dependencyArtifacts,
133                                                     final AssemblerConfigurationSource configSource,
134                                                     final List<ArtifactRepository> repos )
135         throws DependencyResolutionException
136     {
137 
138         final List<Artifact> missing = new ArrayList<Artifact>();
139         final Set<Artifact> resolved = new LinkedHashSet<Artifact>();
140         for (final Artifact depArtifact : dependencyArtifacts) {
141             try {
142                 resolver.resolve(depArtifact, repos, configSource.getLocalRepository());
143                 resolved.add(depArtifact);
144             } catch (final ArtifactResolutionException e) {
145                 if (getLogger().isDebugEnabled()) {
146                     getLogger().debug("Failed to resolve: " + depArtifact.getId() + " for assembly: "
147                             + assembly.getId());
148                 }
149                 missing.add(depArtifact);
150             } catch (final ArtifactNotFoundException e) {
151                 if (getLogger().isDebugEnabled()) {
152                     getLogger().debug("Failed to resolve: " + depArtifact.getId() + " for assembly: "
153                             + assembly.getId());
154                 }
155                 missing.add(depArtifact);
156             }
157         }
158 
159         if ( !missing.isEmpty() )
160         {
161             final MavenProject project = configSource.getProject();
162             final Artifact rootArtifact = project.getArtifact();
163 
164             final Throwable error =
165                 new MultipleArtifactsNotFoundException( rootArtifact, new ArrayList<Artifact>( resolved ), missing,
166                                                         repos );
167 
168             throw new DependencyResolutionException( "Failed to resolve dependencies for: " + assembly.getId(), error );
169         }
170 
171         return resolved;
172     }
173 
174     @SuppressWarnings( "unchecked" )
175     private Set<Artifact> resolveTransitively( final Set<Artifact> dependencyArtifacts,
176                                                final List<ArtifactRepository> repos,
177                                                final ResolutionManagementInfo info,
178                                                final AssemblerConfigurationSource configSource )
179         throws DependencyResolutionException
180     {
181         final MavenProject project = configSource.getProject();
182 
183         final ArtifactFilter filter = info.getScopeFilter();
184         final ArtifactRepository localRepository = configSource.getLocalRepository();
185 
186         ArtifactResolutionResult result;
187         try
188         {
189             result =
190                 resolver.resolveTransitively( dependencyArtifacts, project.getArtifact(),
191                                               project.getManagedVersionMap(), localRepository, repos, metadataSource,
192                                               filter );
193         }
194         catch ( final ArtifactResolutionException e )
195         {
196             throw new DependencyResolutionException( "Failed to resolve dependencies for assembly: ", e );
197         }
198         catch ( final ArtifactNotFoundException e )
199         {
200             throw new DependencyResolutionException( "Failed to resolve dependencies for assembly: ", e );
201         }
202 
203         getLogger().debug( "While resolving dependencies of " + project.getId() + ":" );
204 
205         FilterUtils.reportFilteringStatistics( Collections.singleton( filter ), getLogger() );
206 
207         return result.getArtifacts();
208     }
209 
210     protected void getRepositoryResolutionRequirements( final Assembly assembly,
211                                                         final ResolutionManagementInfo requirements,
212                                                         final MavenProject... project )
213     {
214         final List<Repository> repositories = assembly.getRepositories();
215 
216         if ( repositories != null && !repositories.isEmpty() )
217         {
218             requirements.setResolutionRequired( true );
219             for ( final Repository repo : repositories )
220             {
221                 enableScope( repo.getScope(), requirements );
222             }
223         }
224     }
225 
226     protected void getModuleSetResolutionRequirements( final Assembly assembly,
227                                                        final ResolutionManagementInfo requirements,
228                                                        final AssemblerConfigurationSource configSource )
229         throws DependencyResolutionException
230     {
231         final List<ModuleSet> moduleSets = assembly.getModuleSets();
232 
233         if ( moduleSets != null && !moduleSets.isEmpty() )
234         {
235             for ( final ModuleSet set : moduleSets )
236             {
237                 final ModuleBinaries binaries = set.getBinaries();
238                 if ( binaries != null )
239                 {
240                     Set<MavenProject> projects;
241                     try
242                     {
243                         projects = ModuleSetAssemblyPhase.getModuleProjects( set, configSource, getLogger() );
244                     }
245                     catch ( final ArchiveCreationException e )
246                     {
247                         throw new DependencyResolutionException(
248                                                                  "Error determining project-set for moduleSet with binaries.",
249                                                                  e );
250                     }
251 
252                     if ( projects != null && !projects.isEmpty() )
253                     {
254                         for ( final MavenProject p : projects )
255                         {
256                             requirements.enableProjectResolution( p );
257 
258                             if ( p.getArtifact() == null )
259                             {
260                                 // TODO: such a call in MavenMetadataSource too - packaging not really the intention of
261                                 // type
262                                 final Artifact artifact =
263                                     factory.createBuildArtifact( p.getGroupId(), p.getArtifactId(), p.getVersion(),
264                                                                  p.getPackaging() );
265                                 p.setArtifact( artifact );
266                             }
267                         }
268                     }
269 
270                     if ( binaries.isIncludeDependencies() )
271                     {
272                         getDependencySetResolutionRequirements( assembly,
273                                                                 ModuleSetAssemblyPhase.getDependencySets( binaries ),
274                                                                 requirements, projects.toArray(new MavenProject[projects.size()]));
275                     }
276                 }
277             }
278         }
279     }
280 
281     @SuppressWarnings( "unchecked" )
282     protected void getDependencySetResolutionRequirements( final Assembly assembly, final List<DependencySet> depSets,
283                                                            final ResolutionManagementInfo requirements,
284                                                            final MavenProject... projects )
285         throws DependencyResolutionException
286     {
287         if ( depSets != null && !depSets.isEmpty() )
288         {
289             requirements.setResolutionRequired( true );
290 
291             for ( final DependencySet set : depSets )
292             {
293                 requirements.setResolvedTransitively( set.isUseTransitiveDependencies() );
294 
295                 enableScope( set.getScope(), requirements );
296             }
297 
298             for ( final MavenProject project : projects )
299             {
300                 if ( project == null )
301                 {
302                     continue;
303                 }
304 
305                 Set<Artifact> dependencyArtifacts = project.getDependencyArtifacts();
306                 if ( dependencyArtifacts == null )
307                 {
308                     try
309                     {
310                         dependencyArtifacts = project.createArtifacts( factory, null, requirements.getScopeFilter() );
311                         project.setDependencyArtifacts( dependencyArtifacts );
312                     }
313                     catch ( final InvalidDependencyVersionException e )
314                     {
315                         throw new DependencyResolutionException(
316                                                                  "Failed to create dependency artifacts for resolution. Assembly: "
317                                                                      + assembly.getId(), e );
318                     }
319                 }
320 
321                 requirements.addArtifacts( dependencyArtifacts );
322                 getLogger().debug( "Dependencies for project: " + project.getId() + " are:\n"
323                                        + StringUtils.join( dependencyArtifacts.iterator(), "\n" ) );
324             }
325         }
326     }
327 
328     private void enableScope( final String scope, final ResolutionManagementInfo requirements )
329     {
330         if ( Artifact.SCOPE_COMPILE.equals( scope ) )
331         {
332             requirements.enableCompileScope();
333         }
334         else if ( Artifact.SCOPE_PROVIDED.equals( scope ) )
335         {
336             requirements.enableProvidedScope();
337         }
338         else if ( Artifact.SCOPE_RUNTIME.equals( scope ) )
339         {
340             requirements.enableRuntimeScope();
341         }
342         else if ( Artifact.SCOPE_SYSTEM.equals( scope ) )
343         {
344             requirements.enableSystemScope();
345         }
346         else if ( Artifact.SCOPE_TEST.equals( scope ) )
347         {
348             requirements.enableTestScope();
349         }
350     }
351 
352     @SuppressWarnings( "unchecked" )
353     protected List<ArtifactRepository> aggregateRemoteArtifactRepositories( final List<ArtifactRepository> remoteRepositories,
354                                                                             final Set<MavenProject> projects )
355     {
356         final List<List<ArtifactRepository>> repoLists = new ArrayList<List<ArtifactRepository>>();
357 
358         repoLists.add( remoteRepositories );
359         for ( final MavenProject project : projects )
360         {
361             repoLists.add( project.getRemoteArtifactRepositories() );
362         }
363 
364         final List<ArtifactRepository> remoteRepos = new ArrayList<ArtifactRepository>();
365         final Set<String> encounteredUrls = new HashSet<String>();
366 
367         for (final List<ArtifactRepository> repositoryList : repoLists) {
368             if ((repositoryList != null) && !repositoryList.isEmpty()) {
369                 for (final ArtifactRepository repo : repositoryList) {
370                     if (!encounteredUrls.contains(repo.getUrl())) {
371                         remoteRepos.add(repo);
372                         encounteredUrls.add(repo.getUrl());
373                     }
374                 }
375             }
376         }
377 
378         return remoteRepos;
379     }
380 
381     protected ArtifactResolver getArtifactResolver()
382     {
383         return resolver;
384     }
385 
386     protected DefaultDependencyResolver setArtifactResolver( final ArtifactResolver resolver )
387     {
388         this.resolver = resolver;
389 
390         return this;
391     }
392 
393     protected ArtifactMetadataSource getArtifactMetadataSource()
394     {
395         return metadataSource;
396     }
397 
398     protected DefaultDependencyResolver setArtifactMetadataSource( final ArtifactMetadataSource metadataSource )
399     {
400         this.metadataSource = metadataSource;
401 
402         return this;
403     }
404 
405     protected ArtifactFactory getArtifactFactory()
406     {
407         return factory;
408     }
409 
410     protected DefaultDependencyResolver setArtifactFactory( final ArtifactFactory factory )
411     {
412         this.factory = factory;
413 
414         return this;
415     }
416 
417     protected ArtifactCollector getArtifactCollector()
418     {
419         return collector;
420     }
421 
422     protected DefaultDependencyResolver setArtifactCollector( final ArtifactCollector collector )
423     {
424         this.collector = collector;
425 
426         return this;
427     }
428 
429     protected DefaultDependencyResolver setLogger( final Logger logger )
430     {
431         enableLogging( logger );
432 
433         return this;
434     }
435 
436 }