Clover coverage report - Extension - 1.1
Coverage timestamp: Tue Dec 2 2003 18:57:12 EST
file stats: LOC: 684   Methods: 24
NCLOC: 385   Classes: 1
30 day Evaluation Version distributed via the Maven Jar Repository. Clover is not free. You have 30 days to evaluate it. Please visit http://www.thecortex.net/clover to obtain a licensed version of Clover
 
 Source file Conditionals Statements Methods TOTAL
Extension.java 0% 0% 0% 0%
coverage
 1   
 /*
 2   
  * Copyright (C) The Spice Group. All rights reserved.
 3   
  *
 4   
  * This software is published under the terms of the Spice
 5   
  * Software License version 1.1, a copy of which has been included
 6   
  * with this distribution in the LICENSE.txt file.
 7   
  *
 8   
  * This product includes software developed by the
 9   
  * Apache Software Foundation (http://www.apache.org/).
 10   
  */
 11   
 package org.codehaus.spice.extension;
 12   
 import java.util.ArrayList;
 13   
 import java.util.Iterator;
 14   
 import java.util.Map;
 15   
 import java.util.StringTokenizer;
 16   
 import java.util.jar.Attributes;
 17   
 import java.util.jar.Manifest;
 18   
 /**
 19   
  * <p>Utility class that represents either an available "Optional Package"
 20   
  * (formerly known as "Standard Extension") as described in the manifest
 21   
  * of a JAR file, or the requirement for such an optional package.</p>
 22   
  *
 23   
  * <p>For more information about optional packages, see the document
 24   
  * <em>Optional Package Versioning</em> in the documentation bundle for your
 25   
  * Java2 Standard Edition package, in file
 26   
  * <code>guide/extensions/versioning.html</code>.</p>
 27   
  *
 28   
  * @author <a href="mailto:craigmcc at apache.org">Craig R. McClanahan</a>
 29   
  * @author <a href="mailto:peter at realityforge.org">Peter Donald</a>
 30   
  * @version $Revision: 1.1 $ $Date: 2003/12/02 07:56:59 $
 31   
  */
 32   
 public final class Extension
 33   
 {
 34   
     /**
 35   
      * Manifest Attribute Name object for EXTENSION_LIST.
 36   
      * @see Attributes.Name#EXTENSION_LIST
 37   
      */
 38   
     public static final Attributes.Name EXTENSION_LIST = Attributes.Name.EXTENSION_LIST;
 39   
     /**
 40   
      * <code>Name</code> object for <code>Optional-Extension-List</code>
 41   
      * manifest attribute used for declaring optional dependencies on
 42   
      * installed extensions. Note that the dependencies declared by this method
 43   
      * are not required for the library to operate but if present will be used.
 44   
      * It is NOT part of the official "Optional Package" specification.
 45   
      *
 46   
      * @see <a href="http://java.sun.com/j2se/1.3/docs/guide/extensions/spec.html#dependnecy">
 47   
      *      Installed extension dependency</a>
 48   
      */
 49   
     public static final Attributes.Name OPTIONAL_EXTENSION_LIST =
 50   
         new Attributes.Name( "Optional-Extension-List" );
 51   
     /**
 52   
      * Manifest Attribute Name object for EXTENSION_NAME.
 53   
      * @see Attributes.Name#EXTENSION_NAME
 54   
      */
 55   
     public static final Attributes.Name EXTENSION_NAME =
 56   
         Attributes.Name.EXTENSION_NAME;
 57   
     /**
 58   
      * Manifest Attribute Name object for SPECIFICATION_VERSION.
 59   
      * @see Attributes.Name#SPECIFICATION_VERSION
 60   
      */
 61   
     public static final Attributes.Name SPECIFICATION_VERSION =
 62   
         Attributes.Name.SPECIFICATION_VERSION;
 63   
     /**
 64   
      * Manifest Attribute Name object for SPECIFICATION_VENDOR.
 65   
      * @see Attributes.Name#SPECIFICATION_VENDOR
 66   
      */
 67   
     public static final Attributes.Name SPECIFICATION_VENDOR =
 68   
         Attributes.Name.SPECIFICATION_VENDOR;
 69   
     /**
 70   
      * Manifest Attribute Name object for IMPLEMENTATION_VERSION.
 71   
      * @see Attributes.Name#IMPLEMENTATION_VERSION
 72   
      */
 73   
     public static final Attributes.Name IMPLEMENTATION_VERSION =
 74   
         Attributes.Name.IMPLEMENTATION_VERSION;
 75   
     /**
 76   
      * Manifest Attribute Name object for IMPLEMENTATION_VENDOR.
 77   
      * @see Attributes.Name#IMPLEMENTATION_VENDOR
 78   
      */
 79   
     public static final Attributes.Name IMPLEMENTATION_VENDOR =
 80   
         Attributes.Name.IMPLEMENTATION_VENDOR;
 81   
     /**
 82   
      * Manifest Attribute Name object for IMPLEMENTATION_URL.
 83   
      * @see Attributes.Name#IMPLEMENTATION_URL
 84   
      */
 85   
     public static final Attributes.Name IMPLEMENTATION_URL =
 86   
         Attributes.Name.IMPLEMENTATION_URL;
 87   
     /**
 88   
      * Manifest Attribute Name object for IMPLEMENTATION_VENDOR_ID.
 89   
      * @see Attributes.Name#IMPLEMENTATION_VENDOR_ID
 90   
      */
 91   
     public static final Attributes.Name IMPLEMENTATION_VENDOR_ID =
 92   
         Attributes.Name.IMPLEMENTATION_VENDOR_ID;
 93   
     /**
 94   
      * Enum indicating that extension is compatible with other extension.
 95   
      */
 96   
     public static final Compatability COMPATIBLE =
 97   
         new Compatability( "COMPATIBLE" );
 98   
     /**
 99   
      * Enum indicating that extension requires an upgrade
 100   
      * of specification to be compatible with other extension.
 101   
      */
 102   
     public static final Compatability REQUIRE_SPECIFICATION_UPGRADE =
 103   
         new Compatability( "REQUIRE_SPECIFICATION_UPGRADE" );
 104   
     /**
 105   
      * Enum indicating that extension requires a vendor
 106   
      * switch to be compatible with other extension.
 107   
      */
 108   
     public static final Compatability REQUIRE_VENDOR_SWITCH =
 109   
         new Compatability( "REQUIRE_VENDOR_SWITCH" );
 110   
     /**
 111   
      * Enum indicating that extension requires an upgrade
 112   
      * of implementation to be compatible with other extension.
 113   
      */
 114   
     public static final Compatability REQUIRE_IMPLEMENTATION_UPGRADE =
 115   
         new Compatability( "REQUIRE_IMPLEMENTATION_UPGRADE" );
 116   
     /**
 117   
      * Enum indicating that extension is incompatible with
 118   
      * other extension in ways other than other enums
 119   
      * indicate). ie For example the other extension may have
 120   
      * a different ID.
 121   
      */
 122   
     public static final Compatability INCOMPATIBLE =
 123   
         new Compatability( "INCOMPATIBLE" );
 124   
     /**
 125   
      * The name of the optional package being made available, or required.
 126   
      */
 127   
     private String m_extensionName;
 128   
     /**
 129   
      * The version number (dotted decimal notation) of the specification
 130   
      * to which this optional package conforms.
 131   
      */
 132   
     private DeweyDecimal m_specificationVersion;
 133   
     /**
 134   
      * The name of the company or organization that originated the
 135   
      * specification to which this optional package conforms.
 136   
      */
 137   
     private String m_specificationVendor;
 138   
     /**
 139   
      * The unique identifier of the company that produced the optional
 140   
      * package contained in this JAR file.
 141   
      */
 142   
     private String m_implementationVendorID;
 143   
     /**
 144   
      * The name of the company or organization that produced this
 145   
      * implementation of this optional package.
 146   
      */
 147   
     private String m_implementationVendor;
 148   
     /**
 149   
      * The version number (dotted decimal notation) for this implementation
 150   
      * of the optional package.
 151   
      */
 152   
     private String m_implementationVersion;
 153   
     /**
 154   
      * The URL from which the most recent version of this optional package
 155   
      * can be obtained if it is not already installed.
 156   
      */
 157   
     private String m_implementationURL;
 158   
     /**
 159   
      * Return an array of <code>Extension</code> objects representing optional
 160   
      * packages that are available in the JAR file associated with the
 161   
      * specified <code>Manifest</code>.  If there are no such optional
 162   
      * packages, a zero-length array is returned.
 163   
      *
 164   
      * @param manifest Manifest to be parsed
 165   
      * @return the "available" extensions in specified manifest
 166   
      */
 167  0
     public static Extension[] getAvailable( final Manifest manifest )
 168   
     {
 169  0
         if( null == manifest )
 170   
         {
 171  0
             return new Extension[ 0 ];
 172   
         }
 173  0
         final ArrayList results = new ArrayList();
 174  0
         final Attributes mainAttributes = manifest.getMainAttributes();
 175  0
         if( null != mainAttributes )
 176   
         {
 177  0
             final Extension extension = getExtension( "", mainAttributes );
 178  0
             if( null != extension )
 179   
             {
 180  0
                 results.add( extension );
 181   
             }
 182   
         }
 183  0
         final Map entries = manifest.getEntries();
 184  0
         final Iterator keys = entries.keySet().iterator();
 185  0
         while( keys.hasNext() )
 186   
         {
 187  0
             final String key = (String)keys.next();
 188  0
             final Attributes attributes = (Attributes)entries.get( key );
 189  0
             final Extension extension = getExtension( "", attributes );
 190  0
             if( null != extension )
 191   
             {
 192  0
                 results.add( extension );
 193   
             }
 194   
         }
 195  0
         return (Extension[])results.toArray( new Extension[ results.size() ] );
 196   
     }
 197   
     /**
 198   
      * Retrieve the set of <code>Extension</code> objects that are available
 199   
      * by the specified Manifest objects. If there are no such optional
 200   
      * packages, a zero-length list is returned.
 201   
      *
 202   
      * @param manifests the manifests to scan
 203   
      * @return the extensions
 204   
      */
 205  0
     public static Extension[] getAvailable( final Manifest[] manifests )
 206   
     {
 207  0
         final ArrayList set = new ArrayList();
 208  0
         for( int i = 0; i < manifests.length; i++ )
 209   
         {
 210  0
             final Extension[] extensions = getAvailable( manifests[ i ] );
 211  0
             for( int j = 0; j < extensions.length; j++ )
 212   
             {
 213  0
                 set.add( extensions[ j ] );
 214   
             }
 215   
         }
 216  0
         return (Extension[])set.toArray( new Extension[ set.size() ] );
 217   
     }
 218   
     /**
 219   
      * Return the set of <code>Extension</code> objects representing optional
 220   
      * packages that are required by the application contained in the JAR
 221   
      * file associated with the specified <code>Manifest</code>.  If there
 222   
      * are no such optional packages, a zero-length list is returned.
 223   
      *
 224   
      * @param manifest Manifest to be parsed
 225   
      * @return the dependencies that are specified in manifes
 226   
      */
 227  0
     public static Extension[] getRequired( final Manifest manifest )
 228   
     {
 229  0
         return getListed( manifest, EXTENSION_LIST );
 230   
     }
 231   
     /**
 232   
      * Retrieve the set of <code>Extension</code> objects that are required
 233   
      * by the specified Manifest objects. If there are no such optional
 234   
      * packages, a zero-length list is returned.
 235   
      *
 236   
      * @param manifests the manifests to scan
 237   
      * @return the extensions
 238   
      */
 239  0
     public static Extension[] getRequired( final Manifest[] manifests )
 240   
     {
 241  0
         final ArrayList set = new ArrayList();
 242  0
         for( int i = 0; i < manifests.length; i++ )
 243   
         {
 244  0
             final Extension[] extensions = getRequired( manifests[ i ] );
 245  0
             for( int j = 0; j < extensions.length; j++ )
 246   
             {
 247  0
                 set.add( extensions[ j ] );
 248   
             }
 249   
         }
 250  0
         return (Extension[])set.toArray( new Extension[ set.size() ] );
 251   
     }
 252   
     /**
 253   
      * Return the set of <code>Extension</code> objects representing "Optional
 254   
      * Packages" that the application declares they will use if present. If
 255   
      * there are no such optional packages, a zero-length list is returned.
 256   
      *
 257   
      * @param manifest Manifest to be parsed
 258   
      * @return the optional dependencies that are specified in manifest
 259   
      */
 260  0
     public static Extension[] getOptions( final Manifest manifest )
 261   
     {
 262  0
         return getListed( manifest, OPTIONAL_EXTENSION_LIST );
 263   
     }
 264   
     /**
 265   
      * Add Extension to the specified manifest Attributes.
 266   
      *
 267   
      * @param attributes the attributes of manifest to add to
 268   
      * @param extension the extension
 269   
      */
 270  0
     public static void addExtension( final Extension extension,
 271   
                                      final Attributes attributes )
 272   
     {
 273  0
         addExtension( extension, "", attributes );
 274   
     }
 275   
     /**
 276   
      * Add Extension to the specified manifest Attributes.
 277   
      * Use the specified prefix so that dependencies can added
 278   
      * with a prefix such as "java3d-" etc.
 279   
      *
 280   
      * @param attributes the attributes of manifest to add to
 281   
      * @param extension the extension
 282   
      * @param prefix the name to prefix to extension
 283   
      */
 284  0
     public static void addExtension( final Extension extension,
 285   
                                      final String prefix,
 286   
                                      final Attributes attributes )
 287   
     {
 288  0
         attributes.putValue( prefix + EXTENSION_NAME,
 289   
                              extension.getExtensionName() );
 290  0
         final String specificationVendor = extension.getSpecificationVendor();
 291  0
         if( null != specificationVendor )
 292   
         {
 293  0
             attributes.putValue( prefix + SPECIFICATION_VENDOR,
 294   
                                  specificationVendor );
 295   
         }
 296  0
         final DeweyDecimal specificationVersion = extension.getSpecificationVersion();
 297  0
         if( null != specificationVersion )
 298   
         {
 299  0
             attributes.putValue( prefix + SPECIFICATION_VERSION,
 300   
                                  specificationVersion.toString() );
 301   
         }
 302  0
         final String implementationVendorID = extension.getImplementationVendorID();
 303  0
         if( null != implementationVendorID )
 304   
         {
 305  0
             attributes.putValue( prefix + IMPLEMENTATION_VENDOR_ID,
 306   
                                  implementationVendorID );
 307   
         }
 308  0
         final String implementationVendor = extension.getImplementationVendor();
 309  0
         if( null != implementationVendor )
 310   
         {
 311  0
             attributes.putValue( prefix + IMPLEMENTATION_VENDOR,
 312   
                                  implementationVendor );
 313   
         }
 314  0
         final String implementationVersion = extension.getImplementationVersion();
 315  0
         if( null != implementationVersion )
 316   
         {
 317  0
             attributes.putValue( prefix + IMPLEMENTATION_VERSION,
 318   
                                  implementationVersion.toString() );
 319   
         }
 320  0
         final String implementationURL = extension.getImplementationURL();
 321  0
         if( null != implementationURL )
 322   
         {
 323  0
             attributes.putValue( prefix + IMPLEMENTATION_URL,
 324   
                                  implementationURL );
 325   
         }
 326   
     }
 327   
     /**
 328   
      * The constructor to create Extension object.
 329   
      * Note that every component is allowed to be specified
 330   
      * but only the extensionName is mandatory.
 331   
      *
 332   
      * @param extensionName the name of extension.
 333   
      * @param specificationVersion the specification Version of extension.
 334   
      * @param specificationVendor the specification Vendor of extension.
 335   
      * @param implementationVersion the implementation Version of extension.
 336   
      * @param implementationVendor the implementation Vendor of extension.
 337   
      * @param implementationVendorId the implementation VendorId of extension.
 338   
      * @param implementationURL the implementation URL of extension.
 339   
      */
 340  0
     public Extension( final String extensionName,
 341   
                       final String specificationVersion,
 342   
                       final String specificationVendor,
 343   
                       final String implementationVersion,
 344   
                       final String implementationVendor,
 345   
                       final String implementationVendorId,
 346   
                       final String implementationURL )
 347   
     {
 348  0
         if( null == extensionName )
 349   
         {
 350  0
             throw new NullPointerException( "extensionName" );
 351   
         }
 352  0
         m_extensionName = extensionName;
 353  0
         m_specificationVendor = specificationVendor;
 354  0
         if( null != specificationVersion )
 355   
         {
 356  0
             try
 357   
             {
 358  0
                 m_specificationVersion = new DeweyDecimal( specificationVersion );
 359   
             }
 360   
             catch( final NumberFormatException nfe )
 361   
             {
 362  0
                 final String error = "Bad specification version format '" + specificationVersion +
 363   
                     "' in '" + extensionName + "'. (Reason: " + nfe + ")";
 364  0
                 throw new IllegalArgumentException( error );
 365   
             }
 366   
         }
 367  0
         m_implementationURL = implementationURL;
 368  0
         m_implementationVendor = implementationVendor;
 369  0
         m_implementationVendorID = implementationVendorId;
 370  0
         m_implementationVersion = implementationVersion;
 371   
     }
 372   
     /**
 373   
      * Get the name of the extension.
 374   
      *
 375   
      * @return the name of the extension
 376   
      */
 377  0
     public String getExtensionName()
 378   
     {
 379  0
         return m_extensionName;
 380   
     }
 381   
     /**
 382   
      * Get the vendor of the extensions specification.
 383   
      *
 384   
      * @return the vendor of the extensions specification.
 385   
      */
 386  0
     public String getSpecificationVendor()
 387   
     {
 388  0
         return m_specificationVendor;
 389   
     }
 390   
     /**
 391   
      * Get the version of the extensions specification.
 392   
      *
 393   
      * @return the version of the extensions specification.
 394   
      */
 395  0
     public DeweyDecimal getSpecificationVersion()
 396   
     {
 397  0
         return m_specificationVersion;
 398   
     }
 399   
     /**
 400   
      * Get the url of the extensions implementation.
 401   
      *
 402   
      * @return the url of the extensions implementation.
 403   
      */
 404  0
     public String getImplementationURL()
 405   
     {
 406  0
         return m_implementationURL;
 407   
     }
 408   
     /**
 409   
      * Get the vendor of the extensions implementation.
 410   
      *
 411   
      * @return the vendor of the extensions implementation.
 412   
      */
 413  0
     public String getImplementationVendor()
 414   
     {
 415  0
         return m_implementationVendor;
 416   
     }
 417   
     /**
 418   
      * Get the vendorID of the extensions implementation.
 419   
      *
 420   
      * @return the vendorID of the extensions implementation.
 421   
      */
 422  0
     public String getImplementationVendorID()
 423   
     {
 424  0
         return m_implementationVendorID;
 425   
     }
 426   
     /**
 427   
      * Get the version of the extensions implementation.
 428   
      *
 429   
      * @return the version of the extensions implementation.
 430   
      */
 431  0
     public String getImplementationVersion()
 432   
     {
 433  0
         return m_implementationVersion;
 434   
     }
 435   
     /**
 436   
      * Return a Compatibility enum indicating the relationship of this
 437   
      * <code>Extension</code> with the specified <code>Extension</code>.
 438   
      *
 439   
      * @param required Description of the required optional package
 440   
      * @return the enum indicating the compatability (or lack thereof)
 441   
      *         of specifed extension
 442   
      */
 443  0
     public Compatability getCompatibilityWith( final Extension required )
 444   
     {
 445   
         // Extension Name must match
 446  0
         if( !m_extensionName.equals( required.getExtensionName() ) )
 447   
         {
 448  0
             return INCOMPATIBLE;
 449   
         }
 450   
         // Available specification version must be >= required
 451  0
         final DeweyDecimal specificationVersion = required.getSpecificationVersion();
 452  0
         if( null != specificationVersion )
 453   
         {
 454  0
             if( null == m_specificationVersion ||
 455   
                 !isCompatible( m_specificationVersion, specificationVersion ) )
 456   
             {
 457  0
                 return REQUIRE_SPECIFICATION_UPGRADE;
 458   
             }
 459   
         }
 460   
         // Implementation Vendor ID must match
 461  0
         final String implementationVendorId = required.getImplementationVendorID();
 462  0
         if( null != implementationVendorId )
 463   
         {
 464  0
             if( null == m_implementationVendorID ||
 465   
                 !m_implementationVendorID.equals( implementationVendorId ) )
 466   
             {
 467  0
                 return REQUIRE_VENDOR_SWITCH;
 468   
             }
 469   
         }
 470   
 
 471   
         // This available optional package satisfies the requirements
 472  0
         return COMPATIBLE;
 473   
     }
 474   
     /**
 475   
      * Return <code>true</code> if the specified <code>Extension</code>
 476   
      * (which represents an optional package required by an application)
 477   
      * is satisfied by this <code>Extension</code> (which represents an
 478   
      * optional package that is already installed.  Otherwise, return
 479   
      * <code>false</code>.
 480   
      *
 481   
      * @param required Description of the required optional package
 482   
      * @return true if the specified extension is compatible with this extension
 483   
      */
 484  0
     public boolean isCompatibleWith( final Extension required )
 485   
     {
 486  0
         return ( COMPATIBLE == getCompatibilityWith( required ) );
 487   
     }
 488   
     /**
 489   
      * Return a String representation of this object.
 490   
      *
 491   
      * @return string representation of object.
 492   
      */
 493  0
     public String toString()
 494   
     {
 495  0
         final String lineSeparator = System.getProperty( "line.separator" );
 496  0
         final String brace = ": ";
 497  0
         final StringBuffer sb = new StringBuffer( EXTENSION_NAME.toString() );
 498  0
         sb.append( brace );
 499  0
         sb.append( m_extensionName );
 500  0
         sb.append( lineSeparator );
 501  0
         if( null != m_specificationVersion )
 502   
         {
 503  0
             sb.append( SPECIFICATION_VERSION );
 504  0
             sb.append( brace );
 505  0
             sb.append( m_specificationVersion );
 506  0
             sb.append( lineSeparator );
 507   
         }
 508  0
         if( null != m_specificationVendor )
 509   
         {
 510  0
             sb.append( SPECIFICATION_VENDOR );
 511  0
             sb.append( brace );
 512  0
             sb.append( m_specificationVendor );
 513  0
             sb.append( lineSeparator );
 514   
         }
 515  0
         if( null != m_implementationVersion )
 516   
         {
 517  0
             sb.append( IMPLEMENTATION_VERSION );
 518  0
             sb.append( brace );
 519  0
             sb.append( m_implementationVersion );
 520  0
             sb.append( lineSeparator );
 521   
         }
 522  0
         if( null != m_implementationVendorID )
 523   
         {
 524  0
             sb.append( IMPLEMENTATION_VENDOR_ID );
 525  0
             sb.append( brace );
 526  0
             sb.append( m_implementationVendorID );
 527  0
             sb.append( lineSeparator );
 528   
         }
 529  0
         if( null != m_implementationVendor )
 530   
         {
 531  0
             sb.append( IMPLEMENTATION_VENDOR );
 532  0
             sb.append( brace );
 533  0
             sb.append( m_implementationVendor );
 534  0
             sb.append( lineSeparator );
 535   
         }
 536  0
         if( null != m_implementationURL )
 537   
         {
 538  0
             sb.append( IMPLEMENTATION_URL );
 539  0
             sb.append( brace );
 540  0
             sb.append( m_implementationURL );
 541  0
             sb.append( lineSeparator );
 542   
         }
 543  0
         return sb.toString();
 544   
     }
 545   
     /**
 546   
      * Return <code>true</code> if the first version number is greater than
 547   
      * or equal to the second; otherwise return <code>false</code>.
 548   
      *
 549   
      * @param first First version number (dotted decimal)
 550   
      * @param second Second version number (dotted decimal)
 551   
      */
 552  0
     private boolean isCompatible( final DeweyDecimal first, final DeweyDecimal second )
 553   
     {
 554  0
         return first.isGreaterThanOrEqual( second );
 555   
     }
 556   
     /**
 557   
      * Retrieve all the extensions listed under a particular key
 558   
      * (Usually EXTENSION_LIST or OPTIONAL_EXTENSION_LIST).
 559   
      *
 560   
      * @param manifest the manifest to extract extensions from
 561   
      * @param listKey the key used to get list (Usually
 562   
      *        EXTENSION_LIST or OPTIONAL_EXTENSION_LIST)
 563   
      * @return the list of listed extensions
 564   
      */
 565  0
     private static Extension[] getListed( final Manifest manifest,
 566   
                                           final Attributes.Name listKey )
 567   
     {
 568  0
         final ArrayList results = new ArrayList();
 569  0
         final Attributes mainAttributes = manifest.getMainAttributes();
 570  0
         if( null != mainAttributes )
 571   
         {
 572  0
             getExtension( mainAttributes, results, listKey );
 573   
         }
 574  0
         final Map entries = manifest.getEntries();
 575  0
         final Iterator keys = entries.keySet().iterator();
 576  0
         while( keys.hasNext() )
 577   
         {
 578  0
             final String key = (String)keys.next();
 579  0
             final Attributes attributes = (Attributes)entries.get( key );
 580  0
             getExtension( attributes, results, listKey );
 581   
         }
 582  0
         return (Extension[])results.toArray( new Extension[ 0 ] );
 583   
     }
 584   
     /**
 585   
      * Add required optional packages defined in the specified attributes entry, if any.
 586   
      *
 587   
      * @param attributes Attributes to be parsed
 588   
      * @param required list to add required optional packages to
 589   
      * @param listKey the key to use to lookup list, usually EXTENSION_LIST
 590   
      *    or OPTIONAL_EXTENSION_LIST
 591   
      */
 592  0
     private static void getExtension( final Attributes attributes,
 593   
                                       final ArrayList required,
 594   
                                       final Attributes.Name listKey )
 595   
     {
 596  0
         final String names = attributes.getValue( listKey );
 597  0
         if( null == names )
 598   
         {
 599  0
             return;
 600   
         }
 601  0
         final String[] extentions = split( names, " " );
 602  0
         for( int i = 0; i < extentions.length; i++ )
 603   
         {
 604  0
             final String prefix = extentions[ i ] + "-";
 605  0
             final Extension extension = getExtension( prefix, attributes );
 606  0
             if( null != extension )
 607   
             {
 608  0
                 required.add( extension );
 609   
             }
 610   
         }
 611   
     }
 612   
     /**
 613   
      * Splits the string on every token into an array of strings.
 614   
      *
 615   
      * @param string the string
 616   
      * @param onToken the token
 617   
      * @return the resultant array
 618   
      */
 619  0
     private static final String[] split( final String string, final String onToken )
 620   
     {
 621  0
         final StringTokenizer tokenizer = new StringTokenizer( string, onToken );
 622  0
         final String[] result = new String[ tokenizer.countTokens() ];
 623  0
         for( int i = 0; i < result.length; i++ )
 624   
         {
 625  0
             result[ i ] = tokenizer.nextToken();
 626   
         }
 627  0
         return result;
 628   
     }
 629   
     /**
 630   
      * Extract an Extension from Attributes.
 631   
      * Prefix indicates the prefix checked for each string.
 632   
      * Usually the prefix is <em>"&lt;extension&gt;-"</em> if looking for a
 633   
      * <b>Required</b> extension. If you are looking for an <b>Available</b> extension
 634   
      * then the prefix is <em>""</em>.
 635   
      *
 636   
      * @param prefix the prefix for each attribute name
 637   
      * @param attributes Attributes to searched
 638   
      * @return the new Extension object, or null
 639   
      */
 640  0
     private static Extension getExtension( final String prefix, final Attributes attributes )
 641   
     {
 642   
         //WARNING: We trim the values of all the attributes because
 643   
         //Some extension declarations are badly defined (ie have spaces
 644   
         //after version or vendorID)
 645  0
         final String nameKey = prefix + EXTENSION_NAME;
 646  0
         final String name = getTrimmedString( attributes.getValue( nameKey ) );
 647  0
         if( null == name )
 648   
         {
 649  0
             return null;
 650   
         }
 651  0
         final String specVendorKey = prefix + SPECIFICATION_VENDOR;
 652  0
         final String specVendor = getTrimmedString( attributes.getValue( specVendorKey ) );
 653  0
         final String specVersionKey = prefix + SPECIFICATION_VERSION;
 654  0
         final String specVersion = getTrimmedString( attributes.getValue( specVersionKey ) );
 655  0
         final String impVersionKey = prefix + IMPLEMENTATION_VERSION;
 656  0
         final String impVersion = getTrimmedString( attributes.getValue( impVersionKey ) );
 657  0
         final String impVendorKey = prefix + IMPLEMENTATION_VENDOR;
 658  0
         final String impVendor = getTrimmedString( attributes.getValue( impVendorKey ) );
 659  0
         final String impVendorIDKey = prefix + IMPLEMENTATION_VENDOR_ID;
 660  0
         final String impVendorId = getTrimmedString( attributes.getValue( impVendorIDKey ) );
 661  0
         final String impURLKey = prefix + IMPLEMENTATION_URL;
 662  0
         final String impURL = getTrimmedString( attributes.getValue( impURLKey ) );
 663  0
         return new Extension( name, specVersion, specVendor, impVersion,
 664   
                               impVendor, impVendorId, impURL );
 665   
     }
 666   
     /**
 667   
      * Trim the supplied string if the string is non-null
 668   
      *
 669   
      * @param value the string to trim or null
 670   
      * @return the trimmed string or null
 671   
      */
 672  0
     private static String getTrimmedString( final String value )
 673   
     {
 674  0
         if( null == value )
 675   
         {
 676  0
             return null;
 677   
         }
 678   
         else
 679   
         {
 680  0
             return value.trim();
 681   
         }
 682   
     }
 683   
 }
 684