1 8 package org.codehaus.loom.extension; 9 10 import java.text.ParseException ; 11 import java.util.ArrayList ; 12 import java.util.Arrays ; 13 import java.util.Iterator ; 14 import java.util.Map ; 15 import java.util.jar.Attributes ; 16 import java.util.jar.Manifest ; 17 18 30 public final class Specification 31 { 32 37 public static final Attributes.Name SPECIFICATION_TITLE = Attributes.Name.SPECIFICATION_TITLE; 38 43 public static final Attributes.Name SPECIFICATION_VERSION = Attributes.Name.SPECIFICATION_VERSION; 44 49 public static final Attributes.Name SPECIFICATION_VENDOR = Attributes.Name.SPECIFICATION_VENDOR; 50 55 public static final Attributes.Name IMPLEMENTATION_TITLE = Attributes.Name.IMPLEMENTATION_TITLE; 56 61 public static final Attributes.Name IMPLEMENTATION_VERSION = Attributes.Name.IMPLEMENTATION_VERSION; 62 67 public static final Attributes.Name IMPLEMENTATION_VENDOR = Attributes.Name.IMPLEMENTATION_VENDOR; 68 72 public static final Compatability COMPATIBLE = 73 new Compatability( "COMPATIBLE" ); 74 78 public static final Compatability REQUIRE_SPECIFICATION_UPGRADE = 79 new Compatability( "REQUIRE_SPECIFICATION_UPGRADE" ); 80 84 public static final Compatability REQUIRE_VENDOR_SWITCH = 85 new Compatability( "REQUIRE_VENDOR_SWITCH" ); 86 90 public static final Compatability REQUIRE_IMPLEMENTATION_CHANGE = 91 new Compatability( "REQUIRE_IMPLEMENTATION_CHANGE" ); 92 97 public static final Compatability INCOMPATIBLE = 98 new Compatability( "INCOMPATIBLE" ); 99 100 private String m_specificationTitle; 101 105 private DeweyDecimal m_specificationVersion; 106 110 private String m_specificationVendor; 111 112 private String m_implementationTitle; 113 117 private String m_implementationVendor; 118 121 private String m_implementationVersion; 122 123 private String [] m_sections; 124 125 132 public static Specification[] getSpecifications( final Manifest manifest ) 133 throws ParseException 134 { 135 if( null == manifest ) 136 { 137 return new Specification[ 0 ]; 138 } 139 final ArrayList results = new ArrayList (); 140 final Map entries = manifest.getEntries(); 141 final Iterator keys = entries.keySet().iterator(); 142 while( keys.hasNext() ) 143 { 144 final String key = (String )keys.next(); 145 final Attributes attributes = (Attributes )entries.get( key ); 146 final Specification specification = getSpecification( key, 147 attributes ); 148 if( null != specification ) 149 { 150 results.add( specification ); 151 } 152 } 153 final ArrayList trimmedResults = removeDuplicates( results ); 154 return (Specification[])trimmedResults.toArray( new Specification[ 0 ] ); 155 } 156 157 169 public Specification( final String specificationTitle, 170 final String specificationVersion, 171 final String specificationVendor, 172 final String implementationTitle, 173 final String implementationVersion, 174 final String implementationVendor ) 175 { 176 this( specificationTitle, specificationVersion, specificationVendor, 177 implementationTitle, implementationVersion, implementationVendor, 178 null ); 179 } 180 181 194 public Specification( final String specificationTitle, 195 final String specificationVersion, 196 final String specificationVendor, 197 final String implementationTitle, 198 final String implementationVersion, 199 final String implementationVendor, 200 final String [] sections ) 201 { 202 if( null == specificationTitle ) 203 { 204 throw new NullPointerException ( "specificationTitle" ); 205 } 206 m_specificationTitle = specificationTitle; 207 m_specificationVendor = specificationVendor; 208 if( null != specificationVersion ) 209 { 210 try 211 { 212 m_specificationVersion = 213 new DeweyDecimal( specificationVersion ); 214 } 215 catch( final NumberFormatException nfe ) 216 { 217 final String error = "Bad specification version format '" + 218 specificationVersion + 219 "' in '" + specificationTitle + "'. (Reason: " + nfe + ")"; 220 throw new IllegalArgumentException ( error ); 221 } 222 } 223 m_implementationTitle = implementationTitle; 224 m_implementationVendor = implementationVendor; 225 m_implementationVersion = implementationVersion; 226 String [] copy = null; 227 if( null != sections ) 228 { 229 copy = new String [ sections.length ]; 230 System.arraycopy( sections, 0, copy, 0, sections.length ); 231 } 232 m_sections = copy; 233 } 234 235 240 public String getSpecificationTitle() 241 { 242 return m_specificationTitle; 243 } 244 245 250 public String getSpecificationVendor() 251 { 252 return m_specificationVendor; 253 } 254 255 260 public String getImplementationTitle() 261 { 262 return m_implementationTitle; 263 } 264 265 270 public DeweyDecimal getSpecificationVersion() 271 { 272 return m_specificationVersion; 273 } 274 275 280 public String getImplementationVendor() 281 { 282 return m_implementationVendor; 283 } 284 285 290 public String getImplementationVersion() 291 { 292 return m_implementationVersion; 293 } 294 295 302 public String [] getSections() 303 { 304 if( null == m_sections ) 305 { 306 return null; 307 } 308 else 309 { 310 final String [] sections = new String [ m_sections.length ]; 311 System.arraycopy( m_sections, 0, sections, 0, m_sections.length ); 312 return sections; 313 } 314 } 315 316 325 public Compatability getCompatibilityWith( final Specification other ) 326 { 327 if( !m_specificationTitle.equals( other.getSpecificationTitle() ) ) 329 { 330 return INCOMPATIBLE; 331 } 332 final DeweyDecimal specificationVersion = other.getSpecificationVersion(); 334 if( null != specificationVersion ) 335 { 336 if( null == m_specificationVersion || 337 !isCompatible( m_specificationVersion, specificationVersion ) ) 338 { 339 return REQUIRE_SPECIFICATION_UPGRADE; 340 } 341 } 342 final String implementationVendor = other.getImplementationVendor(); 344 if( null != implementationVendor ) 345 { 346 if( null == m_implementationVendor || 347 !m_implementationVendor.equals( implementationVendor ) ) 348 { 349 return REQUIRE_VENDOR_SWITCH; 350 } 351 } 352 final String implementationVersion = other.getImplementationVersion(); 354 if( null != implementationVersion ) 355 { 356 if( null == m_implementationVersion || 357 !m_implementationVersion.equals( implementationVersion ) ) 358 { 359 return REQUIRE_IMPLEMENTATION_CHANGE; 360 } 361 } 362 return COMPATIBLE; 364 } 365 366 374 public boolean isCompatibleWith( final Specification other ) 375 { 376 return ( COMPATIBLE == getCompatibilityWith( other ) ); 377 } 378 379 384 public String toString() 385 { 386 final String lineSeparator = System.getProperty( "line.separator" ); 387 final String brace = ": "; 388 final StringBuffer sb = new StringBuffer ( 389 SPECIFICATION_TITLE.toString() ); 390 sb.append( brace ); 391 sb.append( m_specificationTitle ); 392 sb.append( lineSeparator ); 393 if( null != m_specificationVersion ) 394 { 395 sb.append( SPECIFICATION_VERSION ); 396 sb.append( brace ); 397 sb.append( m_specificationVersion ); 398 sb.append( lineSeparator ); 399 } 400 if( null != m_specificationVendor ) 401 { 402 sb.append( SPECIFICATION_VENDOR ); 403 sb.append( brace ); 404 sb.append( m_specificationVendor ); 405 sb.append( lineSeparator ); 406 } 407 if( null != m_implementationTitle ) 408 { 409 sb.append( IMPLEMENTATION_TITLE ); 410 sb.append( brace ); 411 sb.append( m_implementationTitle ); 412 sb.append( lineSeparator ); 413 } 414 if( null != m_implementationVersion ) 415 { 416 sb.append( IMPLEMENTATION_VERSION ); 417 sb.append( brace ); 418 sb.append( m_implementationVersion ); 419 sb.append( lineSeparator ); 420 } 421 if( null != m_implementationVendor ) 422 { 423 sb.append( IMPLEMENTATION_VENDOR ); 424 sb.append( brace ); 425 sb.append( m_implementationVendor ); 426 sb.append( lineSeparator ); 427 } 428 return sb.toString(); 429 } 430 431 438 private boolean isCompatible( final DeweyDecimal first, 439 final DeweyDecimal second ) 440 { 441 return first.isGreaterThanOrEqual( second ); 442 } 443 444 454 private static ArrayList removeDuplicates( final ArrayList list ) 455 { 456 final ArrayList results = new ArrayList (); 457 final ArrayList sections = new ArrayList (); 458 while( list.size() > 0 ) 459 { 460 final Specification specification = (Specification)list.remove( 0 ); 461 final Iterator iterator = list.iterator(); 462 while( iterator.hasNext() ) 463 { 464 final Specification other = (Specification)iterator.next(); 465 if( isEqual( specification, other ) ) 466 { 467 final String [] otherSections = other.getSections(); 468 if( null != sections ) 469 { 470 sections.addAll( Arrays.asList( otherSections ) ); 471 } 472 iterator.remove(); 473 } 474 } 475 final Specification merged = 476 mergeInSections( specification, sections ); 477 results.add( merged ); 478 sections.clear(); 480 } 481 return results; 482 } 483 484 492 private static boolean isEqual( final Specification specification, 493 final Specification other ) 494 { 495 return 496 specification.getSpecificationTitle().equals( 497 other.getSpecificationTitle() ) && 498 specification.getSpecificationVersion().isEqual( 499 other.getSpecificationVersion() ) && 500 specification.getSpecificationVendor().equals( 501 other.getSpecificationVendor() ) && 502 specification.getImplementationTitle().equals( 503 other.getImplementationTitle() ) && 504 specification.getImplementationVersion().equals( 505 other.getImplementationVersion() ) && 506 specification.getImplementationVendor().equals( 507 other.getImplementationVendor() ); 508 } 509 510 518 private static Specification mergeInSections( 519 final Specification specification, 520 final ArrayList sectionsToAdd ) 521 { 522 if( 0 == sectionsToAdd.size() ) 523 { 524 return specification; 525 } 526 else 527 { 528 sectionsToAdd.addAll( Arrays.asList( specification.getSections() ) ); 529 final String [] sections = 530 (String [])sectionsToAdd.toArray( 531 new String [ sectionsToAdd.size() ] ); 532 return new Specification( specification.getSpecificationTitle(), 533 specification.getSpecificationVersion() 534 .toString(), 535 specification.getSpecificationVendor(), 536 specification.getImplementationTitle(), 537 specification.getImplementationVersion(), 538 specification.getImplementationVendor(), 539 sections ); 540 } 541 } 542 543 549 private static String getTrimmedString( final String value ) 550 { 551 if( null == value ) 552 { 553 return null; 554 } 555 else 556 { 557 return value.trim(); 558 } 559 } 560 561 567 private static Specification getSpecification( final String section, 568 final Attributes attributes ) 569 throws ParseException 570 { 571 final String name = getTrimmedString( 575 attributes.getValue( SPECIFICATION_TITLE ) ); 576 if( null == name ) 577 { 578 return null; 579 } 580 final String specVendor = getTrimmedString( 581 attributes.getValue( SPECIFICATION_VENDOR ) ); 582 if( null == specVendor ) 583 { 584 throw new ParseException ( "Missing " + SPECIFICATION_VENDOR, 0 ); 585 } 586 final String specVersion = getTrimmedString( 587 attributes.getValue( SPECIFICATION_VERSION ) ); 588 if( null == specVersion ) 589 { 590 throw new ParseException ( "Missing " + SPECIFICATION_VERSION, 0 ); 591 } 592 final String impTitle = getTrimmedString( 593 attributes.getValue( IMPLEMENTATION_TITLE ) ); 594 if( null == impTitle ) 595 { 596 throw new ParseException ( "Missing " + IMPLEMENTATION_TITLE, 0 ); 597 } 598 final String impVersion = getTrimmedString( 599 attributes.getValue( IMPLEMENTATION_VERSION ) ); 600 if( null == impVersion ) 601 { 602 throw new ParseException ( "Missing " + IMPLEMENTATION_VERSION, 0 ); 603 } 604 final String impVendor = getTrimmedString( 605 attributes.getValue( IMPLEMENTATION_VENDOR ) ); 606 if( null == impVendor ) 607 { 608 throw new ParseException ( "Missing " + IMPLEMENTATION_VENDOR, 0 ); 609 } 610 return new Specification( name, specVersion, specVendor, 611 impTitle, impVersion, impVendor, 612 new String []{section} ); 613 } 614 } 615 | Popular Tags |