View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.eclipse.aether.util.graph.selector;
20  
21  import java.util.Arrays;
22  import java.util.Collection;
23  import java.util.Collections;
24  import java.util.Iterator;
25  import java.util.LinkedHashSet;
26  import java.util.Set;
27  
28  import org.eclipse.aether.collection.DependencyCollectionContext;
29  import org.eclipse.aether.collection.DependencySelector;
30  import org.eclipse.aether.graph.Dependency;
31  
32  import static java.util.Objects.requireNonNull;
33  
34  /**
35   * A dependency selector that combines zero or more other selectors using a logical {@code AND}. The resulting selector
36   * selects a given dependency if and only if all constituent selectors do so.
37   */
38  public final class AndDependencySelector implements DependencySelector {
39  
40      private final Set<? extends DependencySelector> selectors;
41  
42      private final int hashCode;
43  
44      /**
45       * Creates a new selector from the specified selectors. Prefer
46       * {@link #newInstance(DependencySelector, DependencySelector)} if any of the input selectors might be {@code null}.
47       *
48       * @param selectors the selectors to combine, may be {@code null} but must not contain {@code null} elements
49       */
50      public AndDependencySelector(DependencySelector... selectors) {
51          if (selectors != null && selectors.length > 0) {
52              this.selectors = new LinkedHashSet<>(Arrays.asList(selectors));
53          } else {
54              this.selectors = Collections.emptySet();
55          }
56          this.hashCode = 17 * 31 + this.selectors.hashCode();
57      }
58  
59      /**
60       * Creates a new selector from the specified selectors.
61       *
62       * @param selectors the selectors to combine, may be {@code null} but must not contain {@code null} elements
63       */
64      public AndDependencySelector(Collection<? extends DependencySelector> selectors) {
65          if (selectors != null && !selectors.isEmpty()) {
66              this.selectors = new LinkedHashSet<>(selectors);
67          } else {
68              this.selectors = Collections.emptySet();
69          }
70          this.hashCode = 17 * 31 + this.selectors.hashCode();
71      }
72  
73      private AndDependencySelector(Set<DependencySelector> selectors) {
74          if (selectors != null && !selectors.isEmpty()) {
75              this.selectors = selectors;
76          } else {
77              this.selectors = Collections.emptySet();
78          }
79          this.hashCode = 17 * 31 + this.selectors.hashCode();
80      }
81  
82      /**
83       * Creates a new selector from the specified selectors.
84       *
85       * @param selector1 the first selector to combine, may be {@code null}
86       * @param selector2 the second selector to combine, may be {@code null}
87       * @return the combined selector or {@code null} if both selectors were {@code null}
88       */
89      public static DependencySelector newInstance(DependencySelector selector1, DependencySelector selector2) {
90          if (selector1 == null) {
91              return selector2;
92          } else if (selector2 == null || selector2.equals(selector1)) {
93              return selector1;
94          }
95          return new AndDependencySelector(selector1, selector2);
96      }
97  
98      public boolean selectDependency(Dependency dependency) {
99          requireNonNull(dependency, "dependency cannot be null");
100         for (DependencySelector selector : selectors) {
101             if (!selector.selectDependency(dependency)) {
102                 return false;
103             }
104         }
105         return true;
106     }
107 
108     public DependencySelector deriveChildSelector(DependencyCollectionContext context) {
109         requireNonNull(context, "context cannot be null");
110         int seen = 0;
111         Set<DependencySelector> childSelectors = null;
112 
113         for (DependencySelector selector : selectors) {
114             DependencySelector childSelector = selector.deriveChildSelector(context);
115             if (childSelectors != null) {
116                 if (childSelector != null) {
117                     childSelectors.add(childSelector);
118                 }
119             } else if (selector != childSelector) {
120                 childSelectors = new LinkedHashSet<>();
121                 if (seen > 0) {
122                     for (DependencySelector s : selectors) {
123                         if (childSelectors.size() >= seen) {
124                             break;
125                         }
126                         childSelectors.add(s);
127                     }
128                 }
129                 if (childSelector != null) {
130                     childSelectors.add(childSelector);
131                 }
132             } else {
133                 seen++;
134             }
135         }
136 
137         if (childSelectors == null) {
138             return this;
139         }
140         if (childSelectors.size() <= 1) {
141             if (childSelectors.isEmpty()) {
142                 return null;
143             }
144             return childSelectors.iterator().next();
145         }
146         return new AndDependencySelector(childSelectors);
147     }
148 
149     @Override
150     public boolean equals(Object obj) {
151         if (this == obj) {
152             return true;
153         } else if (null == obj || !getClass().equals(obj.getClass())) {
154             return false;
155         }
156 
157         AndDependencySelector that = (AndDependencySelector) obj;
158         return selectors.equals(that.selectors);
159     }
160 
161     @Override
162     public int hashCode() {
163         return hashCode;
164     }
165 
166     @Override
167     public String toString() {
168         StringBuilder builder =
169                 new StringBuilder().append(this.getClass().getSimpleName()).append('(');
170         Iterator<? extends DependencySelector> iterator = this.selectors.iterator();
171         while (iterator.hasNext()) {
172             final DependencySelector selector = iterator.next();
173             builder.append(selector.toString());
174             if (iterator.hasNext()) // not last
175             {
176                 builder.append(" && ");
177             }
178         }
179         return builder.append(')').toString();
180     }
181 }