View Javadoc
1   package org.apache.maven.shared.dependency.graph.internal;
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 static org.eclipse.aether.util.graph.manager.DependencyManagerUtils.NODE_DATA_PREMANAGED_VERSION;
23  
24  import java.util.ArrayList;
25  import java.util.Collections;
26  import java.util.List;
27  
28  import org.apache.maven.RepositoryUtils;
29  import org.apache.maven.artifact.Artifact;
30  import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
31  import org.apache.maven.project.DefaultDependencyResolutionRequest;
32  import org.apache.maven.project.DependencyResolutionException;
33  import org.apache.maven.project.DependencyResolutionRequest;
34  import org.apache.maven.project.DependencyResolutionResult;
35  import org.apache.maven.project.MavenProject;
36  import org.apache.maven.project.ProjectBuildingRequest;
37  import org.apache.maven.project.ProjectDependenciesResolver;
38  import org.apache.maven.shared.dependency.graph.DependencyGraphBuilder;
39  import org.apache.maven.shared.dependency.graph.DependencyGraphBuilderException;
40  import org.apache.maven.shared.dependency.graph.DependencyNode;
41  import org.codehaus.plexus.component.annotations.Component;
42  import org.codehaus.plexus.component.annotations.Requirement;
43  import org.codehaus.plexus.logging.AbstractLogEnabled;
44  import org.eclipse.aether.DefaultRepositorySystemSession;
45  import org.eclipse.aether.RepositorySystemSession;
46  import org.eclipse.aether.graph.Dependency;
47  import org.eclipse.aether.graph.DependencyFilter;
48  import org.eclipse.aether.graph.Exclusion;
49  import org.eclipse.aether.util.graph.manager.DependencyManagerUtils;
50  import org.eclipse.aether.version.VersionConstraint;
51  
52  /**
53   * Wrapper around Eclipse Aether dependency resolver, used in Maven 3.1.
54   *
55   * @see ProjectDependenciesResolver
56   * @author Hervé Boutemy
57   * @since 2.1
58   */
59  @Component( role = DependencyGraphBuilder.class, hint = "maven31" )
60  public class Maven31DependencyGraphBuilder
61      extends AbstractLogEnabled
62      implements DependencyGraphBuilder
63  {
64      @Requirement
65      private ProjectDependenciesResolver resolver;
66  
67      private final ExceptionHandler<DependencyGraphBuilderException> exceptionHandler;
68      
69      public Maven31DependencyGraphBuilder()
70      {
71          this.exceptionHandler = DependencyGraphBuilderException::new;
72      }
73  
74      /**
75       * Builds the dependency graph for Maven 3.1+.
76       *
77       * @param buildingRequest the buildingRequest
78       * @param filter artifact filter (can be <code>null</code>)
79       * @return DependencyNode containing the dependency graph.
80       * @throws DependencyGraphBuilderException if some of the dependencies could not be resolved.
81       */
82      @Override
83      public DependencyNode buildDependencyGraph( ProjectBuildingRequest buildingRequest, ArtifactFilter filter )
84          throws DependencyGraphBuilderException
85      {
86          MavenProject project = buildingRequest.getProject();
87  
88          RepositorySystemSession session =
89              (RepositorySystemSession) Invoker.invoke( buildingRequest, "getRepositorySession", exceptionHandler );
90  
91          
92          if ( Boolean.TRUE != session.getConfigProperties().get( NODE_DATA_PREMANAGED_VERSION ) )
93          {
94              DefaultRepositorySystemSession newSession = new DefaultRepositorySystemSession( session );
95              newSession.setConfigProperty( NODE_DATA_PREMANAGED_VERSION, true );
96              session = newSession;
97          }         
98  
99          final DependencyResolutionRequest request = new DefaultDependencyResolutionRequest();
100         request.setMavenProject( project );
101         Invoker.invoke( request, "setRepositorySession", RepositorySystemSession.class, session );
102         // only download the poms, not the artifacts
103         DependencyFilter collectFilter = ( node, parents ) -> false;
104         Invoker.invoke( request, "setResolutionFilter", DependencyFilter.class, collectFilter );
105 
106         final DependencyResolutionResult result = resolveDependencies( request );
107         org.eclipse.aether.graph.DependencyNode graph =
108             (org.eclipse.aether.graph.DependencyNode) Invoker.invoke( DependencyResolutionResult.class, result,
109                                                                       "getDependencyGraph", exceptionHandler );
110 
111         return buildDependencyNode( null, graph, project.getArtifact(), filter );
112     }
113 
114     private DependencyResolutionResult resolveDependencies( DependencyResolutionRequest request )
115         throws DependencyGraphBuilderException
116     {
117         try
118         {
119             return resolver.resolve( request );
120         }
121         catch ( DependencyResolutionException e )
122         {
123             throw new DependencyGraphBuilderException( "Could not resolve following dependencies: "
124                 + e.getResult().getUnresolvedDependencies(), e );
125         }
126     }
127 
128     private Artifact getDependencyArtifact( Dependency dep )
129     {
130         org.eclipse.aether.artifact.Artifact artifact = dep.getArtifact();
131 
132         try
133         {
134             Artifact mavenArtifact = (Artifact) Invoker.invoke( RepositoryUtils.class, "toArtifact",
135                                               org.eclipse.aether.artifact.Artifact.class, artifact, exceptionHandler );
136 
137             mavenArtifact.setScope( dep.getScope() );
138             mavenArtifact.setOptional( dep.isOptional() );
139 
140             return mavenArtifact;
141         }
142         catch ( DependencyGraphBuilderException e )
143         {
144             // ReflectionException should not happen
145             throw new RuntimeException( e.getMessage(), e );
146         }
147     }
148 
149     private DependencyNode buildDependencyNode( DependencyNode parent, org.eclipse.aether.graph.DependencyNode node,
150                                                 Artifact artifact, ArtifactFilter filter )
151     {
152         String premanagedVersion = DependencyManagerUtils.getPremanagedVersion( node );
153         String premanagedScope = DependencyManagerUtils.getPremanagedScope( node );
154 
155         List<org.apache.maven.model.Exclusion> exclusions = null;
156         Boolean optional = null;
157         if ( node.getDependency() != null )
158         {
159             exclusions = new ArrayList<>( node.getDependency().getExclusions().size() );
160             for ( Exclusion exclusion : node.getDependency().getExclusions() )
161             {
162                 org.apache.maven.model.Exclusion modelExclusion = new org.apache.maven.model.Exclusion();
163                 modelExclusion.setGroupId( exclusion.getGroupId() );
164                 modelExclusion.setArtifactId( exclusion.getArtifactId() );
165                 exclusions.add( modelExclusion );
166             }
167         }
168 
169         DefaultDependencyNode current =
170             new DefaultDependencyNode( parent, artifact, premanagedVersion, premanagedScope,
171                                        getVersionSelectedFromRange( node.getVersionConstraint() ),
172                                        optional, exclusions );
173 
174         List<DependencyNode> nodes = new ArrayList<>( node.getChildren().size() );
175         for ( org.eclipse.aether.graph.DependencyNode child : node.getChildren() )
176         {
177             Artifact childArtifact = getDependencyArtifact( child.getDependency() );
178 
179             if ( ( filter == null ) || filter.include( childArtifact ) )
180             {
181                 nodes.add( buildDependencyNode( current, child, childArtifact, filter ) );
182             }
183         }
184 
185         current.setChildren( Collections.unmodifiableList( nodes ) );
186 
187         return current;
188     }
189 
190     private String getVersionSelectedFromRange( VersionConstraint constraint )
191     {
192         if ( ( constraint == null ) || ( constraint.getVersion() != null ) )
193         {
194             return null;
195         }
196 
197         return constraint.getRange().toString();
198     }
199 }