View Javadoc
1   /*******************************************************************************
2    * Copyright (c) 2010, 2013-2014 Sonatype, Inc.
3    * All rights reserved. This program and the accompanying materials
4    * are made available under the terms of the Eclipse Public License v1.0
5    * which accompanies this distribution, and is available at
6    * http://www.eclipse.org/legal/epl-v10.html
7    *
8    * Contributors:
9    *    Sonatype, Inc. - initial API and implementation
10   *    Julien Carsique
11   *******************************************************************************/
12  package org.nuxeo.build.maven.graph;
13  
14  import java.util.ArrayList;
15  import java.util.Arrays;
16  import java.util.Collection;
17  import java.util.HashSet;
18  import java.util.TreeSet;
19  
20  import org.eclipse.aether.collection.DependencyCollectionContext;
21  import org.eclipse.aether.collection.DependencySelector;
22  import org.eclipse.aether.graph.Dependency;
23  
24  /**
25   * A dependency selector that filters transitive dependencies based on their
26   * scope. Direct dependencies are always
27   * included regardless of their scope. <em>Note:</em> This filter does not
28   * assume any relationships between the scopes.
29   * In particular, the filter is not aware of scopes that logically include other
30   * scopes.
31   *
32   * Copy from org.eclipse.aether.util.graph.selector.ScopeDependencySelector,
33   * change is in {@link #deriveChildSelector(DependencyCollectionContext)}.
34   *
35   * @see Dependency#getScope()
36   */
37  public final class ScopeDependencySelector implements DependencySelector {
38  
39      private final boolean transitive;
40  
41      private final Collection<String> included;
42  
43      private final Collection<String> excluded;
44  
45      /**
46       * Creates a new selector using the specified includes and excludes.
47       *
48       * @param included The set of scopes to include, may be {@code null} or
49       *            empty to include any scope.
50       * @param excluded The set of scopes to exclude, may be {@code null} or
51       *            empty to exclude no scope.
52       */
53      public ScopeDependencySelector(Collection<String> included,
54              Collection<String> excluded) {
55          transitive = false;
56          this.included = clone(included);
57          this.excluded = clone(excluded);
58      }
59  
60      private static Collection<String> clone(Collection<String> scopes) {
61          Collection<String> copy;
62          if (scopes == null || scopes.isEmpty()) {
63              // checking for null is faster than isEmpty()
64              copy = null;
65          } else {
66              copy = new HashSet<>(scopes);
67              if (copy.size() <= 2) {
68                  // contains() is faster for smallish array (sorted for
69                  // equals()!)
70                  copy = new ArrayList<>(new TreeSet<>(copy));
71              }
72          }
73          return copy;
74      }
75  
76      /**
77       * Creates a new selector using the specified excludes.
78       *
79       * @param excluded The set of scopes to exclude, may be {@code null} or
80       *            empty to exclude no scope.
81       */
82      public ScopeDependencySelector(String... excluded) {
83          this(null, (excluded != null) ? Arrays.asList(excluded) : null);
84      }
85  
86      private ScopeDependencySelector(boolean transitive,
87              Collection<String> included, Collection<String> excluded) {
88          this.transitive = transitive;
89          this.included = included;
90          this.excluded = excluded;
91      }
92  
93      @Override
94      public boolean selectDependency(Dependency dependency) {
95          if (!transitive) {
96              return true;
97          }
98  
99          String scope = dependency.getScope();
100         return (included == null || included.contains(scope))
101                 && (excluded == null || !excluded.contains(scope));
102     }
103 
104     @Override
105     public DependencySelector deriveChildSelector(
106             DependencyCollectionContext context) {
107         if (this.transitive || context.getDependency() == null) {
108             return this;
109         }
110 
111         // Here, we consider the deriveChildSelector as transitive only if the
112         // dependency related to the current selector has a defined scope.
113         return new ScopeDependencySelector(
114                 context.getDependency().getScope().length() > 0, included,
115                 excluded);
116     }
117 
118     @Override
119     public boolean equals(Object obj) {
120         if (this == obj) {
121             return true;
122         } else if (null == obj || !getClass().equals(obj.getClass())) {
123             return false;
124         }
125 
126         ScopeDependencySelector that = (ScopeDependencySelector) obj;
127         return transitive == that.transitive && eq(included, that.included)
128                 && eq(excluded, that.excluded);
129     }
130 
131     private static <T> boolean eq(T o1, T o2) {
132         return (o1 != null) ? o1.equals(o2) : o2 == null;
133     }
134 
135     @Override
136     public int hashCode() {
137         int hash = 17;
138         hash = hash * 31 + (transitive ? 1 : 0);
139         hash = hash * 31 + (included != null ? included.hashCode() : 0);
140         hash = hash * 31 + (excluded != null ? excluded.hashCode() : 0);
141         return hash;
142     }
143 
144 }