View Javadoc
1   package org.eclipse.aether.util.graph.selector;
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.Arrays;
24  import java.util.Collection;
25  import java.util.HashSet;
26  import java.util.Objects;
27  import java.util.TreeSet;
28  
29  import org.eclipse.aether.collection.DependencyCollectionContext;
30  import org.eclipse.aether.collection.DependencySelector;
31  import org.eclipse.aether.graph.Dependency;
32  
33  import static java.util.Objects.requireNonNull;
34  
35  /**
36   * A dependency selector that filters transitive dependencies based on their scope. Direct dependencies are always
37   * included regardless of their scope. <em>Note:</em> This filter does not assume any relationships between the scopes.
38   * In particular, the filter is not aware of scopes that logically include other scopes.
39   * 
40   * @see Dependency#getScope()
41   */
42  public final class ScopeDependencySelector
43      implements DependencySelector
44  {
45  
46      private final boolean transitive;
47  
48      private final Collection<String> included;
49  
50      private final Collection<String> excluded;
51  
52      /**
53       * Creates a new selector using the specified includes and excludes.
54       * 
55       * @param included The set of scopes to include, may be {@code null} or empty to include any scope.
56       * @param excluded The set of scopes to exclude, may be {@code null} or empty to exclude no scope.
57       */
58      public ScopeDependencySelector( Collection<String> included, Collection<String> excluded )
59      {
60          transitive = false;
61          this.included = clone( included );
62          this.excluded = clone( excluded );
63      }
64  
65      private static Collection<String> clone( Collection<String> scopes )
66      {
67          Collection<String> copy;
68          if ( scopes == null || scopes.isEmpty() )
69          {
70              // checking for null is faster than isEmpty()
71              copy = null;
72          }
73          else
74          {
75              copy = new HashSet<>( scopes );
76              if ( copy.size() <= 2 )
77              {
78                  // contains() is faster for smallish array (sorted for equals()!)
79                  copy = new ArrayList<>( new TreeSet<>( copy ) );
80              }
81          }
82          return copy;
83      }
84  
85      /**
86       * Creates a new selector using the specified excludes.
87       * 
88       * @param excluded The set of scopes to exclude, may be {@code null} or empty to exclude no scope.
89       */
90      public ScopeDependencySelector( String... excluded )
91      {
92          this( null, ( excluded != null ) ? Arrays.asList( excluded ) : null );
93      }
94  
95      private ScopeDependencySelector( boolean transitive, Collection<String> included, Collection<String> excluded )
96      {
97          this.transitive = transitive;
98          this.included = included;
99          this.excluded = excluded;
100     }
101 
102     public boolean selectDependency( Dependency dependency )
103     {
104         requireNonNull( dependency, "dependency cannot be null" );
105         if ( !transitive )
106         {
107             return true;
108         }
109 
110         String scope = dependency.getScope();
111         return ( included == null || included.contains( scope ) )
112                 && ( excluded == null || !excluded.contains( scope ) );
113     }
114 
115     public DependencySelector deriveChildSelector( DependencyCollectionContext context )
116     {
117         requireNonNull( context, "context cannot be null" );
118         if ( this.transitive || context.getDependency() == null )
119         {
120             return this;
121         }
122 
123         return new ScopeDependencySelector( true, included, excluded );
124     }
125 
126     @Override
127     public boolean equals( Object obj )
128     {
129         if ( this == obj )
130         {
131             return true;
132         }
133         else if ( null == obj || !getClass().equals( obj.getClass() ) )
134         {
135             return false;
136         }
137 
138         ScopeDependencySelector that = (ScopeDependencySelector) obj;
139         return transitive == that.transitive && Objects.equals( included, that.included )
140                 && Objects.equals( excluded, that.excluded );
141     }
142 
143     @Override
144     public int hashCode()
145     {
146         int hash = 17;
147         hash = hash * 31 + ( transitive ? 1 : 0 );
148         hash = hash * 31 + ( included != null ? included.hashCode() : 0 );
149         hash = hash * 31 + ( excluded != null ? excluded.hashCode() : 0 );
150         return hash;
151     }
152 
153     @Override
154     public String toString()
155     {
156         return String.format(
157             "%s(included: %s, excluded: %s, transitive: %s)", getClass().getSimpleName(), included, excluded, transitive
158         );
159     }
160 
161 }