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.Arrays;
23  import java.util.Collection;
24  import java.util.Collections;
25  import java.util.Iterator;
26  import java.util.LinkedHashSet;
27  import java.util.Set;
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 combines zero or more other selectors using a logical {@code AND}. The resulting selector
37   * selects a given dependency if and only if all constituent selectors do so.
38   */
39  public final class AndDependencySelector
40      implements DependencySelector
41  {
42  
43      private final Set<? extends DependencySelector> selectors;
44  
45      private int hashCode;
46  
47      /**
48       * Creates a new selector from the specified selectors. Prefer
49       * {@link #newInstance(DependencySelector, DependencySelector)} if any of the input selectors might be {@code null}.
50       * 
51       * @param selectors The selectors to combine, may be {@code null} but must not contain {@code null} elements.
52       */
53      public AndDependencySelector( DependencySelector... selectors )
54      {
55          if ( selectors != null && selectors.length > 0 )
56          {
57              this.selectors = new LinkedHashSet<>( Arrays.asList( selectors ) );
58          }
59          else
60          {
61              this.selectors = Collections.emptySet();
62          }
63      }
64  
65      /**
66       * Creates a new selector from the specified selectors.
67       * 
68       * @param selectors The selectors to combine, may be {@code null} but must not contain {@code null} elements.
69       */
70      public AndDependencySelector( Collection<? extends DependencySelector> selectors )
71      {
72          if ( selectors != null && !selectors.isEmpty() )
73          {
74              this.selectors = new LinkedHashSet<>( selectors );
75          }
76          else
77          {
78              this.selectors = Collections.emptySet();
79          }
80      }
81  
82      private AndDependencySelector( Set<DependencySelector> selectors )
83      {
84          if ( selectors != null && !selectors.isEmpty() )
85          {
86              this.selectors = selectors;
87          }
88          else
89          {
90              this.selectors = Collections.emptySet();
91          }
92      }
93  
94      /**
95       * Creates a new selector from the specified selectors.
96       * 
97       * @param selector1 The first selector to combine, may be {@code null}.
98       * @param selector2 The second selector to combine, may be {@code null}.
99       * @return The combined selector or {@code null} if both selectors were {@code null}.
100      */
101     public static DependencySelector newInstance( DependencySelector selector1, DependencySelector selector2 )
102     {
103         if ( selector1 == null )
104         {
105             return selector2;
106         }
107         else if ( selector2 == null || selector2.equals( selector1 ) )
108         {
109             return selector1;
110         }
111         return new AndDependencySelector( selector1, selector2 );
112     }
113 
114     public boolean selectDependency( Dependency dependency )
115     {
116         requireNonNull( dependency, "dependency cannot be null" );
117         for ( DependencySelector selector : selectors )
118         {
119             if ( !selector.selectDependency( dependency ) )
120             {
121                 return false;
122             }
123         }
124         return true;
125     }
126 
127     public DependencySelector deriveChildSelector( DependencyCollectionContext context )
128     {
129         requireNonNull( context, "context cannot be null" );
130         int seen = 0;
131         Set<DependencySelector> childSelectors = null;
132 
133         for ( DependencySelector selector : selectors )
134         {
135             DependencySelector childSelector = selector.deriveChildSelector( context );
136             if ( childSelectors != null )
137             {
138                 if ( childSelector != null )
139                 {
140                     childSelectors.add( childSelector );
141                 }
142             }
143             else if ( selector != childSelector )
144             {
145                 childSelectors = new LinkedHashSet<>();
146                 if ( seen > 0 )
147                 {
148                     for ( DependencySelector s : selectors )
149                     {
150                         if ( childSelectors.size() >= seen )
151                         {
152                             break;
153                         }
154                         childSelectors.add( s );
155                     }
156                 }
157                 if ( childSelector != null )
158                 {
159                     childSelectors.add( childSelector );
160                 }
161             }
162             else
163             {
164                 seen++;
165             }
166         }
167 
168         if ( childSelectors == null )
169         {
170             return this;
171         }
172         if ( childSelectors.size() <= 1 )
173         {
174             if ( childSelectors.isEmpty() )
175             {
176                 return null;
177             }
178             return childSelectors.iterator().next();
179         }
180         return new AndDependencySelector( childSelectors );
181     }
182 
183     @Override
184     public boolean equals( Object obj )
185     {
186         if ( this == obj )
187         {
188             return true;
189         }
190         else if ( null == obj || !getClass().equals( obj.getClass() ) )
191         {
192             return false;
193         }
194 
195         AndDependencySelector that = (AndDependencySelector) obj;
196         return selectors.equals( that.selectors );
197     }
198 
199     @Override
200     public int hashCode()
201     {
202         if ( hashCode == 0 )
203         {
204             int hash = 17;
205             hash = hash * 31 + selectors.hashCode();
206             hashCode = hash;
207         }
208         return hashCode;
209     }
210 
211     @Override
212     public String toString()
213     {
214         StringBuilder builder = new StringBuilder().append( this.getClass().getSimpleName() ).append( '(' );
215         Iterator<? extends DependencySelector> iterator = this.selectors.iterator();
216         while ( iterator.hasNext() )
217         {
218             final DependencySelector selector = iterator.next();
219             builder.append( selector.toString() );
220             if ( iterator.hasNext() ) // not last
221             {
222                 builder.append( " && " );
223             }
224         }
225         return builder.append( ')' ).toString();
226     }
227 
228 }