1 package org.apache.maven.artifact.versioning; 2 3 18 19 import org.apache.maven.artifact.Artifact; 20 21 import java.util.ArrayList ; 22 import java.util.Collections ; 23 import java.util.Iterator ; 24 import java.util.List ; 25 26 32 public class VersionRange 33 { 34 private final ArtifactVersion RELEASE = new DefaultArtifactVersion( "RELEASE" ); 35 36 private final ArtifactVersion recommendedVersion; 37 38 private final List restrictions; 39 40 private VersionRange( ArtifactVersion recommendedVersion, List 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 getRestrictions() 52 { 53 return restrictions; 54 } 55 56 public VersionRange cloneOf() 57 { 58 List copiedRestrictions = null; 59 60 if ( restrictions != null ) 61 { 62 copiedRestrictions = new ArrayList (); 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 spec ) 74 throws InvalidVersionSpecificationException 75 { 76 if ( spec == null ) 77 { 78 return null; 79 } 80 81 List restrictions = new ArrayList (); 82 String 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 spec ) 147 throws InvalidVersionSpecificationException 148 { 149 boolean lowerBoundInclusive = spec.startsWith( "[" ); 150 boolean upperBoundInclusive = spec.endsWith( "]" ); 151 152 String 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 lowerBound = process.substring( 0, index ).trim(); 172 String 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 version ) 201 { 202 return new VersionRange( new DefaultArtifactVersion( version ), Collections.EMPTY_LIST ); 203 } 204 205 public VersionRange restrict( VersionRange restriction ) 206 { 207 List r1 = this.restrictions; 208 List r2 = restriction.restrictions; 209 List 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 i = restrictions.iterator(); i.hasNext() && !found; ) 224 { 225 Restriction r = (Restriction) i.next(); 226 227 if ( recommendedVersion != null && r.containsVersion( recommendedVersion ) ) 228 { 229 version = recommendedVersion; 231 found = true; 232 } 233 else if ( version == null && restriction.getRecommendedVersion() != null && 234 r.containsVersion( restriction.getRecommendedVersion() ) ) 235 { 236 version = restriction.getRecommendedVersion(); 238 } 239 } 240 } 241 else if ( recommendedVersion != null ) 242 { 243 version = recommendedVersion; 245 } 246 252 253 return new VersionRange( version, restrictions ); 254 } 255 256 private List intersection( List r1, List r2 ) 257 { 258 List restrictions = new ArrayList ( r1.size() + r2.size() ); 259 Iterator i1 = r1.iterator(); 260 Iterator 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 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 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 if ( upper == res2.getUpperBound() ) 351 { 352 if ( i2.hasNext() ) 354 { 355 res2 = (Restriction) i2.next(); 356 } 357 else 358 { 359 done = true; 360 } 361 } 362 else 363 { 364 if ( i1.hasNext() ) 366 { 367 res1 = (Restriction) i1.next(); 368 } 369 else 370 { 371 done = true; 372 } 373 } 374 } 375 else 376 { 377 if ( i1.hasNext() ) 379 { 380 res1 = (Restriction) i1.next(); 381 } 382 else 383 { 384 done = true; 385 } 386 } 387 } 388 else 389 { 390 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 toString() 461 { 462 if ( recommendedVersion != null ) 463 { 464 return recommendedVersion.toString(); 465 } 466 else 467 { 468 StringBuffer buf = new StringBuffer (); 469 for ( Iterator 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 versions ) 495 { 496 498 ArtifactVersion matched = null; 499 for ( Iterator i = versions.iterator(); i.hasNext(); ) 500 { 501 ArtifactVersion version = (ArtifactVersion) i.next(); 502 if ( containsVersion( version ) ) 503 { 504 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 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 |