View Javadoc
1   package com.atlassian.plugin.spring.scanner.maven;
2   
3   import com.google.common.base.Function;
4   import com.google.common.base.Optional;
5   import com.google.common.base.Predicate;
6   import com.google.common.collect.Iterables;
7   import org.apache.maven.artifact.Artifact;
8   import org.apache.maven.model.Dependency;
9   import org.apache.maven.model.Exclusion;
10  import org.apache.maven.shared.dependency.graph.DependencyNode;
11  import org.apache.maven.shared.dependency.graph.filter.DependencyNodeFilter;
12  import org.apache.maven.shared.dependency.graph.traversal.CollectingDependencyNodeVisitor;
13  import org.apache.maven.shared.dependency.graph.traversal.DependencyNodeVisitor;
14  import org.apache.maven.shared.dependency.graph.traversal.FilteringDependencyNodeVisitor;
15  
16  import java.util.ArrayList;
17  import java.util.List;
18  
19  import static com.google.common.collect.Lists.newArrayList;
20  
21  /**
22   * This finds all transitive dependencies of the built artifact and cross reference them to the named
23   * scanned deps and includes any transitive deps of those named scanned dependencies by default UNLESS
24   * there is 'exclusions' named on the configuration
25   */
26  class ScannedDependencyArtifactBuilder {
27  
28      static List<Artifact> buildScannedArtifacts(final DependencyNode projectDependencyGraph, final List<Dependency> configuredScannedDependencies) {
29          final List<Artifact> artifacts = new ArrayList<Artifact>();
30  
31          projectDependencyGraph.accept(new DependencyNodeVisitor() {
32              @Override
33              public boolean visit(DependencyNode node) {
34                  return true;
35              }
36  
37              @Override
38              public boolean endVisit(DependencyNode node) {
39                  Artifact artifact = node.getArtifact();
40                  Optional<Dependency> dependencyOption = artifactInConfiguredList(artifact, configuredScannedDependencies);
41                  if (dependencyOption.isPresent()) {
42                      artifacts.addAll(findIncludedTransitiveDeps(node, dependencyOption.get()));
43                  }
44                  return true;
45              }
46          });
47          return artifacts;
48      }
49  
50      private static Optional<Dependency> artifactInConfiguredList(final Artifact artifact, List<Dependency> configuredScannedDependencies) {
51  
52          Predicate<Dependency> predicate = new Predicate<Dependency>() {
53  
54              @Override
55              public boolean apply(Dependency input) {
56  
57                  if (! "*".equals(input.getArtifactId())) {
58  
59                      return
60                              input.getGroupId().equals(artifact.getGroupId()) &&
61                                      input.getArtifactId().equals(artifact.getArtifactId());
62  
63                  } else {
64  
65                      return input.getGroupId().equals(artifact.getGroupId());
66                  }
67              }
68          };
69  
70          return Optional.fromNullable(Iterables.find(configuredScannedDependencies, predicate, null));
71      }
72  
73      /**
74       * This method descends the specified node and adds all transitive dependencies to the list of artifacts UNLESS the
75       * configuration says that there are exclusions
76       *
77       * @param dependencyNode the graph node
78       * @param dependency     the configuration dependency from maven config
79       *
80       * @return a list of included transitive deps
81       */
82      private static List<Artifact> findIncludedTransitiveDeps(DependencyNode dependencyNode, final Dependency dependency) {
83          //
84          // we want all the transitive deps to be scanned as long as they are not explicitly excluded
85          DependencyNodeFilter includedDeps = new DependencyNodeFilter() {
86              @Override
87              public boolean accept(DependencyNode node) {
88                  return !isExcluded(node.getArtifact(), dependency.getExclusions());
89              }
90          };
91          CollectingDependencyNodeVisitor collector = new CollectingDependencyNodeVisitor();
92          FilteringDependencyNodeVisitor filterer = new FilteringDependencyNodeVisitor(collector, includedDeps);
93          dependencyNode.accept(filterer);
94  
95          List<DependencyNode> nodes = collector.getNodes();
96          return newArrayList(Iterables.transform(nodes, new Function<DependencyNode, Artifact>() {
97              @Override
98              public Artifact apply(DependencyNode input) {
99                  return input.getArtifact();
100             }
101         }));
102 
103     }
104 
105     private static boolean isExcluded(Artifact artifact, List<Exclusion> exclusions) {
106         for (Exclusion exclusion : exclusions) {
107             if (exclusion.getGroupId().equals(artifact.getGroupId()) && exclusion.getArtifactId().equals(artifact.getArtifactId())) {
108                 return true;
109             }
110         }
111         return false;
112     }
113 }
114