1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.eclipse.aether.util.version;
20
21 import java.util.Objects;
22
23 import org.eclipse.aether.version.InvalidVersionSpecificationException;
24 import org.eclipse.aether.version.Version;
25 import org.eclipse.aether.version.VersionRange;
26
27 import static java.util.Objects.requireNonNull;
28
29
30
31
32 final class GenericVersionRange implements VersionRange {
33
34 private final Bound lowerBound;
35
36 private final Bound upperBound;
37
38
39
40
41
42
43
44 GenericVersionRange(String range) throws InvalidVersionSpecificationException {
45 String process = requireNonNull(range, "version range cannot be null");
46
47 boolean lowerBoundInclusive, upperBoundInclusive;
48 Version lowerBound, upperBound;
49
50 if (range.startsWith("[")) {
51 lowerBoundInclusive = true;
52 } else if (range.startsWith("(")) {
53 lowerBoundInclusive = false;
54 } else {
55 throw new InvalidVersionSpecificationException(
56 range, "Invalid version range " + range + ", a range must start with either [ or (");
57 }
58
59 if (range.endsWith("]")) {
60 upperBoundInclusive = true;
61 } else if (range.endsWith(")")) {
62 upperBoundInclusive = false;
63 } else {
64 throw new InvalidVersionSpecificationException(
65 range, "Invalid version range " + range + ", a range must end with either [ or (");
66 }
67
68 process = process.substring(1, process.length() - 1);
69
70 int index = process.indexOf(",");
71
72 if (index < 0) {
73 if (!lowerBoundInclusive || !upperBoundInclusive) {
74 throw new InvalidVersionSpecificationException(
75 range, "Invalid version range " + range + ", single version must be surrounded by []");
76 }
77
78 String version = process.trim();
79 if (version.endsWith(".*")) {
80 String prefix = version.substring(0, version.length() - 1);
81 lowerBound = parse(prefix + "min");
82 upperBound = parse(prefix + "max");
83 } else {
84 lowerBound = parse(version);
85 upperBound = lowerBound;
86 }
87 } else {
88 String parsedLowerBound = process.substring(0, index).trim();
89 String parsedUpperBound = process.substring(index + 1).trim();
90
91
92 if (parsedUpperBound.contains(",")) {
93 throw new InvalidVersionSpecificationException(
94 range, "Invalid version range " + range + ", bounds may not contain additional ','");
95 }
96
97 lowerBound = !parsedLowerBound.isEmpty() ? parse(parsedLowerBound) : null;
98 upperBound = !parsedUpperBound.isEmpty() ? parse(parsedUpperBound) : null;
99
100 if (upperBound != null && lowerBound != null) {
101 if (upperBound.compareTo(lowerBound) < 0) {
102 throw new InvalidVersionSpecificationException(
103 range,
104 "Invalid version range " + range + ", lower bound must not be greater than upper bound");
105 }
106 }
107 }
108
109 this.lowerBound = (lowerBound != null) ? new Bound(lowerBound, lowerBoundInclusive) : null;
110 this.upperBound = (upperBound != null) ? new Bound(upperBound, upperBoundInclusive) : null;
111 }
112
113 private Version parse(String version) {
114 return new GenericVersion(version);
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 containsVersion(Version version) {
129 if (lowerBound != null) {
130 int comparison = lowerBound.getVersion().compareTo(version);
131
132 if (comparison == 0 && !lowerBound.isInclusive()) {
133 return false;
134 }
135 if (comparison > 0) {
136 return false;
137 }
138 }
139
140 if (upperBound != null) {
141 int comparison = upperBound.getVersion().compareTo(version);
142
143 if (comparison == 0 && !upperBound.isInclusive()) {
144 return false;
145 }
146 if (comparison < 0) {
147 return false;
148 }
149 }
150
151 return true;
152 }
153
154 @Override
155 public boolean equals(Object obj) {
156 if (obj == this) {
157 return true;
158 } else if (obj == null || !getClass().equals(obj.getClass())) {
159 return false;
160 }
161
162 GenericVersionRange that = (GenericVersionRange) obj;
163
164 return Objects.equals(upperBound, that.upperBound) && Objects.equals(lowerBound, that.lowerBound);
165 }
166
167 @Override
168 public int hashCode() {
169 int hash = 17;
170 hash = hash * 31 + hash(upperBound);
171 hash = hash * 31 + hash(lowerBound);
172 return hash;
173 }
174
175 private static int hash(Object obj) {
176 return obj != null ? obj.hashCode() : 0;
177 }
178
179 @Override
180 public String toString() {
181 StringBuilder buffer = new StringBuilder(64);
182 if (lowerBound != null) {
183 buffer.append(lowerBound.isInclusive() ? '[' : '(');
184 buffer.append(lowerBound.getVersion());
185 } else {
186 buffer.append('(');
187 }
188 buffer.append(',');
189 if (upperBound != null) {
190 buffer.append(upperBound.getVersion());
191 buffer.append(upperBound.isInclusive() ? ']' : ')');
192 } else {
193 buffer.append(')');
194 }
195 return buffer.toString();
196 }
197 }