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