View Javadoc
1   package org.apache.maven.plugins.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.LinkedHashMap;
26  import java.util.LinkedHashSet;
27  import java.util.List;
28  import java.util.Map;
29  import java.util.Set;
30  
31  import org.apache.maven.artifact.Artifact;
32  import org.apache.maven.artifact.repository.ArtifactRepository;
33  import org.apache.maven.artifact.resolver.ArtifactResolutionRequest;
34  import org.apache.maven.artifact.resolver.ArtifactResolutionResult;
35  import org.apache.maven.artifact.resolver.MultipleArtifactsNotFoundException;
36  import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
37  import org.apache.maven.plugins.assembly.AssemblerConfigurationSource;
38  import org.apache.maven.plugins.assembly.archive.ArchiveCreationException;
39  import org.apache.maven.plugins.assembly.archive.phase.ModuleSetAssemblyPhase;
40  import org.apache.maven.plugins.assembly.model.Assembly;
41  import org.apache.maven.plugins.assembly.model.DependencySet;
42  import org.apache.maven.plugins.assembly.model.ModuleBinaries;
43  import org.apache.maven.plugins.assembly.model.ModuleSet;
44  import org.apache.maven.plugins.assembly.model.Repository;
45  import org.apache.maven.plugins.assembly.resolved.AssemblyId;
46  import org.apache.maven.plugins.assembly.utils.FilterUtils;
47  import org.apache.maven.project.MavenProject;
48  import org.apache.maven.project.ProjectBuildingRequest;
49  import org.apache.maven.repository.RepositorySystem;
50  import org.apache.maven.shared.artifact.filter.resolve.ScopeFilter;
51  import org.apache.maven.shared.artifact.filter.resolve.transform.ArtifactIncludeFilterTransformer;
52  import org.apache.maven.shared.artifact.resolve.ArtifactResult;
53  import org.apache.maven.shared.dependencies.resolve.DependencyResolverException;
54  import org.codehaus.plexus.component.annotations.Component;
55  import org.codehaus.plexus.component.annotations.Requirement;
56  import org.codehaus.plexus.logging.AbstractLogEnabled;
57  import org.codehaus.plexus.util.StringUtils;
58  
59  /**
60   * @author jdcasey
61   * @version $Id: DefaultDependencyResolver.html 1000516 2016-11-05 01:04:48Z olamy $
62   */
63  @Component( role = DependencyResolver.class )
64  public class DefaultDependencyResolver
65      extends AbstractLogEnabled
66      implements DependencyResolver
67  {
68      @Requirement
69      private RepositorySystem resolver;
70      
71      @Requirement
72      private org.apache.maven.shared.dependencies.resolve.DependencyResolver dependencyResolver;
73  
74      @Override
75      public Map<DependencySet, Set<Artifact>> resolveDependencySets( final Assembly assembly, ModuleSet moduleSet,
76                                                                      final AssemblerConfigurationSource configSource,
77                                                                      List<DependencySet> dependencySets )
78          throws DependencyResolutionException
79      {
80          Map<DependencySet, Set<Artifact>> result = new LinkedHashMap<DependencySet, Set<Artifact>>();
81  
82          for ( DependencySet dependencySet : dependencySets )
83          {
84  
85              final MavenProject currentProject = configSource.getProject();
86  
87              final ResolutionManagementInfo info = new ResolutionManagementInfo( currentProject );
88              updateRepositoryResolutionRequirements( assembly, info );
89              final AssemblyId assemblyId = AssemblyId.createAssemblyId( assembly );
90              updateDependencySetResolutionRequirements( dependencySet, info, assemblyId,
91                                                         configSource.getMavenSession().getProjectBuildingRequest(),
92                                                         currentProject );
93              updateModuleSetResolutionRequirements( assemblyId, moduleSet, dependencySet, info, configSource );
94  
95              resolve( assembly, configSource, result, dependencySet, info );
96  
97          }
98          return result;
99      }
100 
101     private void resolve( Assembly assembly, AssemblerConfigurationSource configSource,
102                           Map<DependencySet, Set<Artifact>> result, DependencySet dependencySet,
103                           ResolutionManagementInfo info )
104         throws DependencyResolutionException
105     {
106         Set<Artifact> artifacts;
107         if ( info.isResolutionRequired() )
108         {
109             final List<ArtifactRepository> repos =
110                 aggregateRemoteArtifactRepositories( configSource.getRemoteRepositories(), info.getEnabledProjects() );
111 
112             artifacts = info.getArtifacts();
113             if ( info.isResolvedTransitively() )
114             {
115                 getLogger().debug( "Resolving project dependencies transitively." );
116                 
117                 ArtifactFilter filter = new ArtifactIncludeFilterTransformer().transform( info.getScopeFilter() );
118                 artifacts = resolveTransitively( artifacts, repos, filter, configSource );
119             }
120             else
121             {
122                 getLogger().debug( "Resolving project dependencies ONLY. "
123                                        + "Transitive dependencies WILL NOT be included in the results." );
124                 artifacts = resolveNonTransitively( assembly, artifacts, configSource, repos );
125             }
126         }
127         else
128         {
129             artifacts = new HashSet<Artifact>();
130         }
131         result.put( dependencySet, artifacts );
132     }
133 
134     @Override
135     public Map<DependencySet, Set<Artifact>> resolveDependencySets( final Assembly assembly,
136                                                                     final AssemblerConfigurationSource configSource,
137                                                                     List<DependencySet> dependencySets )
138         throws DependencyResolutionException
139     {
140         Map<DependencySet, Set<Artifact>> result = new LinkedHashMap<DependencySet, Set<Artifact>>();
141 
142         for ( DependencySet dependencySet : dependencySets )
143         {
144 
145             final MavenProject currentProject = configSource.getProject();
146 
147             final ResolutionManagementInfo info = new ResolutionManagementInfo( currentProject );
148             updateRepositoryResolutionRequirements( assembly, info );
149             final AssemblyId assemblyId = AssemblyId.createAssemblyId( assembly );
150             updateDependencySetResolutionRequirements( dependencySet, info, assemblyId,
151                                                        configSource.getMavenSession().getProjectBuildingRequest(),
152                                                        currentProject );
153 
154             resolve( assembly, configSource, result, dependencySet, info );
155 
156         }
157         return result;
158     }
159 
160     Set<Artifact> resolveNonTransitively( final Assembly assembly, final Set<Artifact> dependencyArtifacts,
161                                           final AssemblerConfigurationSource configSource,
162                                           final List<ArtifactRepository> repos )
163         throws DependencyResolutionException
164     {
165 
166         final List<Artifact> missing = new ArrayList<Artifact>();
167         final Set<Artifact> resolved = new LinkedHashSet<Artifact>();
168         for ( final Artifact depArtifact : dependencyArtifacts )
169         {
170             ArtifactResolutionRequest req = new ArtifactResolutionRequest();
171             req.setLocalRepository( configSource.getLocalRepository() );
172             req.setRemoteRepositories( repos );
173             req.setArtifact( depArtifact );
174 
175             ArtifactResolutionResult resolve = resolver.resolve( req );
176             if ( resolve.hasExceptions() )
177             {
178                 if ( getLogger().isDebugEnabled() )
179                 {
180                     getLogger().debug(
181                         "Failed to resolve: " + depArtifact.getId() + " for assembly: " + assembly.getId() );
182                 }
183                 missing.add( depArtifact );
184             }
185             else
186             {
187                 resolved.add( depArtifact );
188             }
189         }
190 
191         if ( !missing.isEmpty() )
192 
193         {
194             final MavenProject project = configSource.getProject();
195             final Artifact rootArtifact = project.getArtifact();
196 
197             final Throwable error =
198                 new MultipleArtifactsNotFoundException( rootArtifact, new ArrayList<Artifact>( resolved ), missing,
199                                                         repos );
200 
201             throw new DependencyResolutionException( "Failed to resolve dependencies for: " + assembly.getId(), error );
202         }
203 
204         return resolved;
205     }
206 
207     private Set<Artifact> resolveTransitively( final Set<Artifact> dependencyArtifacts,
208                                                final List<ArtifactRepository> repos,
209                                                final ArtifactFilter filter,
210                                                final AssemblerConfigurationSource configSource )
211         throws DependencyResolutionException
212     {
213         final MavenProject project = configSource.getProject();
214 
215         ArtifactResolutionRequest req = new ArtifactResolutionRequest();
216         req.setLocalRepository( configSource.getLocalRepository() );
217         req.setResolveRoot( false );
218         req.setRemoteRepositories( repos );
219         req.setResolveTransitively( true );
220         req.setArtifact( project.getArtifact() );
221         req.setArtifactDependencies( dependencyArtifacts );
222         req.setManagedVersionMap( project.getManagedVersionMap() );
223         req.setCollectionFilter( filter );
224         req.setOffline( configSource.getMavenSession().isOffline() );
225         req.setForceUpdate( configSource.getMavenSession().getRequest().isUpdateSnapshots() );
226         req.setServers( configSource.getMavenSession().getRequest().getServers() );
227         req.setMirrors( configSource.getMavenSession().getRequest().getMirrors() );
228         req.setProxies( configSource.getMavenSession().getRequest().getProxies() );
229 
230         ArtifactResolutionResult result;
231 
232         result = resolver.resolve( req );
233         if ( result.hasExceptions() )
234         {
235             throw new DependencyResolutionException( "Failed to resolve dependencies for assembly: ",
236                                                      result.getExceptions().get( 0 ) );
237         }
238 
239         getLogger().debug( "While resolving dependencies of " + project.getId() + ":" );
240 
241         FilterUtils.reportFilteringStatistics( Collections.singleton( filter ), getLogger() );
242 
243         return result.getArtifacts();
244     }
245 
246     void updateRepositoryResolutionRequirements( final Assembly assembly, final ResolutionManagementInfo requirements )
247     {
248         final List<Repository> repositories = assembly.getRepositories();
249 
250         Set<String> rootScopes = new HashSet<String>();
251         
252         if ( repositories != null && !repositories.isEmpty() )
253         {
254             
255             requirements.setResolutionRequired( true );
256             for ( final Repository repo : repositories )
257             {
258                 rootScopes.add( repo.getScope() );
259             }
260         }
261         
262         requirements.setScopeFilter( FilterUtils.newScopeFilter( rootScopes ) );
263     }
264 
265 
266     void updateModuleSetResolutionRequirements( AssemblyId assemblyId, ModuleSet set, DependencySet dependencySet,
267                                                 final ResolutionManagementInfo requirements,
268                                                 final AssemblerConfigurationSource configSource )
269         throws DependencyResolutionException
270     {
271         final ModuleBinaries binaries = set.getBinaries();
272         if ( binaries != null )
273         {
274             Set<MavenProject> projects;
275             try
276             {
277                 projects = ModuleSetAssemblyPhase.getModuleProjects( set, configSource, getLogger() );
278             }
279             catch ( final ArchiveCreationException e )
280             {
281                 throw new DependencyResolutionException( "Error determining project-set for moduleSet with binaries.",
282                                                          e );
283             }
284 
285             if ( !projects.isEmpty() )
286             {
287                 for ( final MavenProject p : projects )
288                 {
289                     requirements.enableProjectResolution( p );
290 
291                     if ( p.getArtifact() == null )
292                     {
293                         // TODO: such a call in MavenMetadataSource too - packaging not really the intention of
294                         // type
295                         final Artifact artifact =
296                             resolver.createArtifact( p.getGroupId(), p.getArtifactId(), p.getVersion(),
297                                                      p.getPackaging() );
298                         p.setArtifact( artifact );
299                     }
300                 }
301             }
302 
303             if ( binaries.isIncludeDependencies() )
304             {
305                 updateDependencySetResolutionRequirements( dependencySet, requirements, assemblyId,
306                                                            configSource.getMavenSession().getProjectBuildingRequest(),
307                                                            projects.toArray( new MavenProject[projects.size()] ) );
308             }
309         }
310     }
311 
312     void updateDependencySetResolutionRequirements( final DependencySet set,
313                                                     final ResolutionManagementInfo requirements, AssemblyId assemblyId,
314                                                     ProjectBuildingRequest buildingRequest,
315                                                     final MavenProject... projects )
316         throws DependencyResolutionException
317     {
318         requirements.setResolutionRequired( true );
319 
320         requirements.setResolvedTransitively( set.isUseTransitiveDependencies() );
321 
322         ScopeFilter scopeFilter = FilterUtils.newScopeFilter( set.getScope() );
323         
324         requirements.setScopeFilter( scopeFilter );
325         
326         for ( final MavenProject project : projects )
327         {
328             if ( project == null )
329             {
330                 continue;
331             }
332 
333             Set<Artifact> dependencyArtifacts = project.getDependencyArtifacts();
334             if ( dependencyArtifacts == null )
335             {
336                 try
337                 {
338                     Iterable<ArtifactResult> artifactResults =
339                         dependencyResolver.resolveDependencies( buildingRequest, project.getModel(), scopeFilter );
340                     
341                     dependencyArtifacts = new HashSet<Artifact>();
342                     
343                     for ( ArtifactResult artifactResult : artifactResults )
344                     {
345                         dependencyArtifacts.add( artifactResult.getArtifact() );
346                     }
347                     
348                     project.setDependencyArtifacts( dependencyArtifacts );
349                 }
350                 catch ( final DependencyResolverException e )
351                 {
352                     throw new DependencyResolutionException(
353                         "Failed to create dependency artifacts for resolution. Assembly: " + assemblyId, e );
354                 }
355             }
356 
357             requirements.addArtifacts( dependencyArtifacts );
358             getLogger().debug( "Dependencies for project: " + project.getId() + " are:\n" + StringUtils.join(
359                 dependencyArtifacts.iterator(), "\n" ) );
360         }
361     }
362 
363     List<ArtifactRepository> aggregateRemoteArtifactRepositories( final List<ArtifactRepository> remoteRepositories,
364                                                                   final Set<MavenProject> projects )
365     {
366         final List<List<ArtifactRepository>> repoLists = new ArrayList<List<ArtifactRepository>>();
367 
368         repoLists.add( remoteRepositories );
369         for ( final MavenProject project : projects )
370         {
371             repoLists.add( project.getRemoteArtifactRepositories() );
372         }
373 
374         final List<ArtifactRepository> remoteRepos = new ArrayList<ArtifactRepository>();
375         final Set<String> encounteredUrls = new HashSet<String>();
376 
377         for ( final List<ArtifactRepository> repositoryList : repoLists )
378         {
379             if ( ( repositoryList != null ) && !repositoryList.isEmpty() )
380             {
381                 for ( final ArtifactRepository repo : repositoryList )
382                 {
383                     if ( !encounteredUrls.contains( repo.getUrl() ) )
384                     {
385                         remoteRepos.add( repo );
386                         encounteredUrls.add( repo.getUrl() );
387                     }
388                 }
389             }
390         }
391 
392         return remoteRepos;
393     }
394 
395 }