diff --git a/src/main/org/apache/tools/ant/taskdefs/optional/extension/Extension.java b/src/main/org/apache/tools/ant/taskdefs/optional/extension/Extension.java
new file mode 100644
index 000000000..58d62b4d8
--- /dev/null
+++ b/src/main/org/apache/tools/ant/taskdefs/optional/extension/Extension.java
@@ -0,0 +1,777 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2002 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ * any, must include the following acknowlegement:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowlegement may appear in the software itself,
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "The Jakarta Project", "Ant", and "Apache Software
+ * Foundation" must not be used to endorse or promote products derived
+ * from this software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache"
+ * nor may "Apache" appear in their names without prior written
+ * permission of the Apache Group.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ *
Utility class that represents either an available "Optional Package" + * (formerly known as "Standard Extension") as described in the manifest + * of a JAR file, or the requirement for such an optional package.
+ * + *For more information about optional packages, see the document
+ * Optional Package Versioning in the documentation bundle for your
+ * Java2 Standard Edition package, in file
+ * guide/extensions/versioning.html.
Name object for Optional-Extension-List
+ * manifest attribute used for declaring optional dependencies on
+ * installed extensions. Note that the dependencies declared by this method
+ * are not required for the library to operate but if present will be used.
+ * It is NOT part of the official "Optional Package" specification.
+ *
+ * @see
+ * Installed extension dependency
+ */
+ public static final Attributes.Name OPTIONAL_EXTENSION_LIST = new Attributes.Name( "Optional-Extension-List" );
+
+ /**
+ * Manifest Attribute Name object for EXTENSION_NAME.
+ * @see Attributes.Name#EXTENSION_NAME
+ */
+ public static final Attributes.Name EXTENSION_NAME = Attributes.Name.EXTENSION_NAME;
+
+ /**
+ * Manifest Attribute Name object for SPECIFICATION_VERSION.
+ * @see Attributes.Name#SPECIFICATION_VERSION
+ */
+ public static final Attributes.Name SPECIFICATION_VERSION = Attributes.Name.SPECIFICATION_VERSION;
+
+ /**
+ * Manifest Attribute Name object for SPECIFICATION_VENDOR.
+ * @see Attributes.Name#SPECIFICATION_VENDOR
+ */
+ public static final Attributes.Name SPECIFICATION_VENDOR = Attributes.Name.SPECIFICATION_VENDOR;
+
+ /**
+ * Manifest Attribute Name object for IMPLEMENTATION_VERSION.
+ * @see Attributes.Name#IMPLEMENTATION_VERSION
+ */
+ public static final Attributes.Name IMPLEMENTATION_VERSION = Attributes.Name.IMPLEMENTATION_VERSION;
+
+ /**
+ * Manifest Attribute Name object for IMPLEMENTATION_VENDOR.
+ * @see Attributes.Name#IMPLEMENTATION_VENDOR
+ */
+ public static final Attributes.Name IMPLEMENTATION_VENDOR = Attributes.Name.IMPLEMENTATION_VENDOR;
+
+ /**
+ * Manifest Attribute Name object for IMPLEMENTATION_URL.
+ * @see Attributes.Name#IMPLEMENTATION_URL
+ */
+ public static final Attributes.Name IMPLEMENTATION_URL = Attributes.Name.IMPLEMENTATION_URL;
+
+ /**
+ * Manifest Attribute Name object for IMPLEMENTATION_VENDOR_ID.
+ * @see Attributes.Name#IMPLEMENTATION_VENDOR_ID
+ */
+ public static final Attributes.Name IMPLEMENTATION_VENDOR_ID = Attributes.Name.IMPLEMENTATION_VENDOR_ID;
+
+ /**
+ * Enum indicating that extension is compatible with other extension.
+ */
+ public static final Compatability COMPATIBLE =
+ new Compatability( "COMPATIBLE" );
+
+ /**
+ * Enum indicating that extension requires an upgrade
+ * of specification to be compatible with other extension.
+ */
+ public static final Compatability REQUIRE_SPECIFICATION_UPGRADE =
+ new Compatability( "REQUIRE_SPECIFICATION_UPGRADE" );
+
+ /**
+ * Enum indicating that extension requires a vendor
+ * switch to be compatible with other extension.
+ */
+ public static final Compatability REQUIRE_VENDOR_SWITCH =
+ new Compatability( "REQUIRE_VENDOR_SWITCH" );
+
+ /**
+ * Enum indicating that extension requires an upgrade
+ * of implementation to be compatible with other extension.
+ */
+ public static final Compatability REQUIRE_IMPLEMENTATION_UPGRADE =
+ new Compatability( "REQUIRE_IMPLEMENTATION_UPGRADE" );
+
+ /**
+ * Enum indicating that extension is incompatible with
+ * other extension in ways other than other enums
+ * indicate). ie For example the other extension may have
+ * a different ID.
+ */
+ public static final Compatability INCOMPATIBLE =
+ new Compatability( "INCOMPATIBLE" );
+
+ /**
+ * The name of the optional package being made available, or required.
+ */
+ private String m_extensionName;
+
+ /**
+ * The version number (dotted decimal notation) of the specification
+ * to which this optional package conforms.
+ */
+ private DeweyDecimal m_specificationVersion;
+
+ /**
+ * The name of the company or organization that originated the
+ * specification to which this optional package conforms.
+ */
+ private String m_specificationVendor;
+
+ /**
+ * The unique identifier of the company that produced the optional
+ * package contained in this JAR file.
+ */
+ private String m_implementationVendorID;
+
+ /**
+ * The name of the company or organization that produced this
+ * implementation of this optional package.
+ */
+ private String m_implementationVendor;
+
+ /**
+ * The version number (dotted decimal notation) for this implementation
+ * of the optional package.
+ */
+ private DeweyDecimal m_implementationVersion;
+
+ /**
+ * The URL from which the most recent version of this optional package
+ * can be obtained if it is not already installed.
+ */
+ private String m_implementationURL;
+
+ /**
+ * Return an array of Extension objects representing optional
+ * packages that are available in the JAR file associated with the
+ * specified Manifest. If there are no such optional
+ * packages, a zero-length array is returned.
+ *
+ * @param manifest Manifest to be parsed
+ * @return the "available" extensions in specified manifest
+ */
+ public static Extension[] getAvailable( final Manifest manifest )
+ {
+ if( null == manifest )
+ {
+ return new Extension[ 0 ];
+ }
+
+ final ArrayList results = new ArrayList();
+
+ final Attributes mainAttributes = manifest.getMainAttributes();
+ if( null != mainAttributes )
+ {
+ final Extension extension = getExtension( "", mainAttributes );
+ if( null != extension )
+ {
+ results.add( extension );
+ }
+ }
+
+ final Map entries = manifest.getEntries();
+ final Iterator keys = entries.keySet().iterator();
+ while( keys.hasNext() )
+ {
+ final String key = (String)keys.next();
+ final Attributes attributes = (Attributes)entries.get( key );
+ final Extension extension = getExtension( "", attributes );
+ if( null != extension )
+ {
+ results.add( extension );
+ }
+ }
+
+ return (Extension[])results.toArray( new Extension[ 0 ] );
+ }
+
+ /**
+ * Return the set of Extension objects representing optional
+ * packages that are required by the application contained in the JAR
+ * file associated with the specified Manifest. If there
+ * are no such optional packages, a zero-length list is returned.
+ *
+ * @param manifest Manifest to be parsed
+ * @return the dependencies that are specified in manifes
+ */
+ public static Extension[] getRequired( final Manifest manifest )
+ {
+ return getListed( manifest, EXTENSION_LIST );
+ }
+
+ /**
+ * Return the set of Extension objects representing "Optional
+ * Packages" that the application declares they will use if present. If
+ * there are no such optional packages, a zero-length list is returned.
+ *
+ * @param manifest Manifest to be parsed
+ * @return the optional dependencies that are specified in manifest
+ */
+ public static Extension[] getOptions( final Manifest manifest )
+ {
+ return getListed( manifest, OPTIONAL_EXTENSION_LIST );
+ }
+
+ /**
+ * Add Extension to the specified manifest Attributes.
+ *
+ * @param attributes the attributes of manifest to add to
+ * @param extension the extension
+ */
+ public static void addExtension( final Extension extension,
+ final Attributes attributes )
+ {
+ addExtension( extension, "", attributes );
+ }
+
+ /**
+ * Add Extension to the specified manifest Attributes.
+ * Use the specified prefix so that dependencies can added
+ * with a prefix such as "java3d-" etc.
+ *
+ * @param attributes the attributes of manifest to add to
+ * @param extension the extension
+ * @param prefix the name to prefix to extension
+ */
+ public static void addExtension( final Extension extension,
+ final String prefix,
+ final Attributes attributes )
+ {
+ attributes.putValue( prefix + EXTENSION_NAME,
+ extension.getExtensionName() );
+
+ final String specificationVendor = extension.getSpecificationVendor();
+ if( null != specificationVendor )
+ {
+ attributes.putValue( prefix + SPECIFICATION_VENDOR,
+ specificationVendor );
+ }
+
+ final DeweyDecimal specificationVersion = extension.getSpecificationVersion();
+ if( null != specificationVersion )
+ {
+ attributes.putValue( prefix + SPECIFICATION_VERSION,
+ specificationVersion.toString() );
+ }
+
+ final String implementationVendorID = extension.getImplementationVendorID();
+ if( null != implementationVendorID )
+ {
+ attributes.putValue( prefix + IMPLEMENTATION_VENDOR_ID,
+ implementationVendorID );
+ }
+
+ final String implementationVendor = extension.getImplementationVendor();
+ if( null != implementationVendor )
+ {
+ attributes.putValue( prefix + IMPLEMENTATION_VENDOR,
+ implementationVendor );
+ }
+
+ final DeweyDecimal implementationVersion = extension.getImplementationVersion();
+ if( null != implementationVersion )
+ {
+ attributes.putValue( prefix + IMPLEMENTATION_VERSION,
+ implementationVersion.toString() );
+ }
+
+ final String implementationURL = extension.getImplementationURL();
+ if( null != implementationURL )
+ {
+ attributes.putValue( prefix + IMPLEMENTATION_URL,
+ implementationURL );
+ }
+ }
+
+ /**
+ * The constructor to create Extension object.
+ * Note that every component is allowed to be specified
+ * but only the extensionName is mandatory.
+ *
+ * @param extensionName the name of extension.
+ * @param specificationVersion the specification Version of extension.
+ * @param specificationVendor the specification Vendor of extension.
+ * @param implementationVersion the implementation Version of extension.
+ * @param implementationVendor the implementation Vendor of extension.
+ * @param implementationVendorId the implementation VendorId of extension.
+ * @param implementationURL the implementation URL of extension.
+ */
+ public Extension( final String extensionName,
+ final String specificationVersion,
+ final String specificationVendor,
+ final String implementationVersion,
+ final String implementationVendor,
+ final String implementationVendorId,
+ final String implementationURL )
+ {
+ m_extensionName = extensionName;
+ m_specificationVendor = specificationVendor;
+
+ if( null != specificationVersion )
+ {
+ try
+ {
+ m_specificationVersion = new DeweyDecimal( specificationVersion );
+ }
+ catch( final NumberFormatException nfe )
+ {
+ final String error = "Bad specification version format '" + specificationVersion +
+ "' in '" + extensionName + "'. (Reason: " + nfe + ")";
+ throw new IllegalArgumentException( error );
+ }
+ }
+
+ m_implementationURL = implementationURL;
+ m_implementationVendor = implementationVendor;
+ m_implementationVendorID = implementationVendorId;
+
+ if( null != implementationVersion )
+ {
+ try
+ {
+ m_implementationVersion = new DeweyDecimal( implementationVersion );
+ }
+ catch( final NumberFormatException nfe )
+ {
+ final String error = "Bad implementation version format '" + implementationVersion +
+ "' in '" + extensionName + "'. (Reason: " + nfe + ")";
+ throw new IllegalArgumentException( error );
+ }
+ }
+
+ if( null == m_extensionName )
+ {
+ throw new NullPointerException( "extensionName property is null" );
+ }
+ }
+
+ /**
+ * Get the name of the extension.
+ *
+ * @return the name of the extension
+ */
+ public String getExtensionName()
+ {
+ return m_extensionName;
+ }
+
+ /**
+ * Get the vendor of the extensions specification.
+ *
+ * @return the vendor of the extensions specification.
+ */
+ public String getSpecificationVendor()
+ {
+ return m_specificationVendor;
+ }
+
+ /**
+ * Get the version of the extensions specification.
+ *
+ * @return the version of the extensions specification.
+ */
+ public DeweyDecimal getSpecificationVersion()
+ {
+ return m_specificationVersion;
+ }
+
+ /**
+ * Get the url of the extensions implementation.
+ *
+ * @return the url of the extensions implementation.
+ */
+ public String getImplementationURL()
+ {
+ return m_implementationURL;
+ }
+
+ /**
+ * Get the vendor of the extensions implementation.
+ *
+ * @return the vendor of the extensions implementation.
+ */
+ public String getImplementationVendor()
+ {
+ return m_implementationVendor;
+ }
+
+ /**
+ * Get the vendorID of the extensions implementation.
+ *
+ * @return the vendorID of the extensions implementation.
+ */
+ public String getImplementationVendorID()
+ {
+ return m_implementationVendorID;
+ }
+
+ /**
+ * Get the version of the extensions implementation.
+ *
+ * @return the version of the extensions implementation.
+ */
+ public DeweyDecimal getImplementationVersion()
+ {
+ return m_implementationVersion;
+ }
+
+ /**
+ * Return a Compatibility enum indicating the relationship of this
+ * Extension with the specified Extension.
+ *
+ * @param required Description of the required optional package
+ * @return the enum indicating the compatability (or lack thereof)
+ * of specifed extension
+ */
+ public Compatability getCompatibilityWith( final Extension required )
+ {
+ // Extension Name must match
+ if( !m_extensionName.equals( required.getExtensionName() ) )
+ {
+ return INCOMPATIBLE;
+ }
+
+ // Available specification version must be >= required
+ final DeweyDecimal specificationVersion = required.getSpecificationVersion();
+ if( null != specificationVersion )
+ {
+ if( null == m_specificationVersion ||
+ !isCompatible( m_specificationVersion, specificationVersion ) )
+ {
+ return REQUIRE_SPECIFICATION_UPGRADE;
+ }
+ }
+
+ // Implementation Vendor ID must match
+ final String implementationVendorId = required.getImplementationVendorID();
+ if( null != implementationVendorId )
+ {
+ if( null == m_implementationVendorID ||
+ !m_implementationVendorID.equals( implementationVendorId ) )
+ {
+ return REQUIRE_VENDOR_SWITCH;
+ }
+ }
+
+ // Implementation version must be >= required
+ final DeweyDecimal implementationVersion = required.getImplementationVersion();
+ if( null != implementationVersion )
+ {
+ if( null == m_implementationVersion ||
+ !isCompatible( m_implementationVersion, implementationVersion ) )
+ {
+ return REQUIRE_IMPLEMENTATION_UPGRADE;
+ }
+ }
+
+ // This available optional package satisfies the requirements
+ return COMPATIBLE;
+ }
+
+ /**
+ * Return true if the specified Extension
+ * (which represents an optional package required by an application)
+ * is satisfied by this Extension (which represents an
+ * optional package that is already installed. Otherwise, return
+ * false.
+ *
+ * @param required Description of the required optional package
+ * @return true if the specified extension is compatible with this extension
+ */
+ public boolean isCompatibleWith( final Extension required )
+ {
+ return ( COMPATIBLE == getCompatibilityWith( required ) );
+ }
+
+ /**
+ * Return a String representation of this object.
+ *
+ * @return string representation of object.
+ */
+ public String toString()
+ {
+ final String lineSeparator = System.getProperty( "line.separator" );
+ final String brace = ": ";
+
+ final StringBuffer sb = new StringBuffer( EXTENSION_NAME.toString() );
+ sb.append( brace );
+ sb.append( m_extensionName );
+ sb.append( lineSeparator );
+
+ if( null != m_specificationVersion )
+ {
+ sb.append( SPECIFICATION_VERSION );
+ sb.append( brace );
+ sb.append( m_specificationVersion );
+ sb.append( lineSeparator );
+ }
+
+ if( null != m_specificationVendor )
+ {
+ sb.append( SPECIFICATION_VENDOR );
+ sb.append( brace );
+ sb.append( m_specificationVendor );
+ sb.append( lineSeparator );
+ }
+
+ if( null != m_implementationVersion )
+ {
+ sb.append( IMPLEMENTATION_VERSION );
+ sb.append( brace );
+ sb.append( m_implementationVersion );
+ sb.append( lineSeparator );
+ }
+
+ if( null != m_implementationVendorID )
+ {
+ sb.append( IMPLEMENTATION_VENDOR_ID );
+ sb.append( brace );
+ sb.append( m_implementationVendorID );
+ sb.append( lineSeparator );
+ }
+
+ if( null != m_implementationVendor )
+ {
+ sb.append( IMPLEMENTATION_VENDOR );
+ sb.append( brace );
+ sb.append( m_implementationVendor );
+ sb.append( lineSeparator );
+ }
+
+ if( null != m_implementationURL )
+ {
+ sb.append( IMPLEMENTATION_URL );
+ sb.append( brace );
+ sb.append( m_implementationURL );
+ sb.append( lineSeparator );
+ }
+
+ return sb.toString();
+ }
+
+ /**
+ * Return true if the first version number is greater than
+ * or equal to the second; otherwise return false.
+ *
+ * @param first First version number (dotted decimal)
+ * @param second Second version number (dotted decimal)
+ */
+ private boolean isCompatible( final DeweyDecimal first, final DeweyDecimal second )
+ {
+ return first.isGreaterThanOrEqual( second );
+ }
+
+ /**
+ * Retrieve all the extensions listed under a particular key
+ * (Usually EXTENSION_LIST or OPTIONAL_EXTENSION_LIST).
+ *
+ * @param manifest the manifest to extract extensions from
+ * @param listKey the key used to get list (Usually
+ * EXTENSION_LIST or OPTIONAL_EXTENSION_LIST)
+ * @return the list of listed extensions
+ */
+ private static Extension[] getListed( final Manifest manifest,
+ final Attributes.Name listKey )
+ {
+ final ArrayList results = new ArrayList();
+ final Attributes mainAttributes = manifest.getMainAttributes();
+
+ if( null != mainAttributes )
+ {
+ getExtension( mainAttributes, results, listKey );
+ }
+
+ final Map entries = manifest.getEntries();
+ final Iterator keys = entries.keySet().iterator();
+ while( keys.hasNext() )
+ {
+ final String key = (String)keys.next();
+ final Attributes attributes = (Attributes)entries.get( key );
+ getExtension( attributes, results, listKey );
+ }
+
+ return (Extension[])results.toArray( new Extension[ 0 ] );
+ }
+
+ /**
+ * Add required optional packages defined in the specified attributes entry, if any.
+ *
+ * @param attributes Attributes to be parsed
+ * @param required list to add required optional packages to
+ * @param listKey the key to use to lookup list, usually EXTENSION_LIST
+ * or OPTIONAL_EXTENSION_LIST
+ */
+ private static void getExtension( final Attributes attributes,
+ final ArrayList required,
+ final Attributes.Name listKey )
+ {
+ final String names = attributes.getValue( listKey );
+ if( null == names )
+ {
+ return;
+ }
+
+ final String[] extentions = split( names, " " );
+ for( int i = 0; i < extentions.length; i++ )
+ {
+ final String prefix = extentions[ i ] + "-";
+ final Extension extension = getExtension( prefix, attributes );
+
+ if( null != extension )
+ {
+ required.add( extension );
+ }
+ }
+ }
+
+ /**
+ * Splits the string on every token into an array of strings.
+ *
+ * @param string the string
+ * @param onToken the token
+ * @return the resultant array
+ */
+ private static final String[] split( final String string, final String onToken )
+ {
+ final StringTokenizer tokenizer = new StringTokenizer( string, onToken );
+ final String[] result = new String[ tokenizer.countTokens() ];
+
+ for( int i = 0; i < result.length; i++ )
+ {
+ result[ i ] = tokenizer.nextToken();
+ }
+
+ return result;
+ }
+
+ /**
+ * Extract an Extension from Attributes.
+ * Prefix indicates the prefix checked for each string.
+ * Usually the prefix is "<extension>-" if looking for a
+ * Required extension. If you are looking for an Available extension
+ * then the prefix is "".
+ *
+ * @param prefix the prefix for each attribute name
+ * @param attributes Attributes to searched
+ * @return the new Extension object, or null
+ */
+ private static Extension getExtension( final String prefix, final Attributes attributes )
+ {
+ //WARNING: We trim the values of all the attributes because
+ //Some extension declarations are badly defined (ie have spaces
+ //after version or vendorID)
+ final String nameKey = prefix + EXTENSION_NAME;
+ final String name = getTrimmedString( attributes.getValue( nameKey ) );
+ if( null == name )
+ {
+ return null;
+ }
+
+ final String specVendorKey = prefix + SPECIFICATION_VENDOR;
+ final String specVendor = getTrimmedString( attributes.getValue( specVendorKey ) );
+ final String specVersionKey = prefix + SPECIFICATION_VERSION;
+ final String specVersion = getTrimmedString( attributes.getValue( specVersionKey ) );
+
+ final String impVersionKey = prefix + IMPLEMENTATION_VERSION;
+ final String impVersion = getTrimmedString( attributes.getValue( impVersionKey ) );
+ final String impVendorKey = prefix + IMPLEMENTATION_VENDOR;
+ final String impVendor = getTrimmedString( attributes.getValue( impVendorKey ) );
+ final String impVendorIDKey = prefix + IMPLEMENTATION_VENDOR_ID;
+ final String impVendorId = getTrimmedString( attributes.getValue( impVendorIDKey ) );
+ final String impURLKey = prefix + IMPLEMENTATION_URL;
+ final String impURL = getTrimmedString( attributes.getValue( impURLKey ) );
+
+ return new Extension( name, specVersion, specVendor, impVersion,
+ impVendor, impVendorId, impURL );
+ }
+
+ /**
+ * Trim the supplied string if the string is non-null
+ *
+ * @param value the string to trim or null
+ * @return the trimmed string or null
+ */
+ private static String getTrimmedString( final String value )
+ {
+ if( null == value )
+ {
+ return null;
+ }
+ else
+ {
+ return value.trim();
+ }
+ }
+}