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