Clover coverage report - Ant Coverage
Coverage timestamp: Tue Apr 8 2003 20:43:55 EST
file stats: LOC: 694   Methods: 19
NCLOC: 339   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
Specification.java 0% 0% 0% 0%
 1   
 /*
 2   
  * The Apache Software License, Version 1.1
 3   
  *
 4   
  * Copyright (c) 2002 The Apache Software Foundation.  All rights
 5   
  * reserved.
 6   
  *
 7   
  * Redistribution and use in source and binary forms, with or without
 8   
  * modification, are permitted provided that the following conditions
 9   
  * are met:
 10   
  *
 11   
  * 1. Redistributions of source code must retain the above copyright
 12   
  *    notice, this list of conditions and the following disclaimer.
 13   
  *
 14   
  * 2. Redistributions in binary form must reproduce the above copyright
 15   
  *    notice, this list of conditions and the following disclaimer in
 16   
  *    the documentation and/or other materials provided with the
 17   
  *    distribution.
 18   
  *
 19   
  * 3. The end-user documentation included with the redistribution, if
 20   
  *    any, must include the following acknowlegement:
 21   
  *       "This product includes software developed by the
 22   
  *        Apache Software Foundation (http://www.apache.org/)."
 23   
  *    Alternately, this acknowlegement may appear in the software itself,
 24   
  *    if and wherever such third-party acknowlegements normally appear.
 25   
  *
 26   
  * 4. The names "Ant" and "Apache Software
 27   
  *    Foundation" must not be used to endorse or promote products derived
 28   
  *    from this software without prior written permission. For written
 29   
  *    permission, please contact apache@apache.org.
 30   
  *
 31   
  * 5. Products derived from this software may not be called "Apache"
 32   
  *    nor may "Apache" appear in their names without prior written
 33   
  *    permission of the Apache Group.
 34   
  *
 35   
  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 36   
  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 37   
  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 38   
  * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 39   
  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 40   
  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 41   
  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 42   
  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 43   
  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 44   
  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 45   
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 46   
  * SUCH DAMAGE.
 47   
  * ====================================================================
 48   
  *
 49   
  * This software consists of voluntary contributions made by many
 50   
  * individuals on behalf of the Apache Software Foundation.  For more
 51   
  * information on the Apache Software Foundation, please see
 52   
  * <http://www.apache.org/>.
 53   
  */
 54   
 package org.apache.tools.ant.taskdefs.optional.extension;
 55   
 
 56   
 import java.text.ParseException;
 57   
 import java.util.ArrayList;
 58   
 import java.util.Arrays;
 59   
 import java.util.Iterator;
 60   
 import java.util.Map;
 61   
 import java.util.jar.Attributes;
 62   
 import java.util.jar.Manifest;
 63   
 
 64   
 /**
 65   
  * <p>Utility class that represents either an available "Optional Package"
 66   
  * (formerly known as "Standard Extension") as described in the manifest
 67   
  * of a JAR file, or the requirement for such an optional package.</p>
 68   
  *
 69   
  * <p>For more information about optional packages, see the document
 70   
  * <em>Optional Package Versioning</em> in the documentation bundle for your
 71   
  * Java2 Standard Edition package, in file
 72   
  * <code>guide/extensions/versioning.html</code>.</p>
 73   
  *
 74   
  * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
 75   
  *  This file is from excalibur.extension package. Dont edit this file
 76   
  * directly as there is no unit tests to make sure it is operational
 77   
  * in ant. Edit file in excalibur and run tests there before changing
 78   
  * ants file.
 79   
  * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
 80   
  *
 81   
  * @author <a href="mailto:peter@apache.org">Peter Donald</a>
 82   
  * @version $Revision: 1.3 $ $Date: 2003/02/10 14:14:03 $
 83   
  */
 84   
 public final class Specification
 85   
 {
 86   
     /**
 87   
      * Manifest Attribute Name object for SPECIFICATION_TITLE.
 88   
      * @see Attributes.Name#SPECIFICATION_TITLE
 89   
      */
 90   
     public static final Attributes.Name SPECIFICATION_TITLE = Attributes.Name.SPECIFICATION_TITLE;
 91   
 
 92   
     /**
 93   
      * Manifest Attribute Name object for SPECIFICATION_VERSION.
 94   
      * @see Attributes.Name#SPECIFICATION_VERSION
 95   
      */
 96   
     public static final Attributes.Name SPECIFICATION_VERSION = Attributes.Name.SPECIFICATION_VERSION;
 97   
 
 98   
     /**
 99   
      * Manifest Attribute Name object for SPECIFICATION_VENDOR.
 100   
      * @see Attributes.Name#SPECIFICATION_VENDOR
 101   
      */
 102   
     public static final Attributes.Name SPECIFICATION_VENDOR = Attributes.Name.SPECIFICATION_VENDOR;
 103   
 
 104   
     /**
 105   
      * Manifest Attribute Name object for IMPLEMENTATION_TITLE.
 106   
      * @see Attributes.Name#IMPLEMENTATION_TITLE
 107   
      */
 108   
     public static final Attributes.Name IMPLEMENTATION_TITLE = Attributes.Name.IMPLEMENTATION_TITLE;
 109   
 
 110   
     /**
 111   
      * Manifest Attribute Name object for IMPLEMENTATION_VERSION.
 112   
      * @see Attributes.Name#IMPLEMENTATION_VERSION
 113   
      */
 114   
     public static final Attributes.Name IMPLEMENTATION_VERSION = Attributes.Name.IMPLEMENTATION_VERSION;
 115   
 
 116   
     /**
 117   
      * Manifest Attribute Name object for IMPLEMENTATION_VENDOR.
 118   
      * @see Attributes.Name#IMPLEMENTATION_VENDOR
 119   
      */
 120   
     public static final Attributes.Name IMPLEMENTATION_VENDOR = Attributes.Name.IMPLEMENTATION_VENDOR;
 121   
 
 122   
     /**
 123   
      * Enum indicating that extension is compatible with other Package
 124   
      * Specification.
 125   
      */
 126   
     public static final Compatibility COMPATIBLE =
 127   
         new Compatibility( "COMPATIBLE" );
 128   
 
 129   
     /**
 130   
      * Enum indicating that extension requires an upgrade
 131   
      * of specification to be compatible with other Package Specification.
 132   
      */
 133   
     public static final Compatibility REQUIRE_SPECIFICATION_UPGRADE =
 134   
         new Compatibility( "REQUIRE_SPECIFICATION_UPGRADE" );
 135   
 
 136   
     /**
 137   
      * Enum indicating that extension requires a vendor
 138   
      * switch to be compatible with other Package Specification.
 139   
      */
 140   
     public static final Compatibility REQUIRE_VENDOR_SWITCH =
 141   
         new Compatibility( "REQUIRE_VENDOR_SWITCH" );
 142   
 
 143   
     /**
 144   
      * Enum indicating that extension requires an upgrade
 145   
      * of implementation to be compatible with other Package Specification.
 146   
      */
 147   
     public static final Compatibility REQUIRE_IMPLEMENTATION_CHANGE =
 148   
         new Compatibility( "REQUIRE_IMPLEMENTATION_CHANGE" );
 149   
 
 150   
     /**
 151   
      * Enum indicating that extension is incompatible with
 152   
      * other Package Specification in ways other than other enums
 153   
      * indicate). ie For example the other Package Specification
 154   
      * may have a different ID.
 155   
      */
 156   
     public static final Compatibility INCOMPATIBLE =
 157   
         new Compatibility( "INCOMPATIBLE" );
 158   
 
 159   
     /**
 160   
      * The name of the Package Specification.
 161   
      */
 162   
     private String m_specificationTitle;
 163   
 
 164   
     /**
 165   
      * The version number (dotted decimal notation) of the specification
 166   
      * to which this optional package conforms.
 167   
      */
 168   
     private DeweyDecimal m_specificationVersion;
 169   
 
 170   
     /**
 171   
      * The name of the company or organization that originated the
 172   
      * specification to which this specification conforms.
 173   
      */
 174   
     private String m_specificationVendor;
 175   
 
 176   
     /**
 177   
      * The title of implementation.
 178   
      */
 179   
     private String m_implementationTitle;
 180   
 
 181   
     /**
 182   
      * The name of the company or organization that produced this
 183   
      * implementation of this specification.
 184   
      */
 185   
     private String m_implementationVendor;
 186   
 
 187   
     /**
 188   
      * The version string for implementation. The version string is
 189   
      * opaque.
 190   
      */
 191   
     private String m_implementationVersion;
 192   
 
 193   
     /**
 194   
      * The sections of jar that the specification applies to.
 195   
      */
 196   
     private String[] m_sections;
 197   
 
 198   
     /**
 199   
      * Return an array of <code>Package Specification</code> objects.
 200   
      * If there are no such optional packages, a zero-length array is returned.
 201   
      *
 202   
      * @param manifest Manifest to be parsed
 203   
      * @return the Package Specifications extensions in specified manifest
 204   
      */
 205  0
     public static Specification[] getSpecifications( final Manifest manifest )
 206   
         throws ParseException
 207   
     {
 208  0
         if( null == manifest )
 209   
         {
 210  0
             return new Specification[ 0 ];
 211   
         }
 212   
 
 213  0
         final ArrayList results = new ArrayList();
 214   
 
 215  0
         final Map entries = manifest.getEntries();
 216  0
         final Iterator keys = entries.keySet().iterator();
 217  0
         while( keys.hasNext() )
 218   
         {
 219  0
             final String key = (String)keys.next();
 220  0
             final Attributes attributes = (Attributes)entries.get( key );
 221  0
             final Specification specification = getSpecification( key, attributes );
 222  0
             if( null != specification )
 223   
             {
 224  0
                 results.add( specification );
 225   
             }
 226   
         }
 227   
 
 228  0
         final ArrayList trimmedResults = removeDuplicates( results );
 229  0
         return (Specification[])trimmedResults.toArray( new Specification[ 0 ] );
 230   
     }
 231   
 
 232   
     /**
 233   
      * The constructor to create Package Specification object.
 234   
      * Note that every component is allowed to be specified
 235   
      * but only the specificationTitle is mandatory.
 236   
      *
 237   
      * @param specificationTitle the name of specification.
 238   
      * @param specificationVersion the specification Version.
 239   
      * @param specificationVendor the specification Vendor.
 240   
      * @param implementationTitle the title of implementation.
 241   
      * @param implementationVersion the implementation Version.
 242   
      * @param implementationVendor the implementation Vendor.
 243   
      */
 244  0
     public Specification( final String specificationTitle,
 245   
                           final String specificationVersion,
 246   
                           final String specificationVendor,
 247   
                           final String implementationTitle,
 248   
                           final String implementationVersion,
 249   
                           final String implementationVendor )
 250   
     {
 251  0
         this( specificationTitle, specificationVersion, specificationVendor,
 252   
               implementationTitle, implementationVersion, implementationVendor,
 253   
               null );
 254   
     }
 255   
 
 256   
     /**
 257   
      * The constructor to create Package Specification object.
 258   
      * Note that every component is allowed to be specified
 259   
      * but only the specificationTitle is mandatory.
 260   
      *
 261   
      * @param specificationTitle the name of specification.
 262   
      * @param specificationVersion the specification Version.
 263   
      * @param specificationVendor the specification Vendor.
 264   
      * @param implementationTitle the title of implementation.
 265   
      * @param implementationVersion the implementation Version.
 266   
      * @param implementationVendor the implementation Vendor.
 267   
      * @param sections the sections/packages that Specification applies to.
 268   
      */
 269  0
     public Specification( final String specificationTitle,
 270   
                           final String specificationVersion,
 271   
                           final String specificationVendor,
 272   
                           final String implementationTitle,
 273   
                           final String implementationVersion,
 274   
                           final String implementationVendor,
 275   
                           final String[] sections )
 276   
     {
 277  0
         m_specificationTitle = specificationTitle;
 278  0
         m_specificationVendor = specificationVendor;
 279   
 
 280  0
         if( null != specificationVersion )
 281   
         {
 282  0
             try
 283   
             {
 284  0
                 m_specificationVersion = new DeweyDecimal( specificationVersion );
 285   
             }
 286   
             catch( final NumberFormatException nfe )
 287   
             {
 288  0
                 final String error = "Bad specification version format '" + specificationVersion +
 289   
                     "' in '" + specificationTitle + "'. (Reason: " + nfe + ")";
 290  0
                 throw new IllegalArgumentException( error );
 291   
             }
 292   
         }
 293   
 
 294  0
         m_implementationTitle = implementationTitle;
 295  0
         m_implementationVendor = implementationVendor;
 296  0
         m_implementationVersion = implementationVersion;
 297   
 
 298  0
         if( null == m_specificationTitle )
 299   
         {
 300  0
             throw new NullPointerException( "specificationTitle" );
 301   
         }
 302   
 
 303  0
         String[] copy = null;
 304  0
         if( null != sections )
 305   
         {
 306  0
             copy = new String[ sections.length ];
 307  0
             System.arraycopy( sections, 0, copy, 0, sections.length );
 308   
         }
 309  0
         m_sections = copy;
 310   
     }
 311   
 
 312   
     /**
 313   
      * Get the title of the specification.
 314   
      *
 315   
      * @return the title of speciication
 316   
      */
 317  0
     public String getSpecificationTitle()
 318   
     {
 319  0
         return m_specificationTitle;
 320   
     }
 321   
 
 322   
     /**
 323   
      * Get the vendor of the specification.
 324   
      *
 325   
      * @return the vendor of the specification.
 326   
      */
 327  0
     public String getSpecificationVendor()
 328   
     {
 329  0
         return m_specificationVendor;
 330   
     }
 331   
 
 332   
     /**
 333   
      * Get the title of the specification.
 334   
      *
 335   
      * @return the title of the specification.
 336   
      */
 337  0
     public String getImplementationTitle()
 338   
     {
 339  0
         return m_implementationTitle;
 340   
     }
 341   
 
 342   
     /**
 343   
      * Get the version of the specification.
 344   
      *
 345   
      * @return the version of the specification.
 346   
      */
 347  0
     public DeweyDecimal getSpecificationVersion()
 348   
     {
 349  0
         return m_specificationVersion;
 350   
     }
 351   
 
 352   
     /**
 353   
      * Get the vendor of the extensions implementation.
 354   
      *
 355   
      * @return the vendor of the extensions implementation.
 356   
      */
 357  0
     public String getImplementationVendor()
 358   
     {
 359  0
         return m_implementationVendor;
 360   
     }
 361   
 
 362   
     /**
 363   
      * Get the version of the implementation.
 364   
      *
 365   
      * @return the version of the implementation.
 366   
      */
 367  0
     public String getImplementationVersion()
 368   
     {
 369  0
         return m_implementationVersion;
 370   
     }
 371   
 
 372   
     /**
 373   
      * Return an array containing sections to which specification applies
 374   
      * or null if relevent to no sections.
 375   
      *
 376   
      * @return an array containing sections to which specification applies
 377   
      *         or null if relevent to no sections.
 378   
      */
 379  0
     public String[] getSections()
 380   
     {
 381  0
         if( null == m_sections )
 382   
         {
 383  0
             return null;
 384   
         }
 385   
         else
 386   
         {
 387  0
             final String[] sections = new String[ m_sections.length ];
 388  0
             System.arraycopy( m_sections, 0, sections, 0, m_sections.length );
 389  0
             return sections;
 390   
         }
 391   
     }
 392   
 
 393   
     /**
 394   
      * Return a Compatibility enum indicating the relationship of this
 395   
      * <code>Package Specification</code> with the specified <code>Extension</code>.
 396   
      *
 397   
      * @param other the other specification
 398   
      * @return the enum indicating the compatibility (or lack thereof)
 399   
      *         of specifed Package Specification
 400   
      */
 401  0
     public Compatibility getCompatibilityWith( final Specification other )
 402   
     {
 403   
         // Specification Name must match
 404  0
         if( !m_specificationTitle.equals( other.getSpecificationTitle() ) )
 405   
         {
 406  0
             return INCOMPATIBLE;
 407   
         }
 408   
 
 409   
         // Available specification version must be >= required
 410  0
         final DeweyDecimal specificationVersion = other.getSpecificationVersion();
 411  0
         if( null != specificationVersion )
 412   
         {
 413  0
             if( null == m_specificationVersion ||
 414   
                 !isCompatible( m_specificationVersion, specificationVersion ) )
 415   
             {
 416  0
                 return REQUIRE_SPECIFICATION_UPGRADE;
 417   
             }
 418   
         }
 419   
 
 420   
         // Implementation Vendor ID must match
 421  0
         final String implementationVendor = other.getImplementationVendor();
 422  0
         if( null != implementationVendor )
 423   
         {
 424  0
             if( null == m_implementationVendor ||
 425   
                 !m_implementationVendor.equals( implementationVendor ) )
 426   
             {
 427  0
                 return REQUIRE_VENDOR_SWITCH;
 428   
             }
 429   
         }
 430   
 
 431   
         // Implementation version must be >= required
 432  0
         final String implementationVersion = other.getImplementationVersion();
 433  0
         if( null != implementationVersion )
 434   
         {
 435  0
             if( null == m_implementationVersion ||
 436   
                 !m_implementationVersion.equals( implementationVersion ) )
 437   
             {
 438  0
                 return REQUIRE_IMPLEMENTATION_CHANGE;
 439   
             }
 440   
         }
 441   
 
 442   
         // This available optional package satisfies the requirements
 443  0
         return COMPATIBLE;
 444   
     }
 445   
 
 446   
     /**
 447   
      * Return <code>true</code> if the specified <code>package</code>
 448   
      * is satisfied by this <code>Specification</code>. Otherwise, return
 449   
      * <code>false</code>.
 450   
      *
 451   
      * @param other the specification
 452   
      * @return true if the specification is compatible with this specification
 453   
      */
 454  0
     public boolean isCompatibleWith( final Specification other )
 455   
     {
 456  0
         return ( COMPATIBLE == getCompatibilityWith( other ) );
 457   
     }
 458   
 
 459   
     /**
 460   
      * Return a String representation of this object.
 461   
      *
 462   
      * @return string representation of object.
 463   
      */
 464  0
     public String toString()
 465   
     {
 466  0
         final String lineSeparator = System.getProperty( "line.separator" );
 467  0
         final String brace = ": ";
 468   
 
 469  0
         final StringBuffer sb = new StringBuffer( SPECIFICATION_TITLE.toString() );
 470  0
         sb.append( brace );
 471  0
         sb.append( m_specificationTitle );
 472  0
         sb.append( lineSeparator );
 473   
 
 474  0
         if( null != m_specificationVersion )
 475   
         {
 476  0
             sb.append( SPECIFICATION_VERSION );
 477  0
             sb.append( brace );
 478  0
             sb.append( m_specificationVersion );
 479  0
             sb.append( lineSeparator );
 480   
         }
 481   
 
 482  0
         if( null != m_specificationVendor )
 483   
         {
 484  0
             sb.append( SPECIFICATION_VENDOR );
 485  0
             sb.append( brace );
 486  0
             sb.append( m_specificationVendor );
 487  0
             sb.append( lineSeparator );
 488   
         }
 489   
 
 490  0
         if( null != m_implementationTitle )
 491   
         {
 492  0
             sb.append( IMPLEMENTATION_TITLE );
 493  0
             sb.append( brace );
 494  0
             sb.append( m_implementationTitle );
 495  0
             sb.append( lineSeparator );
 496   
         }
 497   
 
 498  0
         if( null != m_implementationVersion )
 499   
         {
 500  0
             sb.append( IMPLEMENTATION_VERSION );
 501  0
             sb.append( brace );
 502  0
             sb.append( m_implementationVersion );
 503  0
             sb.append( lineSeparator );
 504   
         }
 505   
 
 506  0
         if( null != m_implementationVendor )
 507   
         {
 508  0
             sb.append( IMPLEMENTATION_VENDOR );
 509  0
             sb.append( brace );
 510  0
             sb.append( m_implementationVendor );
 511  0
             sb.append( lineSeparator );
 512   
         }
 513   
 
 514  0
         return sb.toString();
 515   
     }
 516   
 
 517   
     /**
 518   
      * Return <code>true</code> if the first version number is greater than
 519   
      * or equal to the second; otherwise return <code>false</code>.
 520   
      *
 521   
      * @param first First version number (dotted decimal)
 522   
      * @param second Second version number (dotted decimal)
 523   
      */
 524  0
     private boolean isCompatible( final DeweyDecimal first, final DeweyDecimal second )
 525   
     {
 526  0
         return first.isGreaterThanOrEqual( second );
 527   
     }
 528   
 
 529   
     /**
 530   
      * Combine all specifications objects that are identical except
 531   
      * for the sections.
 532   
      *
 533   
      * <p>Note this is very inefficent and should probably be fixed
 534   
      * in the future.</p>
 535   
      *
 536   
      * @param list the array of results to trim
 537   
      * @return an array list with all duplicates removed
 538   
      */
 539  0
     private static ArrayList removeDuplicates( final ArrayList list )
 540   
     {
 541  0
         final ArrayList results = new ArrayList();
 542  0
         final ArrayList sections = new ArrayList();
 543  0
         while( list.size() > 0 )
 544   
         {
 545  0
             final Specification specification = (Specification)list.remove( 0 );
 546  0
             final Iterator iterator = list.iterator();
 547  0
             while( iterator.hasNext() )
 548   
             {
 549  0
                 final Specification other = (Specification)iterator.next();
 550  0
                 if( isEqual( specification, other ) )
 551   
                 {
 552  0
                     final String[] otherSections = other.getSections();
 553  0
                     if( null != sections )
 554   
                     {
 555  0
                         sections.addAll( Arrays.asList( otherSections ) );
 556   
                     }
 557  0
                     iterator.remove();
 558   
                 }
 559   
             }
 560   
 
 561  0
             final Specification merged =
 562   
                 mergeInSections( specification, sections );
 563  0
             results.add( merged );
 564   
             //Reset list of sections
 565  0
             sections.clear();
 566   
         }
 567   
 
 568  0
         return results;
 569   
     }
 570   
 
 571   
     /**
 572   
      * Test if two specifications are equal except for their sections.
 573   
      *
 574   
      * @param specification one specificaiton
 575   
      * @param other the ohter specification
 576   
      * @return true if two specifications are equal except for their
 577   
      *         sections, else false
 578   
      */
 579  0
     private static boolean isEqual( final Specification specification,
 580   
                                     final Specification other )
 581   
     {
 582  0
         return
 583   
             specification.getSpecificationTitle().equals( other.getSpecificationTitle() ) &&
 584   
             specification.getSpecificationVersion().isEqual( other.getSpecificationVersion() ) &&
 585   
             specification.getSpecificationVendor().equals( other.getSpecificationVendor() ) &&
 586   
             specification.getImplementationTitle().equals( other.getImplementationTitle() ) &&
 587   
             specification.getImplementationVersion().equals( other.getImplementationVersion() ) &&
 588   
             specification.getImplementationVendor().equals( other.getImplementationVendor() );
 589   
     }
 590   
 
 591   
     /**
 592   
      * Merge the specified sections into specified section and return result.
 593   
      * If no sections to be added then just return original specification.
 594   
      *
 595   
      * @param specification the specification
 596   
      * @param sectionsToAdd the list of sections to merge
 597   
      * @return the merged specification
 598   
      */
 599  0
     private static Specification mergeInSections( final Specification specification,
 600   
                                                   final ArrayList sectionsToAdd )
 601   
     {
 602  0
         if( 0 == sectionsToAdd.size() )
 603   
         {
 604  0
             return specification;
 605   
         }
 606   
         else
 607   
         {
 608  0
             sectionsToAdd.addAll( Arrays.asList( specification.getSections() ) );
 609   
 
 610  0
             final String[] sections =
 611   
                 (String[])sectionsToAdd.toArray( new String[ sectionsToAdd.size() ] );
 612   
 
 613  0
             return new Specification( specification.getSpecificationTitle(),
 614   
                                       specification.getSpecificationVersion().toString(),
 615   
                                       specification.getSpecificationVendor(),
 616   
                                       specification.getImplementationTitle(),
 617   
                                       specification.getImplementationVersion(),
 618   
                                       specification.getImplementationVendor(),
 619   
                                       sections );
 620   
         }
 621   
     }
 622   
 
 623   
     /**
 624   
      * Trim the supplied string if the string is non-null
 625   
      *
 626   
      * @param value the string to trim or null
 627   
      * @return the trimmed string or null
 628   
      */
 629  0
     private static String getTrimmedString( final String value )
 630   
     {
 631  0
         if( null == value )
 632   
         {
 633  0
             return null;
 634   
         }
 635   
         else
 636   
         {
 637  0
             return value.trim();
 638   
         }
 639   
     }
 640   
 
 641   
     /**
 642   
      * Extract an Package Specification from Attributes.
 643   
      *
 644   
      * @param attributes Attributes to searched
 645   
      * @return the new Specification object, or null
 646   
      */
 647  0
     private static Specification getSpecification( final String section,
 648   
                                                    final Attributes attributes )
 649   
         throws ParseException
 650   
     {
 651   
         //WARNING: We trim the values of all the attributes because
 652   
         //Some extension declarations are badly defined (ie have spaces
 653   
         //after version or vendor)
 654  0
         final String name = getTrimmedString( attributes.getValue( SPECIFICATION_TITLE ) );
 655  0
         if( null == name )
 656   
         {
 657  0
             return null;
 658   
         }
 659   
 
 660  0
         final String specVendor = getTrimmedString( attributes.getValue( SPECIFICATION_VENDOR ) );
 661  0
         if( null == specVendor )
 662   
         {
 663  0
             throw new ParseException( "Missing " + SPECIFICATION_VENDOR, 0 );
 664   
         }
 665   
 
 666  0
         final String specVersion = getTrimmedString( attributes.getValue( SPECIFICATION_VERSION ) );
 667  0
         if( null == specVersion )
 668   
         {
 669  0
             throw new ParseException( "Missing " + SPECIFICATION_VERSION, 0 );
 670   
         }
 671   
 
 672  0
         final String impTitle = getTrimmedString( attributes.getValue( IMPLEMENTATION_TITLE ) );
 673  0
         if( null == impTitle )
 674   
         {
 675  0
             throw new ParseException( "Missing " + IMPLEMENTATION_TITLE, 0 );
 676   
         }
 677   
 
 678  0
         final String impVersion = getTrimmedString( attributes.getValue( IMPLEMENTATION_VERSION ) );
 679  0
         if( null == impVersion )
 680   
         {
 681  0
             throw new ParseException( "Missing " + IMPLEMENTATION_VERSION, 0 );
 682   
         }
 683   
 
 684  0
         final String impVendor = getTrimmedString( attributes.getValue( IMPLEMENTATION_VENDOR ) );
 685  0
         if( null == impVendor )
 686   
         {
 687  0
             throw new ParseException( "Missing " + IMPLEMENTATION_VENDOR, 0 );
 688   
         }
 689   
 
 690  0
         return new Specification( name, specVersion, specVendor,
 691   
                                   impTitle, impVersion, impVendor,
 692   
                                   new String[]{section} );
 693   
     }
 694   
 }