KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > maven > artifact > versioning > VersionRange


1 package org.apache.maven.artifact.versioning;
2
3 /*
4  * Copyright 2001-2005 The Apache Software Foundation.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * 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, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */

18
19 import org.apache.maven.artifact.Artifact;
20
21 import java.util.ArrayList JavaDoc;
22 import java.util.Collections JavaDoc;
23 import java.util.Iterator JavaDoc;
24 import java.util.List JavaDoc;
25
26 /**
27  * Construct a version range from a specification.
28  *
29  * @author <a HREF="mailto:brett@apache.org">Brett Porter</a>
30  * @version $Id: VersionRange.java 330080 2005-11-01 15:55:45Z jdcasey $
31  */

32 public class VersionRange
33 {
34     private final ArtifactVersion RELEASE = new DefaultArtifactVersion( "RELEASE" );
35
36     private final ArtifactVersion recommendedVersion;
37
38     private final List JavaDoc restrictions;
39
40     private VersionRange( ArtifactVersion recommendedVersion, List JavaDoc restrictions )
41     {
42         this.recommendedVersion = recommendedVersion;
43         this.restrictions = restrictions;
44     }
45
46     public ArtifactVersion getRecommendedVersion()
47     {
48         return recommendedVersion;
49     }
50
51     public List JavaDoc getRestrictions()
52     {
53         return restrictions;
54     }
55     
56     public VersionRange cloneOf()
57     {
58         List JavaDoc copiedRestrictions = null;
59         
60         if ( restrictions != null )
61         {
62             copiedRestrictions = new ArrayList JavaDoc();
63             
64             if ( !restrictions.isEmpty() )
65             {
66                 copiedRestrictions.addAll( restrictions );
67             }
68         }
69         
70         return new VersionRange( recommendedVersion, copiedRestrictions );
71     }
72
73     public static VersionRange createFromVersionSpec( String JavaDoc spec )
74         throws InvalidVersionSpecificationException
75     {
76         if ( spec == null )
77         {
78             return null;
79         }
80
81         List JavaDoc restrictions = new ArrayList JavaDoc();
82         String JavaDoc process = spec;
83         ArtifactVersion version = null;
84         ArtifactVersion upperBound = null;
85         ArtifactVersion lowerBound = null;
86
87         while ( process.startsWith( "[" ) || process.startsWith( "(" ) )
88         {
89             int index1 = process.indexOf( ")" );
90             int index2 = process.indexOf( "]" );
91
92             int index = index2;
93             if ( index2 < 0 || index1 < index2 )
94             {
95                 if ( index1 >= 0 )
96                 {
97                     index = index1;
98                 }
99             }
100
101             if ( index < 0 )
102             {
103                 throw new InvalidVersionSpecificationException( "Unbounded range: " + spec );
104             }
105
106             Restriction restriction = parseRestriction( process.substring( 0, index + 1 ) );
107             if ( lowerBound == null )
108             {
109                 lowerBound = restriction.getLowerBound();
110             }
111             if ( upperBound != null )
112             {
113                 if ( restriction.getLowerBound() == null || restriction.getLowerBound().compareTo( upperBound ) < 0 )
114                 {
115                     throw new InvalidVersionSpecificationException( "Ranges overlap: " + spec );
116                 }
117             }
118             restrictions.add( restriction );
119             upperBound = restriction.getUpperBound();
120
121             process = process.substring( index + 1 ).trim();
122
123             if ( process.length() > 0 && process.startsWith( "," ) )
124             {
125                 process = process.substring( 1 ).trim();
126             }
127         }
128
129         if ( process.length() > 0 )
130         {
131             if ( restrictions.size() > 0 )
132             {
133                 throw new InvalidVersionSpecificationException(
134                     "Only fully-qualified sets allowed in multiple set scenario: " + spec );
135             }
136             else
137             {
138                 version = new DefaultArtifactVersion( process );
139                 restrictions.add( Restriction.EVERYTHING );
140             }
141         }
142
143         return new VersionRange( version, restrictions );
144     }
145
146     private static Restriction parseRestriction( String JavaDoc spec )
147         throws InvalidVersionSpecificationException
148     {
149         boolean lowerBoundInclusive = spec.startsWith( "[" );
150         boolean upperBoundInclusive = spec.endsWith( "]" );
151
152         String JavaDoc process = spec.substring( 1, spec.length() - 1 ).trim();
153
154         Restriction restriction;
155
156         int index = process.indexOf( "," );
157
158         if ( index < 0 )
159         {
160             if ( !lowerBoundInclusive || !upperBoundInclusive )
161             {
162                 throw new InvalidVersionSpecificationException( "Single version must be surrounded by []: " + spec );
163             }
164
165             ArtifactVersion version = new DefaultArtifactVersion( process );
166
167             restriction = new Restriction( version, lowerBoundInclusive, version, upperBoundInclusive );
168         }
169         else
170         {
171             String JavaDoc lowerBound = process.substring( 0, index ).trim();
172             String JavaDoc upperBound = process.substring( index + 1 ).trim();
173             if ( lowerBound.equals( upperBound ) )
174             {
175                 throw new InvalidVersionSpecificationException( "Range cannot have identical boundaries: " + spec );
176             }
177
178             ArtifactVersion lowerVersion = null;
179             if ( lowerBound.length() > 0 )
180             {
181                 lowerVersion = new DefaultArtifactVersion( lowerBound );
182             }
183             ArtifactVersion upperVersion = null;
184             if ( upperBound.length() > 0 )
185             {
186                 upperVersion = new DefaultArtifactVersion( upperBound );
187             }
188
189             if ( upperVersion != null && lowerVersion != null && upperVersion.compareTo( lowerVersion ) < 0 )
190             {
191                 throw new InvalidVersionSpecificationException( "Range defies version ordering: " + spec );
192             }
193
194             restriction = new Restriction( lowerVersion, lowerBoundInclusive, upperVersion, upperBoundInclusive );
195         }
196
197         return restriction;
198     }
199
200     public static VersionRange createFromVersion( String JavaDoc version )
201     {
202         return new VersionRange( new DefaultArtifactVersion( version ), Collections.EMPTY_LIST );
203     }
204
205     public VersionRange restrict( VersionRange restriction )
206     {
207         List JavaDoc r1 = this.restrictions;
208         List JavaDoc r2 = restriction.restrictions;
209         List JavaDoc restrictions;
210         if ( r1.isEmpty() || r2.isEmpty() )
211         {
212             restrictions = Collections.EMPTY_LIST;
213         }
214         else
215         {
216             restrictions = intersection( r1, r2 );
217         }
218
219         ArtifactVersion version = null;
220         if ( restrictions.size() > 0 )
221         {
222             boolean found = false;
223             for ( Iterator JavaDoc i = restrictions.iterator(); i.hasNext() && !found; )
224             {
225                 Restriction r = (Restriction) i.next();
226
227                 if ( recommendedVersion != null && r.containsVersion( recommendedVersion ) )
228                 {
229                     // if we find the original, use that
230
version = recommendedVersion;
231                     found = true;
232                 }
233                 else if ( version == null && restriction.getRecommendedVersion() != null &&
234                     r.containsVersion( restriction.getRecommendedVersion() ) )
235                 {
236                     // use this if we can, but prefer the original if possible
237
version = restriction.getRecommendedVersion();
238                 }
239             }
240         }
241         else if ( recommendedVersion != null )
242         {
243             // no range, so the recommended version is valid
244
version = recommendedVersion;
245         }
246 /* TODO: should throw this immediately, but need artifact
247         else
248         {
249             throw new OverConstrainedVersionException( "Restricting incompatible version ranges" );
250         }
251 */

252
253         return new VersionRange( version, restrictions );
254     }
255
256     private List JavaDoc intersection( List JavaDoc r1, List JavaDoc r2 )
257     {
258         List JavaDoc restrictions = new ArrayList JavaDoc( r1.size() + r2.size() );
259         Iterator JavaDoc i1 = r1.iterator();
260         Iterator JavaDoc i2 = r2.iterator();
261         Restriction res1 = (Restriction) i1.next();
262         Restriction res2 = (Restriction) i2.next();
263
264         boolean done = false;
265         while ( !done )
266         {
267             if ( res1.getLowerBound() == null || res2.getUpperBound() == null ||
268                 res1.getLowerBound().compareTo( res2.getUpperBound() ) <= 0 )
269             {
270                 if ( res1.getUpperBound() == null || res2.getLowerBound() == null ||
271                     res1.getUpperBound().compareTo( res2.getLowerBound() ) >= 0 )
272                 {
273                     ArtifactVersion lower;
274                     ArtifactVersion upper;
275                     boolean lowerInclusive;
276                     boolean upperInclusive;
277
278                     // overlaps
279
if ( res1.getLowerBound() == null )
280                     {
281                         lower = res2.getLowerBound();
282                         lowerInclusive = res2.isLowerBoundInclusive();
283                     }
284                     else if ( res2.getLowerBound() == null )
285                     {
286                         lower = res1.getLowerBound();
287                         lowerInclusive = res1.isLowerBoundInclusive();
288                     }
289                     else
290                     {
291                         int comparison = res1.getLowerBound().compareTo( res2.getLowerBound() );
292                         if ( comparison < 0 )
293                         {
294                             lower = res2.getLowerBound();
295                             lowerInclusive = res2.isLowerBoundInclusive();
296                         }
297                         else if ( comparison == 0 )
298                         {
299                             lower = res1.getLowerBound();
300                             lowerInclusive = res1.isLowerBoundInclusive() && res2.isLowerBoundInclusive();
301                         }
302                         else
303                         {
304                             lower = res1.getLowerBound();
305                             lowerInclusive = res1.isLowerBoundInclusive();
306                         }
307                     }
308
309                     if ( res1.getUpperBound() == null )
310                     {
311                         upper = res2.getUpperBound();
312                         upperInclusive = res2.isUpperBoundInclusive();
313                     }
314                     else if ( res2.getUpperBound() == null )
315                     {
316                         upper = res1.getUpperBound();
317                         upperInclusive = res1.isUpperBoundInclusive();
318                     }
319                     else
320                     {
321                         int comparison = res1.getUpperBound().compareTo( res2.getUpperBound() );
322                         if ( comparison < 0 )
323                         {
324                             upper = res1.getUpperBound();
325                             upperInclusive = res1.isUpperBoundInclusive();
326                         }
327                         else if ( comparison == 0 )
328                         {
329                             upper = res1.getUpperBound();
330                             upperInclusive = res1.isUpperBoundInclusive() && res2.isUpperBoundInclusive();
331                         }
332                         else
333                         {
334                             upper = res2.getUpperBound();
335                             upperInclusive = res2.isUpperBoundInclusive();
336                         }
337                     }
338
339                     // don't add if they are equal and one is not inclusive
340
if ( lower == null || upper == null || lower.compareTo( upper ) != 0 )
341                     {
342                         restrictions.add( new Restriction( lower, lowerInclusive, upper, upperInclusive ) );
343                     }
344                     else if ( lowerInclusive && upperInclusive )
345                     {
346                         restrictions.add( new Restriction( lower, lowerInclusive, upper, upperInclusive ) );
347                     }
348
349                     //noinspection ObjectEquality
350
if ( upper == res2.getUpperBound() )
351                     {
352                         // advance res2
353
if ( i2.hasNext() )
354                         {
355                             res2 = (Restriction) i2.next();
356                         }
357                         else
358                         {
359                             done = true;
360                         }
361                     }
362                     else
363                     {
364                         // advance res1
365
if ( i1.hasNext() )
366                         {
367                             res1 = (Restriction) i1.next();
368                         }
369                         else
370                         {
371                             done = true;
372                         }
373                     }
374                 }
375                 else
376                 {
377                     // move on to next in r1
378
if ( i1.hasNext() )
379                     {
380                         res1 = (Restriction) i1.next();
381                     }
382                     else
383                     {
384                         done = true;
385                     }
386                 }
387             }
388             else
389             {
390                 // move on to next in r2
391
if ( i2.hasNext() )
392                 {
393                     res2 = (Restriction) i2.next();
394                 }
395                 else
396                 {
397                     done = true;
398                 }
399             }
400         }
401
402         return restrictions;
403     }
404
405     public ArtifactVersion getSelectedVersion( Artifact artifact )
406         throws OverConstrainedVersionException
407     {
408         ArtifactVersion version;
409         if ( recommendedVersion != null )
410         {
411             version = recommendedVersion;
412         }
413         else
414         {
415             if ( restrictions.size() == 0 )
416             {
417                 throw new OverConstrainedVersionException( "The artifact has no valid ranges", artifact );
418             }
419             else
420             {
421                 Restriction restriction = (Restriction) restrictions.get( restrictions.size() - 1 );
422
423                 version = restriction.getUpperBound();
424                 if ( version == null )
425                 {
426                     version = RELEASE;
427                 }
428             }
429         }
430         return version;
431     }
432
433     public boolean isSelectedVersionKnown( Artifact artifact )
434         throws OverConstrainedVersionException
435     {
436         boolean value = false;
437         if ( recommendedVersion != null )
438         {
439             value = true;
440         }
441         else
442         {
443             if ( restrictions.size() == 0 )
444             {
445                 throw new OverConstrainedVersionException( "The artifact has no valid ranges", artifact );
446             }
447             else
448             {
449                 Restriction restriction = (Restriction) restrictions.get( restrictions.size() - 1 );
450
451                 if ( restriction.getUpperBound() != null )
452                 {
453                     value = restriction.isUpperBoundInclusive();
454                 }
455             }
456         }
457         return value;
458     }
459
460     public String JavaDoc toString()
461     {
462         if ( recommendedVersion != null )
463         {
464             return recommendedVersion.toString();
465         }
466         else
467         {
468             StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
469             for ( Iterator JavaDoc i = restrictions.iterator(); i.hasNext(); )
470             {
471                 Restriction r = (Restriction) i.next();
472
473                 buf.append( r.isLowerBoundInclusive() ? "[" : "(" );
474                 if ( r.getLowerBound() != null )
475                 {
476                     buf.append( r.getLowerBound().toString() );
477                 }
478                 buf.append( "," );
479                 if ( r.getUpperBound() != null )
480                 {
481                     buf.append( r.getUpperBound().toString() );
482                 }
483                 buf.append( r.isUpperBoundInclusive() ? "]" : ")" );
484
485                 if ( i.hasNext() )
486                 {
487                     buf.append( "," );
488                 }
489             }
490             return buf.toString();
491         }
492     }
493
494     public ArtifactVersion matchVersion( List JavaDoc versions )
495     {
496         // TODO: could be more efficient by sorting the list and then moving along the restrictions in order?
497

498         ArtifactVersion matched = null;
499         for ( Iterator JavaDoc i = versions.iterator(); i.hasNext(); )
500         {
501             ArtifactVersion version = (ArtifactVersion) i.next();
502             if ( containsVersion( version ) )
503             {
504                 // valid - check if it is greater than the currently matched version
505
if ( matched == null || version.compareTo( matched ) > 0 )
506                 {
507                     matched = version;
508                 }
509             }
510         }
511         return matched;
512     }
513
514     public boolean containsVersion( ArtifactVersion version )
515     {
516         boolean matched = false;
517         for ( Iterator JavaDoc i = restrictions.iterator(); i.hasNext() && !matched; )
518         {
519             Restriction restriction = (Restriction) i.next();
520             if ( restriction.containsVersion( version ) )
521             {
522                 matched = true;
523             }
524         }
525         return matched;
526     }
527
528     public boolean hasRestrictions()
529     {
530         return !restrictions.isEmpty() && recommendedVersion == null;
531     }
532 }
533
Popular Tags