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 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      }
57  
58      /**
59       * Creates a new selector from the specified selectors.
60       *
61       * @param selectors The selectors to combine, may be {@code null} but must not contain {@code null} elements.
62       */
63      public AndDependencySelector(Collection<? extends DependencySelector> selectors) {
64          if (selectors != null && !selectors.isEmpty()) {
65              this.selectors = new LinkedHashSet<>(selectors);
66          } else {
67              this.selectors = Collections.emptySet();
68          }
69      }
70  
71      private AndDependencySelector(Set<DependencySelector> selectors) {
72          if (selectors != null && !selectors.isEmpty()) {
73              this.selectors = selectors;
74          } else {
75              this.selectors = Collections.emptySet();
76          }
77      }
78  
79      /**
80       * Creates a new selector from the specified selectors.
81       *
82       * @param selector1 The first selector to combine, may be {@code null}.
83       * @param selector2 The second selector to combine, may be {@code null}.
84       * @return The combined selector or {@code null} if both selectors were {@code null}.
85       */
86      public static DependencySelector newInstance(DependencySelector selector1, DependencySelector selector2) {
87          if (selector1 == null) {
88              return selector2;
89          } else if (selector2 == null || selector2.equals(selector1)) {
90              return selector1;
91          }
92          return new AndDependencySelector(selector1, selector2);
93      }
94  
95      public boolean selectDependency(Dependency dependency) {
96          requireNonNull(dependency, "dependency cannot be null");
97          for (DependencySelector selector : selectors) {
98              if (!selector.selectDependency(dependency)) {
99                  return false;
100             }
101         }
102         return true;
103     }
104 
105     public DependencySelector deriveChildSelector(DependencyCollectionContext context) {
106         requireNonNull(context, "context cannot be null");
107         int seen = 0;
108         Set<DependencySelector> childSelectors = null;
109 
110         for (DependencySelector selector : selectors) {
111             DependencySelector childSelector = selector.deriveChildSelector(context);
112             if (childSelectors != null) {
113                 if (childSelector != null) {
114                     childSelectors.add(childSelector);
115                 }
116             } else if (selector != childSelector) {
117                 childSelectors = new LinkedHashSet<>();
118                 if (seen > 0) {
119                     for (DependencySelector s : selectors) {
120                         if (childSelectors.size() >= seen) {
121                             break;
122                         }
123                         childSelectors.add(s);
124                     }
125                 }
126                 if (childSelector != null) {
127                     childSelectors.add(childSelector);
128                 }
129             } else {
130                 seen++;
131             }
132         }
133 
134         if (childSelectors == null) {
135             return this;
136         }
137         if (childSelectors.size() <= 1) {
138             if (childSelectors.isEmpty()) {
139                 return null;
140             }
141             return childSelectors.iterator().next();
142         }
143         return new AndDependencySelector(childSelectors);
144     }
145 
146     @Override
147     public boolean equals(Object obj) {
148         if (this == obj) {
149             return true;
150         } else if (null == obj || !getClass().equals(obj.getClass())) {
151             return false;
152         }
153 
154         AndDependencySelector that = (AndDependencySelector) obj;
155         return selectors.equals(that.selectors);
156     }
157 
158     @Override
159     public int hashCode() {
160         if (hashCode == 0) {
161             int hash = 17;
162             hash = hash * 31 + selectors.hashCode();
163             hashCode = hash;
164         }
165         return hashCode;
166     }
167 
168     @Override
169     public String toString() {
170         StringBuilder builder =
171                 new StringBuilder().append(this.getClass().getSimpleName()).append('(');
172         Iterator<? extends DependencySelector> iterator = this.selectors.iterator();
173         while (iterator.hasNext()) {
174             final DependencySelector selector = iterator.next();
175             builder.append(selector.toString());
176             if (iterator.hasNext()) // not last
177             {
178                 builder.append(" && ");
179             }
180         }
181         return builder.append(')').toString();
182     }
183 }