View Javadoc
1   package org.eclipse.aether.internal.test.util;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   * 
12   *  http://www.apache.org/licenses/LICENSE-2.0
13   * 
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
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   * A version range inspired by mathematical range syntax. For example, "[1.0,2.0)", "[1.0,)" or "[1.0]".
28   */
29  final class TestVersionRange
30      implements VersionRange
31  {
32  
33      private final Version lowerBound;
34  
35      private final boolean lowerBoundInclusive;
36  
37      private final Version upperBound;
38  
39      private final boolean upperBoundInclusive;
40  
41      /**
42       * Creates a version range from the specified range specification.
43       * 
44       * @param range The range specification to parse, must not be {@code null}.
45       * @throws InvalidVersionSpecificationException If the range could not be parsed.
46       */
47      public TestVersionRange( String range )
48          throws InvalidVersionSpecificationException
49      {
50          String process = range;
51  
52          if ( range.startsWith( "[" ) )
53          {
54              lowerBoundInclusive = true;
55          }
56          else if ( range.startsWith( "(" ) )
57          {
58              lowerBoundInclusive = false;
59          }
60          else
61          {
62              throw new InvalidVersionSpecificationException( range, "Invalid version range " + range
63                  + ", a range must start with either [ or (" );
64          }
65  
66          if ( range.endsWith( "]" ) )
67          {
68              upperBoundInclusive = true;
69          }
70          else if ( range.endsWith( ")" ) )
71          {
72              upperBoundInclusive = false;
73          }
74          else
75          {
76              throw new InvalidVersionSpecificationException( range, "Invalid version range " + range
77                  + ", a range must end with either [ or (" );
78          }
79  
80          process = process.substring( 1, process.length() - 1 );
81  
82          int index = process.indexOf( "," );
83  
84          if ( index < 0 )
85          {
86              if ( !lowerBoundInclusive || !upperBoundInclusive )
87              {
88                  throw new InvalidVersionSpecificationException( range, "Invalid version range " + range
89                      + ", single version must be surrounded by []" );
90              }
91  
92              lowerBound = upperBound = new TestVersion( process.trim() );
93          }
94          else
95          {
96              String parsedLowerBound = process.substring( 0, index ).trim();
97              String parsedUpperBound = process.substring( index + 1 ).trim();
98  
99              // more than two bounds, e.g. (1,2,3)
100             if ( parsedUpperBound.contains( "," ) )
101             {
102                 throw new InvalidVersionSpecificationException( range, "Invalid version range " + range
103                     + ", bounds may not contain additional ','" );
104             }
105 
106             lowerBound = parsedLowerBound.length() > 0 ? new TestVersion( parsedLowerBound ) : null;
107             upperBound = parsedUpperBound.length() > 0 ? new TestVersion( parsedUpperBound ) : null;
108 
109             if ( upperBound != null && lowerBound != null )
110             {
111                 if ( upperBound.compareTo( lowerBound ) < 0 )
112                 {
113                     throw new InvalidVersionSpecificationException( range, "Invalid version range " + range
114                         + ", lower bound must not be greater than upper bound" );
115                 }
116             }
117         }
118     }
119 
120     public Bound getLowerBound()
121     {
122         return new Bound( lowerBound, lowerBoundInclusive );
123     }
124 
125     public Bound getUpperBound()
126     {
127         return new Bound( upperBound, upperBoundInclusive );
128     }
129 
130     public boolean acceptsSnapshots()
131     {
132         return isSnapshot( lowerBound ) || isSnapshot( upperBound );
133     }
134 
135     public boolean containsVersion( Version version )
136     {
137         boolean snapshot = isSnapshot( version );
138 
139         if ( lowerBound != null )
140         {
141             int comparison = lowerBound.compareTo( version );
142 
143             if ( snapshot && comparison == 0 )
144             {
145                 return true;
146             }
147 
148             if ( comparison == 0 && !lowerBoundInclusive )
149             {
150                 return false;
151             }
152             if ( comparison > 0 )
153             {
154                 return false;
155             }
156         }
157 
158         if ( upperBound != null )
159         {
160             int comparison = upperBound.compareTo( version );
161 
162             if ( snapshot && comparison == 0 )
163             {
164                 return true;
165             }
166 
167             if ( comparison == 0 && !upperBoundInclusive )
168             {
169                 return false;
170             }
171             if ( comparison < 0 )
172             {
173                 return false;
174             }
175         }
176 
177         if ( lowerBound != null || upperBound != null )
178         {
179             return !snapshot;
180         }
181 
182         return true;
183     }
184 
185     private boolean isSnapshot( Version version )
186     {
187         return version != null && version.toString().endsWith( "SNAPSHOT" );
188     }
189 
190     @Override
191     public boolean equals( Object obj )
192     {
193         if ( obj == this )
194         {
195             return true;
196         }
197         else if ( obj == null || !getClass().equals( obj.getClass() ) )
198         {
199             return false;
200         }
201 
202         TestVersionRange that = (TestVersionRange) obj;
203 
204         return upperBoundInclusive == that.upperBoundInclusive && lowerBoundInclusive == that.lowerBoundInclusive
205             && eq( upperBound, that.upperBound ) && eq( lowerBound, that.lowerBound );
206     }
207 
208     private static <T> boolean eq( T s1, T s2 )
209     {
210         return s1 != null ? s1.equals( s2 ) : s2 == null;
211     }
212 
213     @Override
214     public int hashCode()
215     {
216         int hash = 17;
217         hash = hash * 31 + hash( upperBound );
218         hash = hash * 31 + ( upperBoundInclusive ? 1 : 0 );
219         hash = hash * 31 + hash( lowerBound );
220         hash = hash * 31 + ( lowerBoundInclusive ? 1 : 0 );
221         return hash;
222     }
223 
224     private static int hash( Object obj )
225     {
226         return obj != null ? obj.hashCode() : 0;
227     }
228 
229     @Override
230     public String toString()
231     {
232         StringBuilder buffer = new StringBuilder( 64 );
233         buffer.append( lowerBoundInclusive ? '[' : '(' );
234         if ( lowerBound != null )
235         {
236             buffer.append( lowerBound );
237         }
238         buffer.append( ',' );
239         if ( upperBound != null )
240         {
241             buffer.append( upperBound );
242         }
243         buffer.append( upperBoundInclusive ? ']' : ')' );
244         return buffer.toString();
245     }
246 
247 }