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.version;
20  
21  import java.util.Arrays;
22  import java.util.Collection;
23  import java.util.Collections;
24  import java.util.HashSet;
25  import java.util.Set;
26  import java.util.stream.Collectors;
27  
28  import org.eclipse.aether.version.Version;
29  import org.eclipse.aether.version.VersionRange;
30  
31  /**
32   * A union of version ranges.
33   */
34  public final class UnionVersionRange implements VersionRange {
35  
36      private final Set<VersionRange> ranges;
37  
38      private final Bound lowerBound;
39  
40      private final Bound upperBound;
41  
42      /**
43       * Creates union {@link VersionRange}s out of passed in {@link VersionRange} instances.
44       *
45       * @param ranges The ranges, may be empty array or even {@code null}.
46       */
47      public static VersionRange from(VersionRange... ranges) {
48          if (ranges == null || ranges.length == 0) {
49              return from(Collections.emptySet());
50          }
51          return from(Arrays.asList(ranges));
52      }
53  
54      /**
55       * Creates union {@link VersionRange}s out of passed in {@link VersionRange} collection.
56       *
57       * @param ranges The ranges, may be empty collection or even {@code null}.
58       */
59      public static VersionRange from(Collection<? extends VersionRange> ranges) {
60          if (ranges != null && ranges.size() == 1) {
61              return ranges.iterator().next();
62          }
63          return new UnionVersionRange(ranges);
64      }
65  
66      private UnionVersionRange(Collection<? extends VersionRange> ranges) {
67          if (ranges == null || ranges.isEmpty()) {
68              this.ranges = Collections.emptySet();
69              lowerBound = null;
70              upperBound = null;
71          } else {
72              this.ranges = new HashSet<>(ranges);
73              Bound lowerBound = null, upperBound = null;
74              for (VersionRange range : this.ranges) {
75                  Bound lb = range.getLowerBound();
76                  if (lb == null) {
77                      lowerBound = null;
78                      break;
79                  } else if (lowerBound == null) {
80                      lowerBound = lb;
81                  } else {
82                      int c = lb.getVersion().compareTo(lowerBound.getVersion());
83                      if (c < 0 || (c == 0 && !lowerBound.isInclusive())) {
84                          lowerBound = lb;
85                      }
86                  }
87              }
88              for (VersionRange range : this.ranges) {
89                  Bound ub = range.getUpperBound();
90                  if (ub == null) {
91                      upperBound = null;
92                      break;
93                  } else if (upperBound == null) {
94                      upperBound = ub;
95                  } else {
96                      int c = ub.getVersion().compareTo(upperBound.getVersion());
97                      if (c > 0 || (c == 0 && !upperBound.isInclusive())) {
98                          upperBound = ub;
99                      }
100                 }
101             }
102             this.lowerBound = lowerBound;
103             this.upperBound = upperBound;
104         }
105     }
106 
107     @Override
108     public boolean containsVersion(Version version) {
109         for (VersionRange range : ranges) {
110             if (range.containsVersion(version)) {
111                 return true;
112             }
113         }
114         return false;
115     }
116 
117     @Override
118     public Bound getLowerBound() {
119         return lowerBound;
120     }
121 
122     @Override
123     public Bound getUpperBound() {
124         return upperBound;
125     }
126 
127     @Override
128     public boolean equals(Object obj) {
129         if (obj == this) {
130             return true;
131         } else if (obj == null || !getClass().equals(obj.getClass())) {
132             return false;
133         }
134 
135         UnionVersionRange that = (UnionVersionRange) obj;
136 
137         return ranges.equals(that.ranges);
138     }
139 
140     @SuppressWarnings("checkstyle:magicnumber")
141     @Override
142     public int hashCode() {
143         return 97 * ranges.hashCode();
144     }
145 
146     @Override
147     public String toString() {
148         return ranges.stream().map(VersionRange::toString).collect(Collectors.joining(", "));
149     }
150 }