You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@avalon.apache.org by do...@apache.org on 2003/04/30 12:03:54 UTC

cvs commit: avalon-phoenix/src/java/org/apache/avalon/phoenix/components/extensions/pkgmgr/impl DefaultExtensionManager.java DelegatingExtensionManager.java NoopExtensionManager.java OptionalPackageComparator.java

donaldp     2003/04/30 03:03:53

  Added:       src/java/org/apache/avalon/phoenix/components/extensions/pkgmgr
                        ExtensionManager.java OptionalPackage.java
                        PackageManager.java
                        UnsatisfiedExtensionException.java
               src/java/org/apache/avalon/phoenix/components/extensions/pkgmgr/impl
                        DefaultExtensionManager.java
                        DelegatingExtensionManager.java
                        NoopExtensionManager.java
                        OptionalPackageComparator.java
  Log:
  Import excalibur-extension PackageManager stuff in prep for decoupling
  
  Revision  Changes    Path
  1.1                  avalon-phoenix/src/java/org/apache/avalon/phoenix/components/extensions/pkgmgr/ExtensionManager.java
  
  Index: ExtensionManager.java
  ===================================================================
  /*
  
   ============================================================================
                     The Apache Software License, Version 1.1
   ============================================================================
  
   Copyright (C) 1997-2003 The Apache Software Foundation. All rights reserved.
  
   Redistribution and use in source and binary forms, with or without modifica-
   tion, 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  acknowledgment:  "This product includes  software
      developed  by the  Apache Software Foundation  (http://www.apache.org/)."
      Alternately, this  acknowledgment may  appear in the software itself,  if
      and wherever such third-party acknowledgments normally appear.
  
   4. The names "Avalon", "Phoenix" 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 name,  without prior written permission  of the
      Apache Software Foundation.
  
   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 (INCLU-
   DING, 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 <http://www.apache.org/>.
  
  */
  package org.apache.avalon.phoenix.components.extensions.pkgmgr;
  
  import org.apache.avalon.excalibur.extension.Extension;
  
  /**
   * <p>Interface used to store a collection of "Optional Packages"
   * (formerly known as "Standard Extensions"). It is assumed that each
   * "Optional Package" is represented by a single file on the file system.</p>
   *
   * <p>This repository is responsible for storing the local repository of
   * packages. The method used to locate packages on local filesystem
   * and install packages is not specified.</p>
   *
   * <p>For more information about optional packages, see the document
   * <em>Optional Package Versioning</em> in the documentation bundle for your
   * Java2 Standard Edition package, in file
   * <code>guide/extensions/versioning.html</code></p>.
   *
   * @author <a href="mailto:peter at apache.org">Peter Donald</a>
   * @version $Revision: 1.1 $ $Date: 2003/04/30 10:03:52 $
   */
  public interface ExtensionManager
  {
      String ROLE = ExtensionManager.class.getName();
  
      /**
       * Return all the {@link OptionalPackage}s that satisfy specified
       * {@link Extension}. The array must be sorted with the packages that
       * "best" satisfy the Extension earlier in the array. Note that the
       * definition of "best" is implementation dependent.
       *
       * @param extension Description of the extension that needs to be provided by
       *                  optional packages
       * @return an array of optional packages that satisfy extension and
       *         the extensions dependencies
       * @see OptionalPackage
       * @see Extension
       */
      OptionalPackage[] getOptionalPackages( Extension extension );
  }
  
  
  
  1.1                  avalon-phoenix/src/java/org/apache/avalon/phoenix/components/extensions/pkgmgr/OptionalPackage.java
  
  Index: OptionalPackage.java
  ===================================================================
  /*
  
   ============================================================================
                     The Apache Software License, Version 1.1
   ============================================================================
  
   Copyright (C) 1997-2003 The Apache Software Foundation. All rights reserved.
  
   Redistribution and use in source and binary forms, with or without modifica-
   tion, 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  acknowledgment:  "This product includes  software
      developed  by the  Apache Software Foundation  (http://www.apache.org/)."
      Alternately, this  acknowledgment may  appear in the software itself,  if
      and wherever such third-party acknowledgments normally appear.
  
   4. The names "Avalon", "Phoenix" 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 name,  without prior written permission  of the
      Apache Software Foundation.
  
   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 (INCLU-
   DING, 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 <http://www.apache.org/>.
  
  */
  package org.apache.avalon.phoenix.components.extensions.pkgmgr;
  
  import java.io.File;
  import org.apache.avalon.excalibur.extension.Extension;
  
  /**
   * This contains the required meta-data for an "Optional Package"
   * (formerly known as "Standard Extension") as described in the manifest
   * of a JAR file.
   *
   * @author <a href="mailto:peter at apache.org">Peter Donald</a>
   */
  public final class OptionalPackage
  {
      private final File m_file;
      private final Extension[] m_available;
      private final Extension[] m_required;
  
      /**
       * Convert a list of OptionalPackages into a list of Files.
       *
       * @param packages the list of packages
       * @return the list of files
       */
      public static final File[] toFiles( final OptionalPackage[] packages )
      {
          final File[] results = new File[ packages.length ];
  
          for( int i = 0; i < packages.length; i++ )
          {
              results[ i ] = packages[ i ].getFile();
          }
  
          return results;
      }
  
      /**
       * Constructor for OptionalPackage.
       * No parameter is allowed to be null.
       *
       * @param file absolute location of file
       * @param available the list of Extensions Optional Package provides
       * @param required the list of Extensions Optional Package requires
       */
      public OptionalPackage( final File file,
                              final Extension[] available,
                              final Extension[] required )
      {
          if( null == file )
          {
              throw new NullPointerException( "file" );
          }
  
          if( null == available )
          {
              throw new NullPointerException( "available" );
          }
  
          if( null == required )
          {
              throw new NullPointerException( "required" );
          }
  
          m_file = file;
          m_available = available;
          m_required = required;
      }
  
      /**
       * Return <code>File</code> object in which OptionalPackage
       * is contained.
       *
       * @return the file object for OptionalPackage
       */
      public File getFile()
      {
          return m_file;
      }
  
      /**
       * Return <code>Extension</code>s which OptionalPackage
       * requires to operate.
       *
       * @return the extensions required by OptionalPackage
       */
      public Extension[] getRequiredExtensions()
      {
          return m_required;
      }
  
      /**
       * Return <code>Extension</code>s which OptionalPackage
       * makes available.
       *
       * @return the extensions made available by OptionalPackage
       */
      public Extension[] getAvailableExtensions()
      {
          return m_available;
      }
  
      /**
       * Return <code>true</code> if any of the available <code>Extension</code>s
       * are compatible with specified extension. Otherwise return <code>false</code>.
       *
       * @param extension the extension
       * @return true if compatible, false otherwise
       */
      public boolean isCompatible( final Extension extension )
      {
          for( int i = 0; i < m_available.length; i++ )
          {
              if( m_available[ i ].isCompatibleWith( extension ) )
              {
                  return true;
              }
          }
  
          return false;
      }
  
      /**
       * Return a String representation of this object.
       *
       * @return the string representation of object
       */
      public String toString()
      {
          final StringBuffer sb = new StringBuffer( "OptionalPackage[" );
          sb.append( m_file );
  
          sb.append( ", Available[" );
          for( int i = 0; i < m_available.length; i++ )
          {
              if( 0 != i )
              {
                  sb.append( " " );
              }
              sb.append( m_available[ i ].getExtensionName() );
          }
  
          sb.append( "], Required[" );
          for( int i = 0; i < m_required.length; i++ )
          {
              if( 0 != i )
              {
                  sb.append( " " );
              }
              sb.append( m_required[ i ].getExtensionName() );
          }
  
          sb.append( "] ]" );
  
          return sb.toString();
      }
  }
  
  
  
  1.1                  avalon-phoenix/src/java/org/apache/avalon/phoenix/components/extensions/pkgmgr/PackageManager.java
  
  Index: PackageManager.java
  ===================================================================
  /*
  
   ============================================================================
                     The Apache Software License, Version 1.1
   ============================================================================
  
   Copyright (C) 1997-2003 The Apache Software Foundation. All rights reserved.
  
   Redistribution and use in source and binary forms, with or without modifica-
   tion, 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  acknowledgment:  "This product includes  software
      developed  by the  Apache Software Foundation  (http://www.apache.org/)."
      Alternately, this  acknowledgment may  appear in the software itself,  if
      and wherever such third-party acknowledgments normally appear.
  
   4. The names "Avalon", "Phoenix" 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 name,  without prior written permission  of the
      Apache Software Foundation.
  
   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 (INCLU-
   DING, 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 <http://www.apache.org/>.
  
  */
  package org.apache.avalon.phoenix.components.extensions.pkgmgr;
  
  import java.util.ArrayList;
  import java.util.List;
  import org.apache.avalon.excalibur.extension.Extension;
  
  /**
   * Basic Implementation Of PackageManager Interface used to manage
   * "Optional Packages" (formerly known as "Standard Extensions").
   * The "Optional Packages" are stored on file system in a number of
   * directories.
   *
   * @author <a href="mailto:peter at apache.org">Peter Donald</a>
   * @version $Revision: 1.1 $ $Date: 2003/04/30 10:03:52 $
   * @see ExtensionManager
   * @todo Determine an appropriate interface to this service and
   *       an appropriate mechanism via which to do searching and
   *       expansion of a package set. At that point separate out
   *       implementation and interface for mechanism.
   */
  public class PackageManager
  {
      ///Ordered list of repositories to search in
      private ExtensionManager m_repository;
  
      /**
       * Construct a PackageManager for a repositories.
       *
       * @param repository the repository to use in PackageManager
       */
      public PackageManager( final ExtensionManager repository )
      {
          if( null == repository )
          {
              throw new NullPointerException( "repository" );
          }
  
          m_repository = repository;
      }
  
      /**
       * Return the {@link OptionalPackage} that provides specified
       * {@link Extension}. If the specified {@link Extension}
       * can not be found then <code>null</code> is returned. If there is
       * multiple implementations that satisfy {@link Extension},
       * then an {@link OptionalPackage} returned is based on the
       * following heristic;
       *
       * <p>Return the first Optional Package. (This heuristic will
       * be replaced in time).</p>
       *
       * @param extension Description of the extension that needs to be provided by
       *                  optional package
       * @return an array of optional packages that satisfy extension and
       *         the extensions dependencies
       * @see OptionalPackage
       * @see Extension
       */
      public OptionalPackage getOptionalPackage( final Extension extension )
      {
          final OptionalPackage[] packages = m_repository.getOptionalPackages( extension );
          if( null == packages || 0 == packages.length )
          {
              return null;
          }
  
          //The best candidate is always returned first so we
          //can just return it.
          return packages[ 0 ];
      }
  
      /**
       * Build a list of dependencies based on specified {@link Extension}s.
       * Each specified {@link Extension} is expected to be a required extension
       * of another "Optional Package".
       *
       * <p>If the required {@link Extension} can not be found locally then
       * an UnsatisfiedPackageException is thrown. if an {@link OptionalPackage}
       * is found locally that satisfies specified required {@link Extension}
       * then it is returned in the array of OptionalPackages. scanDependencies() is then recursively
       * called on all of the candidates required extensions.</p>
       *
       * @param required the array of required Extensions.
       * @param available the array of Extensions already available to caller.
       * @return the list of OptionalPackages that satisfy required Extensions
       * @throws UnsatisfiedExtensionException if extensions could not be satisified
       * @see #scanDependencies
       */
      public OptionalPackage[] scanDependencies( final Extension required,
                                                 final Extension[] available )
          throws UnsatisfiedExtensionException
      {
          return scanDependencies( new Extension[]{required}, available );
      }
  
      /**
       * Build a list of dependencies based on specified {@link Extension}.
       * The specified {@link Extension} is expected to be a required extension
       * of another "Optional Package".
       *
       * <p>If the required {@link Extension} can not be found locally then
       * an UnsatisfiedPackageException is thrown. if an {@link OptionalPackage}
       * is found locally that satisfies specified required {@link Extension}
       * then it is returned in the array of OptionalPackages. scanDependencies() is then recursively
       * called on all of the candidates required extensions.</p>
       *
       * @param required the array of required Extensions.
       * @param available the array of Extensions already available to caller.
       * @return the list of OptionalPackages that satisfy required Extensions
       * @throws UnsatisfiedExtensionException if extensions could not be satisified
       * @see #scanDependencies
       */
      public OptionalPackage[] scanDependencies( final Extension[] required,
                                                 final Extension[] available )
          throws UnsatisfiedExtensionException
      {
          final ArrayList dependencies = new ArrayList();
          final ArrayList unsatisfied = new ArrayList();
  
          scanDependencies( required, available, dependencies, unsatisfied );
  
          if( 0 != unsatisfied.size() )
          {
              final Extension extension = (Extension)unsatisfied.get( 0 );
              throw new UnsatisfiedExtensionException( extension );
          }
  
          return (OptionalPackage[])dependencies.toArray( new OptionalPackage[ 0 ] );
      }
  
      /**
       * Build a list of dependencies based on specified {@link Extension}s.
       * Each specified {@link Extension} is expected to be a required extension
       * of another "Optional Package".
       *
       * <p>If the required {@link Extension} can not be found locally then
       * it is placed in list of unsatisfied Extensions. If a candidate {@link Extension}
       * is found locally that satisfies specified required {@link Extension}
       * then it is added to list of dependencies. scanDependencies() is then recursively
       * called on all of the candidates required extensions.</p>
       *
       * @param required the array of required Extensions.
       * @param available the array of Extensions already available to caller.
       * @param dependencies the list of dependencies.
       * @param unsatisfied the list of unsatisfied (ie non-local) dependencies.
       * @see #scanDependencies
       */
      public void scanDependencies( final Extension[] required,
                                    final Extension[] available,
                                    final List dependencies,
                                    final List unsatisfied )
      {
          for( int i = 0; i < required.length; i++ )
          {
              scanDependencies( required[ i ], available, dependencies, unsatisfied );
          }
      }
  
      /**
       * Build a list of dependencies based on specified {@link Extension}.
       * The specified {@link Extension} is expected to be a required extension
       * of another "Optional Package".
       *
       * <p>If the required {@link Extension} can not be found locally then
       * it is placed in list of unsatisfied Extensions. If a candidate {@link OptionalPackage}
       * is found locally that satisfies specified required {@link Extension}
       * then it is added to list of dependencies. scanDependencies() is then recursively
       * called on all of the candidates required extensions.</p>
       *
       * @param required the required Extension.
       * @param available the array of Extensions already available to caller.
       * @param dependencies the list of OptionalPackages required to satisfy extension.
       * @param unsatisfied the list of unsatisfied (ie non-local) dependencies.
       * @see #scanDependencies
       */
      public void scanDependencies( final Extension required,
                                    final Extension[] available,
                                    final List dependencies,
                                    final List unsatisfied )
      {
          //Check to see if extension is satisifed by the
          //list of available extensions passed in
          for( int i = 0; i < available.length; i++ )
          {
              final Extension other = available[ i ];
              if( other.isCompatibleWith( required ) )
              {
                  return;
              }
          }
  
          //Check to see if extension is satisifed by one
          //of the extensions already found
          final int size = dependencies.size();
          for( int i = 0; i < size; i++ )
          {
              final OptionalPackage optionalPackage = (OptionalPackage)dependencies.get( i );
              if( optionalPackage.isCompatible( required ) )
              {
                  return;
              }
          }
  
          final OptionalPackage optionalPackage = getOptionalPackage( required );
          if( null == optionalPackage )
          {
              if( !unsatisfied.contains( required ) )
              {
                  unsatisfied.add( required );
              }
          }
          else
          {
              if( !dependencies.contains( optionalPackage ) )
              {
                  dependencies.add( optionalPackage );
              }
  
              scanDependencies( optionalPackage.getRequiredExtensions(),
                                available,
                                dependencies,
                                unsatisfied );
          }
      }
  }
  
  
  
  1.1                  avalon-phoenix/src/java/org/apache/avalon/phoenix/components/extensions/pkgmgr/UnsatisfiedExtensionException.java
  
  Index: UnsatisfiedExtensionException.java
  ===================================================================
  /*
  
   ============================================================================
                     The Apache Software License, Version 1.1
   ============================================================================
  
   Copyright (C) 1997-2003 The Apache Software Foundation. All rights reserved.
  
   Redistribution and use in source and binary forms, with or without modifica-
   tion, 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  acknowledgment:  "This product includes  software
      developed  by the  Apache Software Foundation  (http://www.apache.org/)."
      Alternately, this  acknowledgment may  appear in the software itself,  if
      and wherever such third-party acknowledgments normally appear.
  
   4. The names "Avalon", "Phoenix" 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 name,  without prior written permission  of the
      Apache Software Foundation.
  
   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 (INCLU-
   DING, 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 <http://www.apache.org/>.
  
  */
  package org.apache.avalon.phoenix.components.extensions.pkgmgr;
  
  import org.apache.avalon.excalibur.extension.Extension;
  
  /**
   * Exception indicating an extension was not found in Package Repository.
   *
   * @author <a href="mailto:peter at apache.org">Peter Donald</a>
   * @version $Revision: 1.1 $ $Date: 2003/04/30 10:03:52 $
   * @see Extension
   */
  public class UnsatisfiedExtensionException
      extends Exception
  {
      /**
       * The unsatisfied Extension.
       */
      private final Extension m_extension;
  
      /**
       * Construct the <code>UnsatisfiedPackageException</code>
       * for specified {@link Extension}.
       *
       * @param extension the extension that caused exception
       */
      public UnsatisfiedExtensionException( final Extension extension )
      {
          if( null == extension )
          {
              throw new NullPointerException( "extension" );
          }
  
          m_extension = extension;
      }
  
      /**
       * Return the unsatisfied {@link Extension} that
       * caused this exception tho be thrown.
       *
       * @return the unsatisfied Extension
       */
      public Extension getUnsatisfiedExtension()
      {
          return m_extension;
      }
  }
  
  
  
  1.1                  avalon-phoenix/src/java/org/apache/avalon/phoenix/components/extensions/pkgmgr/impl/DefaultExtensionManager.java
  
  Index: DefaultExtensionManager.java
  ===================================================================
  /*
  
   ============================================================================
                     The Apache Software License, Version 1.1
   ============================================================================
  
   Copyright (C) 1997-2003 The Apache Software Foundation. All rights reserved.
  
   Redistribution and use in source and binary forms, with or without modifica-
   tion, 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  acknowledgment:  "This product includes  software
      developed  by the  Apache Software Foundation  (http://www.apache.org/)."
      Alternately, this  acknowledgment may  appear in the software itself,  if
      and wherever such third-party acknowledgments normally appear.
  
   4. The names "Avalon", "Phoenix" 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 name,  without prior written permission  of the
      Apache Software Foundation.
  
   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 (INCLU-
   DING, 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 <http://www.apache.org/>.
  
  */
  package org.apache.avalon.phoenix.components.extensions.pkgmgr.impl;
  
  import java.io.File;
  import java.io.IOException;
  import java.util.ArrayList;
  import java.util.Collections;
  import java.util.HashMap;
  import java.util.Iterator;
  import java.util.Map;
  import java.util.StringTokenizer;
  import java.util.jar.JarFile;
  import java.util.jar.Manifest;
  import org.apache.avalon.excalibur.extension.Extension;
  import org.apache.avalon.phoenix.components.extensions.pkgmgr.ExtensionManager;
  import org.apache.avalon.phoenix.components.extensions.pkgmgr.OptionalPackage;
  
  /**
   * <p>Interface used to contain "Optional Packages" (formerly known as
   * "Standard Extensions"). It is assumed that each "Optional Package" is
   * represented by a single file on the file system. This Repository searches
   * a path to find the Optional Packages.</p>
   *
   * @author <a href="mailto:peter at apache.org">Peter Donald</a>
   * @version $Revision: 1.1 $ $Date: 2003/04/30 10:03:52 $
   * @see OptionalPackage
   * @see ExtensionManager
   */
  public class DefaultExtensionManager
      implements ExtensionManager
  {
      private static final boolean DEBUG = false;
  
      /**
       * separator used to separate path elements in a string.
       */
      private static final String SEPARATOR = "|";
  
      /**
       * Map between files and {@link OptionalPackage} objects.
       */
      private final Map m_packages = new HashMap();
  
      /**
       * The set of directories in which to look for Optional Packages
       */
      private File[] m_path;
  
      /**
       * Flag set when it is necessary to scan paths to
       * build "Optional Package" list
       */
      private boolean m_needToScan;
  
      /**
       * Construct a package repository with no path specified.
       */
      public DefaultExtensionManager()
      {
          this( new File[ 0 ] );
      }
  
      /**
       * Construct a package repository with path.
       *
       * @param path The set of directories in which to look for Optional Packages
       */
      public DefaultExtensionManager( final File[] path )
      {
          setPath( path );
      }
  
      /**
       * Return an array of path elements where each
       * element in array represents a directory
       * in which the ExtensionManager will look
       * for Extensions.
       *
       * @return the list of paths to search in
       */
      public File[] getPaths()
      {
          return m_path;
      }
  
      /**
       * Return all the {@link OptionalPackage}s that satisfy specified
       * {@link Extension}. It is expected that this {@link Extension}
       * object will be one retrieved via getLocalExtension() method. If the
       * specified {@link Extension} is not local then <code>null</code>
       * is returned.
       *
       * @param extension the extension to search for
       * @return an array of optional packages that satisfy the extension
       *         (and the extensions dependencies)
       */
      public synchronized OptionalPackage[] getOptionalPackages( final Extension extension )
      {
          if( m_needToScan )
          {
              scanPath();
          }
  
          final ArrayList results = new ArrayList();
          final ArrayList candidates = (ArrayList)m_packages.get( extension.getExtensionName() );
          if( null != candidates )
          {
              final int size = candidates.size();
              for( int i = 0; i < size; i++ )
              {
                  final OptionalPackage optionalPackage = (OptionalPackage)candidates.get( i );
                  final Extension[] extensions = optionalPackage.getAvailableExtensions();
  
                  for( int j = 0; j < extensions.length; j++ )
                  {
                      if( extensions[ j ].isCompatibleWith( extension ) )
                      {
                          results.add( optionalPackage );
                      }
                  }
              }
          }
  
          final OptionalPackageComparator comparator =
              new OptionalPackageComparator( extension.getExtensionName() );
          Collections.sort( results, comparator );
          return (OptionalPackage[])results.toArray( new OptionalPackage[ 0 ] );
      }
  
      /**
       * Return all the OptionalPackages stored in ExtensionManager.
       *
       * @return all the OptionalPackages stored in ExtensionManager.
       */
      protected synchronized OptionalPackage[] getAllOptionalPackages()
      {
          //This is woefully inefficient - should rewrite it somehow
          final ArrayList packages = new ArrayList();
          final Iterator iterator = m_packages.values().iterator();
          while( iterator.hasNext() )
          {
              final ArrayList list = (ArrayList)iterator.next();
              final int size = list.size();
              for( int i = 0; i < size; i++ )
              {
                  final OptionalPackage optionalPackage = (OptionalPackage)list.get( i );
                  if( !packages.contains( optionalPackage ) )
                  {
                      packages.add( optionalPackage );
                  }
              }
          }
  
          return (OptionalPackage[])packages.toArray( new OptionalPackage[ packages.size() ] );
      }
  
      /**
       * Add path elements to repository search path
       *
       * @param pathElements the path elements to add to repository search path
       */
      protected void addPathElements( final String[] pathElements )
      {
          final File[] path = toFiles( pathElements );
          addPathElements( path );
      }
  
      /**
       * Add path elements to repository search path
       *
       * @param path the path elements to add to repository search path
       */
      protected synchronized void addPathElements( final File[] path )
      {
          validatePath( path );
          final File[] files = resolvePath( path );
          m_path = mergePaths( files );
          m_needToScan = true;
      }
  
      /**
       * Add path elements to repository search path.
       * Note that each path element is separated by a '|' character.
       *
       * @param pathString the path elements to add to repository search path
       */
      protected void addPathElements( final String pathString )
      {
          final String[] pathElements = split( pathString, SEPARATOR );
          addPathElements( pathElements );
      }
  
      /**
       * Set the path for the Repository.
       * Note thart each path element is separated by a '|' character.
       *
       * @param pathString the list of directories in which to search
       */
      protected synchronized void setPath( final String pathString )
      {
          final String[] pathElements = split( pathString, SEPARATOR );
          setPath( pathElements );
      }
  
      /**
       * Set the path for the Repository.
       *
       * @param pathElements the list of directories in which to search
       */
      protected synchronized void setPath( final String[] pathElements )
      {
          final File[] path = toFiles( pathElements );
          setPath( path );
      }
  
      /**
       * Set the path for the Repository.
       *
       * @param path the list of directories in which to search
       */
      protected synchronized void setPath( final File[] path )
      {
          validatePath( path );
          m_path = resolvePath( path );
          m_needToScan = true;
      }
  
      /**
       * Scan the path for this repository and reload all
       * the "Optional Packages" found in the path.
       * All of the old Extensions/Optional Packages will
       * be removed.
       */
      protected final synchronized void scanPath()
      {
          clearCache();
  
          for( int i = 0; i < m_path.length; i++ )
          {
              scanDirectory( m_path[ i ] );
          }
      }
  
      /**
       * Utility method to scan a directory for
       * all jar fi;les in directory and add them as
       * OptionalPackages.
       *
       * @param directory the directory to scan
       */
      private synchronized void scanDirectory( final File directory )
      {
          final File[] files = directory.listFiles();
          for( int i = 0; i < files.length; i++ )
          {
              final File file = files[ i ];
              final String name = file.getName();
  
              if( !name.endsWith( ".jar" ) )
              {
                  final String message =
                      "Skipping " + file + " as it does not end with '.jar'";
                  debug( message );
                  continue;
              }
  
              if( !file.isFile() )
              {
                  final String message =
                      "Skipping " + file + " as it is not a file.";
                  debug( message );
                  continue;
              }
  
              if( !file.canRead() )
              {
                  final String message =
                      "Skipping " + file + " as it is not readable.";
                  debug( message );
                  continue;
              }
  
              try
              {
                  final OptionalPackage optionalPackage = getOptionalPackage( file );
                  cacheOptionalPackage( optionalPackage );
              }
              catch( final IOException ioe )
              {
                  final String message =
                      "Skipping " + file + " as it could not be loaded " +
                      "due to " + ioe;
                  debug( message );
              }
          }
      }
  
      /**
       * Clear internal cache of optional packages.
       */
      protected final synchronized void clearCache()
      {
          m_packages.clear();
          m_needToScan = true;
      }
  
      /**
       * Add OptionalPackage to internal cache of Optional Packages.
       * Note that this method is only protected so that unit tests can sub-class
       * and add entries to PackageRepository by calling this method.
       *
       * @param optionalPackage the OptionalPackage to be added to repository
       */
      protected final synchronized void cacheOptionalPackage( final OptionalPackage optionalPackage )
      {
          m_needToScan = false;
  
          // added to avoid out of bounds exception
          if( optionalPackage.getAvailableExtensions().length == 0 )
          {
              return;
          }
  
          final Extension extension = optionalPackage.getAvailableExtensions()[ 0 ];
          ArrayList candidates = (ArrayList)m_packages.get( extension.getExtensionName() );
          if( null == candidates )
          {
              candidates = new ArrayList();
              m_packages.put( extension.getExtensionName(), candidates );
          }
  
          candidates.add( optionalPackage );
      }
  
      /**
       * Construct an OptionalPackage out of the specified jar archive.
       *
       * @param archive the file object for Jar archive
       * @return the OptionalPackage constructed
       * @throws IOException if an error occurs
       */
      private OptionalPackage getOptionalPackage( final File archive )
          throws IOException
      {
          final File file = archive.getCanonicalFile();
          final JarFile jarFile = new JarFile( file );
          try
          {
              final Manifest manifest = jarFile.getManifest();
              if( null == manifest )
              {
                  return null;
              }
              final Extension[] available = Extension.getAvailable( manifest );
              final Extension[] required = Extension.getRequired( manifest );
  
              return new OptionalPackage( file, available, required );
          }
          finally
          {
              jarFile.close();
          }
      }
  
      /**
       * Output a debug message for repository.
       *
       * @param message the debug message
       */
      protected void debug( final String message )
      {
          if( DEBUG )
          {
              System.out.println( message );
          }
      }
  
      /**
       * Get Canonical or failing that the absolute file
       * for every specified file.
       *
       * @param path the files that make up path
       * @return the resolved path
       */
      private File[] resolvePath( final File[] path )
      {
          final File[] resultPath = new File[ path.length ];
          for( int i = 0; i < path.length; i++ )
          {
              resultPath[ i ] = resolveFile( path[ i ] );
          }
          return resultPath;
      }
  
      /**
       * Get Canonical or failing that the absolute file
       * for specified file.
       *
       * @param file the file
       * @return the resolved file
       */
      private File resolveFile( final File file )
      {
          try
          {
              return file.getCanonicalFile();
          }
          catch( IOException e )
          {
              return file.getAbsoluteFile();
          }
      }
  
      /**
       * Validate each element in path to make sure they are valid.
       *
       * @param path the path
       */
      private void validatePath( final File[] path )
      {
          if( null == path )
          {
              throw new NullPointerException( "path" );
          }
  
          for( int i = 0; i < path.length; i++ )
          {
              validatePathElement( path[ i ] );
          }
      }
  
      /**
       * Make sure specified path element is valid.
       * The elements should exist and should be a directory.
       *
       * @param file the path element
       */
      private void validatePathElement( final File file )
      {
          if( !file.exists() || !file.isDirectory() )
          {
              final String message = "path element " + file +
                  " must exist and must be a directory";
              throw new IllegalArgumentException( message );
          }
      }
  
      /**
       * Merge the specified file list with existing path.
       *
       * @param files the files to merge
       * @return the merged path
       */
      private File[] mergePaths( final File[] files )
      {
          final File[] resultPath =
              new File[ m_path.length + files.length ];
          System.arraycopy( m_path, 0, resultPath, 0, m_path.length );
          System.arraycopy( files, m_path.length, resultPath, 0, files.length );
          return resultPath;
      }
  
      /**
       * Convert set of string elements into file objects
       *
       * @param pathElements the string path elements
       * @return the file array representing each element
       */
      private File[] toFiles( final String[] pathElements )
      {
          final File[] path = new File[ pathElements.length ];
          for( int i = 0; i < path.length; i++ )
          {
              path[ i ] = new File( pathElements[ i ] );
          }
          return path;
      }
  
      /**
       * 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 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;
      }
  }
  
  
  
  1.1                  avalon-phoenix/src/java/org/apache/avalon/phoenix/components/extensions/pkgmgr/impl/DelegatingExtensionManager.java
  
  Index: DelegatingExtensionManager.java
  ===================================================================
  /*
  
   ============================================================================
                     The Apache Software License, Version 1.1
   ============================================================================
  
   Copyright (C) 1997-2003 The Apache Software Foundation. All rights reserved.
  
   Redistribution and use in source and binary forms, with or without modifica-
   tion, 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  acknowledgment:  "This product includes  software
      developed  by the  Apache Software Foundation  (http://www.apache.org/)."
      Alternately, this  acknowledgment may  appear in the software itself,  if
      and wherever such third-party acknowledgments normally appear.
  
   4. The names "Avalon", "Phoenix" 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 name,  without prior written permission  of the
      Apache Software Foundation.
  
   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 (INCLU-
   DING, 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 <http://www.apache.org/>.
  
  */
  package org.apache.avalon.phoenix.components.extensions.pkgmgr.impl;
  
  import java.util.ArrayList;
  import java.util.Collections;
  import org.apache.avalon.excalibur.extension.Extension;
  import org.apache.avalon.phoenix.components.extensions.pkgmgr.ExtensionManager;
  import org.apache.avalon.phoenix.components.extensions.pkgmgr.OptionalPackage;
  
  /**
   * A {@link ExtensionManager} that can delegate to multiple
   * different package repositories.
   *
   * @author <a href="mailto:peter at apache.org">Peter Donald</a>
   * @version $Revision: 1.1 $ $Date: 2003/04/30 10:03:52 $
   */
  public class DelegatingExtensionManager
      implements ExtensionManager
  {
      /**
       * The list containing the {@link ExtensionManager} objects.
       */
      private final ArrayList m_extensionManagers = new ArrayList();
  
      /**
       * Default constructor that does not add any repositories.
       */
      public DelegatingExtensionManager()
      {
      }
  
      /**
       * Default constructor that delegates to specified extensionManagers.
       */
      public DelegatingExtensionManager( final ExtensionManager[] extensionManagers )
      {
          for( int i = 0; i < extensionManagers.length; i++ )
          {
              addExtensionManager( extensionManagers[ i ] );
          }
      }
  
      /**
       * Add a extensionManager to list of repositories delegated to
       * to find Optional Packages.
       *
       * @param extensionManager the extensionManager to add
       */
      protected synchronized void addExtensionManager( final ExtensionManager extensionManager )
      {
          if( !m_extensionManagers.contains( extensionManager ) )
          {
              m_extensionManagers.add( extensionManager );
          }
      }
  
      /**
       * Add a extensionManager to list of repositories delegated to
       * to find Optional Packages.
       *
       * @param extensionManager the extensionManager to add
       * @deprecated Use addExtensionManager instead
       */
      protected void addPackageRepository( final ExtensionManager extensionManager )
      {
          addExtensionManager( extensionManager );
      }
  
      /**
       * Remove a repository from list of repositories delegated to
       * to find Optional Packages.
       *
       * @param repository the repository to remove
       */
      protected synchronized void removeExtensionManager( final ExtensionManager repository )
      {
          m_extensionManagers.remove( repository );
      }
  
      /**
       * Remove a extensionManager from list of repositories delegated to
       * to find Optional Packages.
       *
       * @param extensionManager the extensionManager to remove
       * @deprecated Use removeExtensionManager instead.
       */
      protected void removePackageRepository( final ExtensionManager extensionManager )
      {
          removeExtensionManager( extensionManager );
      }
  
      /**
       * Scan through list of respositories and return all the matching {@link OptionalPackage}
       * objects that match in any repository.
       *
       * @param extension the extension to search for
       * @return the matching {@link OptionalPackage} objects.
       */
      public synchronized OptionalPackage[] getOptionalPackages( final Extension extension )
      {
          final ArrayList resultPackages = new ArrayList();
  
          final int size = m_extensionManagers.size();
          for( int i = 0; i < size; i++ )
          {
              final ExtensionManager repository =
                  (ExtensionManager)m_extensionManagers.get( i );
              final OptionalPackage[] packages =
                  repository.getOptionalPackages( extension );
              if( null == packages || 0 == packages.length )
              {
                  continue;
              }
  
              for( int j = 0; j < packages.length; j++ )
              {
                  resultPackages.add( packages[ j ] );
              }
          }
  
          final OptionalPackageComparator comparator =
              new OptionalPackageComparator( extension.getExtensionName() );
          Collections.sort( resultPackages, comparator );
          final OptionalPackage[] resultData =
              new OptionalPackage[ resultPackages.size() ];
          return (OptionalPackage[])resultPackages.toArray( resultData );
      }
  }
  
  
  
  1.1                  avalon-phoenix/src/java/org/apache/avalon/phoenix/components/extensions/pkgmgr/impl/NoopExtensionManager.java
  
  Index: NoopExtensionManager.java
  ===================================================================
  /*
  
   ============================================================================
                     The Apache Software License, Version 1.1
   ============================================================================
  
   Copyright (C) 1997-2003 The Apache Software Foundation. All rights reserved.
  
   Redistribution and use in source and binary forms, with or without modifica-
   tion, 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  acknowledgment:  "This product includes  software
      developed  by the  Apache Software Foundation  (http://www.apache.org/)."
      Alternately, this  acknowledgment may  appear in the software itself,  if
      and wherever such third-party acknowledgments normally appear.
  
   4. The names "Avalon", "Phoenix" 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 name,  without prior written permission  of the
      Apache Software Foundation.
  
   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 (INCLU-
   DING, 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 <http://www.apache.org/>.
  
  */
  package org.apache.avalon.phoenix.components.extensions.pkgmgr.impl;
  
  import org.apache.avalon.excalibur.extension.Extension;
  import org.apache.avalon.phoenix.components.extensions.pkgmgr.ExtensionManager;
  import org.apache.avalon.phoenix.components.extensions.pkgmgr.OptionalPackage;
  
  /**
   * A Noop ExtensionManager that can't provide any extensions.
   * This is for use in certain environments (ala Servlets) that
   * require apps to be be self-contained.
   *
   * @author <a href="mailto:peter at apache.org">Peter Donald</a>
   * @version $Revision: 1.1 $ $Date: 2003/04/30 10:03:52 $
   */
  public class NoopExtensionManager
      implements ExtensionManager
  {
      /**
       * Return an empty array of {@link OptionalPackage}s.
       *
       * @param extension the extension looking for
       * @see ExtensionManager#getOptionalPackages
       */
      public OptionalPackage[] getOptionalPackages( final Extension extension )
      {
          return new OptionalPackage[ 0 ];
      }
  }
  
  
  
  1.1                  avalon-phoenix/src/java/org/apache/avalon/phoenix/components/extensions/pkgmgr/impl/OptionalPackageComparator.java
  
  Index: OptionalPackageComparator.java
  ===================================================================
  /*
  
   ============================================================================
                     The Apache Software License, Version 1.1
   ============================================================================
  
   Copyright (C) 1997-2003 The Apache Software Foundation. All rights reserved.
  
   Redistribution and use in source and binary forms, with or without modifica-
   tion, 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  acknowledgment:  "This product includes  software
      developed  by the  Apache Software Foundation  (http://www.apache.org/)."
      Alternately, this  acknowledgment may  appear in the software itself,  if
      and wherever such third-party acknowledgments normally appear.
  
   4. The names "Avalon", "Phoenix" 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 name,  without prior written permission  of the
      Apache Software Foundation.
  
   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 (INCLU-
   DING, 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 <http://www.apache.org/>.
  
  */
  package org.apache.avalon.phoenix.components.extensions.pkgmgr.impl;
  
  import java.util.Comparator;
  import org.apache.avalon.excalibur.extension.DeweyDecimal;
  import org.apache.avalon.excalibur.extension.Extension;
  import org.apache.avalon.phoenix.components.extensions.pkgmgr.OptionalPackage;
  
  /**
   * A simple class to compare two extensions and sort them
   * on spec version and then on impl version. Unspecified
   * versions rate lower than specified versions.
   *
   * @author <a href="mailto:peter at apache.org">Peter Donald</a>
   * @version $Revision: 1.1 $ $Date: 2003/04/30 10:03:52 $
   */
  class OptionalPackageComparator
      implements Comparator
  {
      /**
       * The name of extension the comparator is working with.
       */
      private final String m_name;
  
      public OptionalPackageComparator( final String name )
      {
          if( null == name )
          {
              throw new NullPointerException( "name" );
          }
  
          m_name = name;
      }
  
      public int compare( final Object o1,
                          final Object o2 )
      {
          final OptionalPackage pkg1 = (OptionalPackage)o1;
          final OptionalPackage pkg2 = (OptionalPackage)o2;
          final Extension e1 = getMatchingExtension( pkg1 );
          final Extension e2 = getMatchingExtension( pkg2 );
          int result = compareSpecVersion( e1, e2 );
          if( 0 != result )
          {
              return result;
          }
          else
          {
              return compareImplVersion( e1, e2 );
          }
      }
  
      private Extension getMatchingExtension( final OptionalPackage pkg )
      {
          final Extension[] extensions = pkg.getAvailableExtensions();
          for( int i = 0; i < extensions.length; i++ )
          {
              final Extension extension = extensions[ i ];
              if( extension.getExtensionName().equals( m_name ) )
              {
                  return extension;
              }
          }
  
          final String message = "Unable to locate extension " +
              m_name + " in package " + pkg;
          throw new IllegalStateException( message );
      }
  
      private int compareImplVersion( final Extension e1, final Extension e2 )
      {
          final String implVersion1 = e1.getImplementationVersion();
          final String implVersion2 = e2.getImplementationVersion();
          if( null == implVersion1 && null == implVersion2 )
          {
              return 0;
          }
          else if( null != implVersion1 && null == implVersion2 )
          {
              return -1;
          }
          else if( null == implVersion1 && null != implVersion2 )
          {
              return 1;
          }
          else
          {
              return -implVersion1.compareTo( implVersion2 );
          }
      }
  
      private int compareSpecVersion( final Extension e1,
                                      final Extension e2 )
      {
          final DeweyDecimal specVersion1 = e1.getSpecificationVersion();
          final DeweyDecimal specVersion2 = e2.getSpecificationVersion();
          if( null == specVersion1 && null == specVersion2 )
          {
              return 0;
          }
          else if( null != specVersion1 && null == specVersion2 )
          {
              return -1;
          }
          else if( null == specVersion1 && null != specVersion2 )
          {
              return 1;
          }
          else
          {
              if( specVersion1.isEqual( specVersion2 ) )
              {
                  return 0;
              }
              else if( specVersion1.isGreaterThan( specVersion2 ) )
              {
                  return -1;
              }
              else
              {
                  return 1;
              }
          }
      }
  }
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: cvs-unsubscribe@avalon.apache.org
For additional commands, e-mail: cvs-help@avalon.apache.org


Re: cvs commit: avalon-phoenix/src/java/org/apache/avalon/phoenix/components/extensions/pkgmgr/impl DefaultExtensionManager.java DelegatingExtensionManager.java NoopExtensionManager.java OptionalPackageComparator.java

Posted by Stephen McConnell <mc...@apache.org>.

Peter Donald wrote:

>On Wed, 30 Apr 2003 22:47, Stephen McConnell wrote:
>
>>   1. that this duplication will result in the reduction in
>>      quality of the existing Excalibur Extension code base
>>    
>>
>
>Exactly the opposite actually. I am in the process of merging in the Library 
>stuff done by Adam in myrmidon which will involve breaking backwards 
>compatability with package manager. It would seem unreasonable to do it in 
>extension when I would break your codebase and besides Extension is exiting 
>Avalon anyway.
>

I suggest we work on this together under a branch of the Excalibur 
Extension package. Just for reference, no decision has been taken 
concerning the exiting of the extension package and as such it remains 
an Avalon concern.

-- 

Stephen J. McConnell
mailto:mcconnell@apache.org
http://www.osm.net

Sent via James running under Merlin as an NT service.



---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@avalon.apache.org
For additional commands, e-mail: dev-help@avalon.apache.org


Re: cvs commit: avalon-phoenix/src/java/org/apache/avalon/phoenix/components/extensions/pkgmgr/impl DefaultExtensionManager.java DelegatingExtensionManager.java NoopExtensionManager.java OptionalPackageComparator.java

Posted by Peter Donald <pe...@realityforge.org>.
On Wed, 30 Apr 2003 22:47, Stephen McConnell wrote:
>    1. that this duplication will result in the reduction in
>       quality of the existing Excalibur Extension code base

Exactly the opposite actually. I am in the process of merging in the Library 
stuff done by Adam in myrmidon which will involve breaking backwards 
compatability with package manager. It would seem unreasonable to do it in 
extension when I would break your codebase and besides Extension is exiting 
Avalon anyway.

-- 
Cheers,

Peter Donald
-------------------------------------------------------
To fight and conquer in all your battles is not supreme 
excellence; supreme excellence consists in breaking the 
enemy's resistance without fighting. - Sun Tzu, 300 B.C.
-------------------------------------------------------


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@avalon.apache.org
For additional commands, e-mail: dev-help@avalon.apache.org


Re: cvs commit: avalon-phoenix/src/java/org/apache/avalon/phoenix/components/extensions/pkgmgr/impl DefaultExtensionManager.java DelegatingExtensionManager.java NoopExtensionManager.java OptionalPackageComparator.java

Posted by Stephen McConnell <mc...@apache.org>.

Peter Royal wrote:

> On Wednesday, April 30, 2003, at 08:47  AM, Stephen McConnell wrote:
>
>> This commit constitutes a fork of the existing Excalibur Extensions 
>> package, resulting in the doubling up of the code to be 
>> maintained/managed by Avalon.
>
>
> I believe the plan was to move Extension to the Excalibur 
> Compatibility project:
>
> http://marc.theaimsgroup.com/?l=avalon-dev&m=105056981008335&w=2
> http://marc.theaimsgroup.com/?l=avalon-dev&m=105057109509708&w=2
> http://marc.theaimsgroup.com/?l=avalon-dev&m=105057277811364&w=2
>
> And especially:
>
> http://marc.theaimsgroup.com/?l=avalon-dev&m=105058203919910&w=2
> http://marc.theaimsgroup.com/?l=avalon-dev&m=105058376321354&w=2


Your neglecting the conclusion of the thread (this bit where a vote is 
taken and the result posted).

http://marc.theaimsgroup.com/?l=avalon-dev&m=105068223616095&w=2


>
> You never answered Berin's second question..


Nothing substantive - identification of some bugs and posting of 
solutions. The larely reflects that fact that the package was reasonably 
stable before I starting using it.  However, initial usage within Merlin 
identifed some recusion errors - since that time no techjnical issues or 
bugs have been identifed.  I should point out that I am completely 
familiar with the package having spent considerable time working with it.

>
> We are trying to (a) remove one-man codebases and (b) remove utility 
> code. AFAIK, Extension meets the bill for both of those two criteria. 


That is accademic.  There was discussion on the subject of this 
package.  There was conclusion - no action was agreed to - i.e. no 
kicking out, no sandboxing, etc.  This package is in use within Merlin - 
it cannot simply dissapear.  Any comments now after a vote on the 
subject do not change the result of that vote.

>
>
> Saying that the commit "constitutes a fork" implies that there will be 
> further development of Excalibur Extension. I do not believe that was 
> the case, it appears that it was destined to be deprecated, at least 
> in the context of this community. 


Absolutely incorrect.
There is some solid documetation work to be done both about the package 
and enhancing javadoc.  This will be required no mater what.  I except 
to take care of this sometime in the near future.

The conclusion of the discussion was to *not* take a decision at this 
time - see 18-APR [VOTE-RESULT] and preceeding discussions.  The 
Excalibur Extension package remains an Excalibur package in use by 
Merlin and Phoenix.

Cheers, Steve.

-- 

Stephen J. McConnell
mailto:mcconnell@apache.org
http://www.osm.net

Sent via James running under Merlin as an NT service.



---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@avalon.apache.org
For additional commands, e-mail: dev-help@avalon.apache.org


Re: cvs commit: avalon-phoenix/src/java/org/apache/avalon/phoenix/components/extensions/pkgmgr/impl DefaultExtensionManager.java DelegatingExtensionManager.java NoopExtensionManager.java OptionalPackageComparator.java

Posted by Peter Royal <pr...@apache.org>.
On Wednesday, April 30, 2003, at 08:47  AM, Stephen McConnell wrote:
> This commit constitutes a fork of the existing Excalibur Extensions 
> package, resulting in the doubling up of the code to be 
> maintained/managed by Avalon.

I believe the plan was to move Extension to the Excalibur Compatibility 
project:

http://marc.theaimsgroup.com/?l=avalon-dev&m=105056981008335&w=2
http://marc.theaimsgroup.com/?l=avalon-dev&m=105057109509708&w=2
http://marc.theaimsgroup.com/?l=avalon-dev&m=105057277811364&w=2

And especially:

http://marc.theaimsgroup.com/?l=avalon-dev&m=105058203919910&w=2
http://marc.theaimsgroup.com/?l=avalon-dev&m=105058376321354&w=2

You never answered Berin's second question..

We are trying to (a) remove one-man codebases and (b) remove utility 
code. AFAIK, Extension meets the bill for both of those two criteria.

Saying that the commit "constitutes a fork" implies that there will be 
further development of Excalibur Extension. I do not believe that was 
the case, it appears that it was destined to be deprecated, at least in 
the context of this community.
-pete


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@avalon.apache.org
For additional commands, e-mail: dev-help@avalon.apache.org


Re: cvs commit: avalon-phoenix/src/java/org/apache/avalon/phoenix/components/extensions/pkgmgr/impl DefaultExtensionManager.java DelegatingExtensionManager.java NoopExtensionManager.java OptionalPackageComparator.java

Posted by Stephen McConnell <mc...@apache.org>.
Peter:

This commit constitutes a fork of the existing Excalibur Extensions 
package, resulting in the doubling up of the code to be 
maintained/managed by Avalon.

 I consider this problematic on the following grounds

   1. that this duplication will result in the reduction in
      quality of the existing Excalibur Extension code base
   2. this action will ultimately be a source of confusion
   3. that no prior discussion on this actions was initiated
      under the deval@avalon list

As such, would you please accept this message as my formal -1 (veto) on 
these commits and the related changes that you made earlier today.  Once 
the sources in Phoenix have been reverted I would be more than willing 
to discuss the subject further with the full participation of the Avalon 
development community.

Cheers, Steve.


donaldp@apache.org wrote:

>donaldp     2003/04/30 03:03:53
>
>  Added:       src/java/org/apache/avalon/phoenix/components/extensions/pkgmgr
>                        ExtensionManager.java OptionalPackage.java
>                        PackageManager.java
>                        UnsatisfiedExtensionException.java
>               src/java/org/apache/avalon/phoenix/components/extensions/pkgmgr/impl
>                        DefaultExtensionManager.java
>                        DelegatingExtensionManager.java
>                        NoopExtensionManager.java
>                        OptionalPackageComparator.java
>  Log:
>  Import excalibur-extension PackageManager stuff in prep for decoupling
>  
>  Revision  Changes    Path
>  1.1                  avalon-phoenix/src/java/org/apache/avalon/phoenix/components/extensions/pkgmgr/ExtensionManager.java
>  
>  Index: ExtensionManager.java
>  ===================================================================
>  /*
>  
>   ============================================================================
>                     The Apache Software License, Version 1.1
>   ============================================================================
>  
>   Copyright (C) 1997-2003 The Apache Software Foundation. All rights reserved.
>  
>   Redistribution and use in source and binary forms, with or without modifica-
>   tion, 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  acknowledgment:  "This product includes  software
>      developed  by the  Apache Software Foundation  (http://www.apache.org/)."
>      Alternately, this  acknowledgment may  appear in the software itself,  if
>      and wherever such third-party acknowledgments normally appear.
>  
>   4. The names "Avalon", "Phoenix" 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 name,  without prior written permission  of the
>      Apache Software Foundation.
>  
>   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 (INCLU-
>   DING, 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 <http://www.apache.org/>.
>  
>  */
>  package org.apache.avalon.phoenix.components.extensions.pkgmgr;
>  
>  import org.apache.avalon.excalibur.extension.Extension;
>  
>  /**
>   * <p>Interface used to store a collection of "Optional Packages"
>   * (formerly known as "Standard Extensions"). It is assumed that each
>   * "Optional Package" is represented by a single file on the file system.</p>
>   *
>   * <p>This repository is responsible for storing the local repository of
>   * packages. The method used to locate packages on local filesystem
>   * and install packages is not specified.</p>
>   *
>   * <p>For more information about optional packages, see the document
>   * <em>Optional Package Versioning</em> in the documentation bundle for your
>   * Java2 Standard Edition package, in file
>   * <code>guide/extensions/versioning.html</code></p>.
>   *
>   * @author <a href="mailto:peter at apache.org">Peter Donald</a>
>   * @version $Revision: 1.1 $ $Date: 2003/04/30 10:03:52 $
>   */
>  public interface ExtensionManager
>  {
>      String ROLE = ExtensionManager.class.getName();
>  
>      /**
>       * Return all the {@link OptionalPackage}s that satisfy specified
>       * {@link Extension}. The array must be sorted with the packages that
>       * "best" satisfy the Extension earlier in the array. Note that the
>       * definition of "best" is implementation dependent.
>       *
>       * @param extension Description of the extension that needs to be provided by
>       *                  optional packages
>       * @return an array of optional packages that satisfy extension and
>       *         the extensions dependencies
>       * @see OptionalPackage
>       * @see Extension
>       */
>      OptionalPackage[] getOptionalPackages( Extension extension );
>  }
>  
>  
>  
>  1.1                  avalon-phoenix/src/java/org/apache/avalon/phoenix/components/extensions/pkgmgr/OptionalPackage.java
>  
>  Index: OptionalPackage.java
>  ===================================================================
>  /*
>  
>   ============================================================================
>                     The Apache Software License, Version 1.1
>   ============================================================================
>  
>   Copyright (C) 1997-2003 The Apache Software Foundation. All rights reserved.
>  
>   Redistribution and use in source and binary forms, with or without modifica-
>   tion, 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  acknowledgment:  "This product includes  software
>      developed  by the  Apache Software Foundation  (http://www.apache.org/)."
>      Alternately, this  acknowledgment may  appear in the software itself,  if
>      and wherever such third-party acknowledgments normally appear.
>  
>   4. The names "Avalon", "Phoenix" 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 name,  without prior written permission  of the
>      Apache Software Foundation.
>  
>   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 (INCLU-
>   DING, 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 <http://www.apache.org/>.
>  
>  */
>  package org.apache.avalon.phoenix.components.extensions.pkgmgr;
>  
>  import java.io.File;
>  import org.apache.avalon.excalibur.extension.Extension;
>  
>  /**
>   * This contains the required meta-data for an "Optional Package"
>   * (formerly known as "Standard Extension") as described in the manifest
>   * of a JAR file.
>   *
>   * @author <a href="mailto:peter at apache.org">Peter Donald</a>
>   */
>  public final class OptionalPackage
>  {
>      private final File m_file;
>      private final Extension[] m_available;
>      private final Extension[] m_required;
>  
>      /**
>       * Convert a list of OptionalPackages into a list of Files.
>       *
>       * @param packages the list of packages
>       * @return the list of files
>       */
>      public static final File[] toFiles( final OptionalPackage[] packages )
>      {
>          final File[] results = new File[ packages.length ];
>  
>          for( int i = 0; i < packages.length; i++ )
>          {
>              results[ i ] = packages[ i ].getFile();
>          }
>  
>          return results;
>      }
>  
>      /**
>       * Constructor for OptionalPackage.
>       * No parameter is allowed to be null.
>       *
>       * @param file absolute location of file
>       * @param available the list of Extensions Optional Package provides
>       * @param required the list of Extensions Optional Package requires
>       */
>      public OptionalPackage( final File file,
>                              final Extension[] available,
>                              final Extension[] required )
>      {
>          if( null == file )
>          {
>              throw new NullPointerException( "file" );
>          }
>  
>          if( null == available )
>          {
>              throw new NullPointerException( "available" );
>          }
>  
>          if( null == required )
>          {
>              throw new NullPointerException( "required" );
>          }
>  
>          m_file = file;
>          m_available = available;
>          m_required = required;
>      }
>  
>      /**
>       * Return <code>File</code> object in which OptionalPackage
>       * is contained.
>       *
>       * @return the file object for OptionalPackage
>       */
>      public File getFile()
>      {
>          return m_file;
>      }
>  
>      /**
>       * Return <code>Extension</code>s which OptionalPackage
>       * requires to operate.
>       *
>       * @return the extensions required by OptionalPackage
>       */
>      public Extension[] getRequiredExtensions()
>      {
>          return m_required;
>      }
>  
>      /**
>       * Return <code>Extension</code>s which OptionalPackage
>       * makes available.
>       *
>       * @return the extensions made available by OptionalPackage
>       */
>      public Extension[] getAvailableExtensions()
>      {
>          return m_available;
>      }
>  
>      /**
>       * Return <code>true</code> if any of the available <code>Extension</code>s
>       * are compatible with specified extension. Otherwise return <code>false</code>.
>       *
>       * @param extension the extension
>       * @return true if compatible, false otherwise
>       */
>      public boolean isCompatible( final Extension extension )
>      {
>          for( int i = 0; i < m_available.length; i++ )
>          {
>              if( m_available[ i ].isCompatibleWith( extension ) )
>              {
>                  return true;
>              }
>          }
>  
>          return false;
>      }
>  
>      /**
>       * Return a String representation of this object.
>       *
>       * @return the string representation of object
>       */
>      public String toString()
>      {
>          final StringBuffer sb = new StringBuffer( "OptionalPackage[" );
>          sb.append( m_file );
>  
>          sb.append( ", Available[" );
>          for( int i = 0; i < m_available.length; i++ )
>          {
>              if( 0 != i )
>              {
>                  sb.append( " " );
>              }
>              sb.append( m_available[ i ].getExtensionName() );
>          }
>  
>          sb.append( "], Required[" );
>          for( int i = 0; i < m_required.length; i++ )
>          {
>              if( 0 != i )
>              {
>                  sb.append( " " );
>              }
>              sb.append( m_required[ i ].getExtensionName() );
>          }
>  
>          sb.append( "] ]" );
>  
>          return sb.toString();
>      }
>  }
>  
>  
>  
>  1.1                  avalon-phoenix/src/java/org/apache/avalon/phoenix/components/extensions/pkgmgr/PackageManager.java
>  
>  Index: PackageManager.java
>  ===================================================================
>  /*
>  
>   ============================================================================
>                     The Apache Software License, Version 1.1
>   ============================================================================
>  
>   Copyright (C) 1997-2003 The Apache Software Foundation. All rights reserved.
>  
>   Redistribution and use in source and binary forms, with or without modifica-
>   tion, 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  acknowledgment:  "This product includes  software
>      developed  by the  Apache Software Foundation  (http://www.apache.org/)."
>      Alternately, this  acknowledgment may  appear in the software itself,  if
>      and wherever such third-party acknowledgments normally appear.
>  
>   4. The names "Avalon", "Phoenix" 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 name,  without prior written permission  of the
>      Apache Software Foundation.
>  
>   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 (INCLU-
>   DING, 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 <http://www.apache.org/>.
>  
>  */
>  package org.apache.avalon.phoenix.components.extensions.pkgmgr;
>  
>  import java.util.ArrayList;
>  import java.util.List;
>  import org.apache.avalon.excalibur.extension.Extension;
>  
>  /**
>   * Basic Implementation Of PackageManager Interface used to manage
>   * "Optional Packages" (formerly known as "Standard Extensions").
>   * The "Optional Packages" are stored on file system in a number of
>   * directories.
>   *
>   * @author <a href="mailto:peter at apache.org">Peter Donald</a>
>   * @version $Revision: 1.1 $ $Date: 2003/04/30 10:03:52 $
>   * @see ExtensionManager
>   * @todo Determine an appropriate interface to this service and
>   *       an appropriate mechanism via which to do searching and
>   *       expansion of a package set. At that point separate out
>   *       implementation and interface for mechanism.
>   */
>  public class PackageManager
>  {
>      ///Ordered list of repositories to search in
>      private ExtensionManager m_repository;
>  
>      /**
>       * Construct a PackageManager for a repositories.
>       *
>       * @param repository the repository to use in PackageManager
>       */
>      public PackageManager( final ExtensionManager repository )
>      {
>          if( null == repository )
>          {
>              throw new NullPointerException( "repository" );
>          }
>  
>          m_repository = repository;
>      }
>  
>      /**
>       * Return the {@link OptionalPackage} that provides specified
>       * {@link Extension}. If the specified {@link Extension}
>       * can not be found then <code>null</code> is returned. If there is
>       * multiple implementations that satisfy {@link Extension},
>       * then an {@link OptionalPackage} returned is based on the
>       * following heristic;
>       *
>       * <p>Return the first Optional Package. (This heuristic will
>       * be replaced in time).</p>
>       *
>       * @param extension Description of the extension that needs to be provided by
>       *                  optional package
>       * @return an array of optional packages that satisfy extension and
>       *         the extensions dependencies
>       * @see OptionalPackage
>       * @see Extension
>       */
>      public OptionalPackage getOptionalPackage( final Extension extension )
>      {
>          final OptionalPackage[] packages = m_repository.getOptionalPackages( extension );
>          if( null == packages || 0 == packages.length )
>          {
>              return null;
>          }
>  
>          //The best candidate is always returned first so we
>          //can just return it.
>          return packages[ 0 ];
>      }
>  
>      /**
>       * Build a list of dependencies based on specified {@link Extension}s.
>       * Each specified {@link Extension} is expected to be a required extension
>       * of another "Optional Package".
>       *
>       * <p>If the required {@link Extension} can not be found locally then
>       * an UnsatisfiedPackageException is thrown. if an {@link OptionalPackage}
>       * is found locally that satisfies specified required {@link Extension}
>       * then it is returned in the array of OptionalPackages. scanDependencies() is then recursively
>       * called on all of the candidates required extensions.</p>
>       *
>       * @param required the array of required Extensions.
>       * @param available the array of Extensions already available to caller.
>       * @return the list of OptionalPackages that satisfy required Extensions
>       * @throws UnsatisfiedExtensionException if extensions could not be satisified
>       * @see #scanDependencies
>       */
>      public OptionalPackage[] scanDependencies( final Extension required,
>                                                 final Extension[] available )
>          throws UnsatisfiedExtensionException
>      {
>          return scanDependencies( new Extension[]{required}, available );
>      }
>  
>      /**
>       * Build a list of dependencies based on specified {@link Extension}.
>       * The specified {@link Extension} is expected to be a required extension
>       * of another "Optional Package".
>       *
>       * <p>If the required {@link Extension} can not be found locally then
>       * an UnsatisfiedPackageException is thrown. if an {@link OptionalPackage}
>       * is found locally that satisfies specified required {@link Extension}
>       * then it is returned in the array of OptionalPackages. scanDependencies() is then recursively
>       * called on all of the candidates required extensions.</p>
>       *
>       * @param required the array of required Extensions.
>       * @param available the array of Extensions already available to caller.
>       * @return the list of OptionalPackages that satisfy required Extensions
>       * @throws UnsatisfiedExtensionException if extensions could not be satisified
>       * @see #scanDependencies
>       */
>      public OptionalPackage[] scanDependencies( final Extension[] required,
>                                                 final Extension[] available )
>          throws UnsatisfiedExtensionException
>      {
>          final ArrayList dependencies = new ArrayList();
>          final ArrayList unsatisfied = new ArrayList();
>  
>          scanDependencies( required, available, dependencies, unsatisfied );
>  
>          if( 0 != unsatisfied.size() )
>          {
>              final Extension extension = (Extension)unsatisfied.get( 0 );
>              throw new UnsatisfiedExtensionException( extension );
>          }
>  
>          return (OptionalPackage[])dependencies.toArray( new OptionalPackage[ 0 ] );
>      }
>  
>      /**
>       * Build a list of dependencies based on specified {@link Extension}s.
>       * Each specified {@link Extension} is expected to be a required extension
>       * of another "Optional Package".
>       *
>       * <p>If the required {@link Extension} can not be found locally then
>       * it is placed in list of unsatisfied Extensions. If a candidate {@link Extension}
>       * is found locally that satisfies specified required {@link Extension}
>       * then it is added to list of dependencies. scanDependencies() is then recursively
>       * called on all of the candidates required extensions.</p>
>       *
>       * @param required the array of required Extensions.
>       * @param available the array of Extensions already available to caller.
>       * @param dependencies the list of dependencies.
>       * @param unsatisfied the list of unsatisfied (ie non-local) dependencies.
>       * @see #scanDependencies
>       */
>      public void scanDependencies( final Extension[] required,
>                                    final Extension[] available,
>                                    final List dependencies,
>                                    final List unsatisfied )
>      {
>          for( int i = 0; i < required.length; i++ )
>          {
>              scanDependencies( required[ i ], available, dependencies, unsatisfied );
>          }
>      }
>  
>      /**
>       * Build a list of dependencies based on specified {@link Extension}.
>       * The specified {@link Extension} is expected to be a required extension
>       * of another "Optional Package".
>       *
>       * <p>If the required {@link Extension} can not be found locally then
>       * it is placed in list of unsatisfied Extensions. If a candidate {@link OptionalPackage}
>       * is found locally that satisfies specified required {@link Extension}
>       * then it is added to list of dependencies. scanDependencies() is then recursively
>       * called on all of the candidates required extensions.</p>
>       *
>       * @param required the required Extension.
>       * @param available the array of Extensions already available to caller.
>       * @param dependencies the list of OptionalPackages required to satisfy extension.
>       * @param unsatisfied the list of unsatisfied (ie non-local) dependencies.
>       * @see #scanDependencies
>       */
>      public void scanDependencies( final Extension required,
>                                    final Extension[] available,
>                                    final List dependencies,
>                                    final List unsatisfied )
>      {
>          //Check to see if extension is satisifed by the
>          //list of available extensions passed in
>          for( int i = 0; i < available.length; i++ )
>          {
>              final Extension other = available[ i ];
>              if( other.isCompatibleWith( required ) )
>              {
>                  return;
>              }
>          }
>  
>          //Check to see if extension is satisifed by one
>          //of the extensions already found
>          final int size = dependencies.size();
>          for( int i = 0; i < size; i++ )
>          {
>              final OptionalPackage optionalPackage = (OptionalPackage)dependencies.get( i );
>              if( optionalPackage.isCompatible( required ) )
>              {
>                  return;
>              }
>          }
>  
>          final OptionalPackage optionalPackage = getOptionalPackage( required );
>          if( null == optionalPackage )
>          {
>              if( !unsatisfied.contains( required ) )
>              {
>                  unsatisfied.add( required );
>              }
>          }
>          else
>          {
>              if( !dependencies.contains( optionalPackage ) )
>              {
>                  dependencies.add( optionalPackage );
>              }
>  
>              scanDependencies( optionalPackage.getRequiredExtensions(),
>                                available,
>                                dependencies,
>                                unsatisfied );
>          }
>      }
>  }
>  
>  
>  
>  1.1                  avalon-phoenix/src/java/org/apache/avalon/phoenix/components/extensions/pkgmgr/UnsatisfiedExtensionException.java
>  
>  Index: UnsatisfiedExtensionException.java
>  ===================================================================
>  /*
>  
>   ============================================================================
>                     The Apache Software License, Version 1.1
>   ============================================================================
>  
>   Copyright (C) 1997-2003 The Apache Software Foundation. All rights reserved.
>  
>   Redistribution and use in source and binary forms, with or without modifica-
>   tion, 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  acknowledgment:  "This product includes  software
>      developed  by the  Apache Software Foundation  (http://www.apache.org/)."
>      Alternately, this  acknowledgment may  appear in the software itself,  if
>      and wherever such third-party acknowledgments normally appear.
>  
>   4. The names "Avalon", "Phoenix" 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 name,  without prior written permission  of the
>      Apache Software Foundation.
>  
>   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 (INCLU-
>   DING, 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 <http://www.apache.org/>.
>  
>  */
>  package org.apache.avalon.phoenix.components.extensions.pkgmgr;
>  
>  import org.apache.avalon.excalibur.extension.Extension;
>  
>  /**
>   * Exception indicating an extension was not found in Package Repository.
>   *
>   * @author <a href="mailto:peter at apache.org">Peter Donald</a>
>   * @version $Revision: 1.1 $ $Date: 2003/04/30 10:03:52 $
>   * @see Extension
>   */
>  public class UnsatisfiedExtensionException
>      extends Exception
>  {
>      /**
>       * The unsatisfied Extension.
>       */
>      private final Extension m_extension;
>  
>      /**
>       * Construct the <code>UnsatisfiedPackageException</code>
>       * for specified {@link Extension}.
>       *
>       * @param extension the extension that caused exception
>       */
>      public UnsatisfiedExtensionException( final Extension extension )
>      {
>          if( null == extension )
>          {
>              throw new NullPointerException( "extension" );
>          }
>  
>          m_extension = extension;
>      }
>  
>      /**
>       * Return the unsatisfied {@link Extension} that
>       * caused this exception tho be thrown.
>       *
>       * @return the unsatisfied Extension
>       */
>      public Extension getUnsatisfiedExtension()
>      {
>          return m_extension;
>      }
>  }
>  
>  
>  
>  1.1                  avalon-phoenix/src/java/org/apache/avalon/phoenix/components/extensions/pkgmgr/impl/DefaultExtensionManager.java
>  
>  Index: DefaultExtensionManager.java
>  ===================================================================
>  /*
>  
>   ============================================================================
>                     The Apache Software License, Version 1.1
>   ============================================================================
>  
>   Copyright (C) 1997-2003 The Apache Software Foundation. All rights reserved.
>  
>   Redistribution and use in source and binary forms, with or without modifica-
>   tion, 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  acknowledgment:  "This product includes  software
>      developed  by the  Apache Software Foundation  (http://www.apache.org/)."
>      Alternately, this  acknowledgment may  appear in the software itself,  if
>      and wherever such third-party acknowledgments normally appear.
>  
>   4. The names "Avalon", "Phoenix" 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 name,  without prior written permission  of the
>      Apache Software Foundation.
>  
>   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 (INCLU-
>   DING, 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 <http://www.apache.org/>.
>  
>  */
>  package org.apache.avalon.phoenix.components.extensions.pkgmgr.impl;
>  
>  import java.io.File;
>  import java.io.IOException;
>  import java.util.ArrayList;
>  import java.util.Collections;
>  import java.util.HashMap;
>  import java.util.Iterator;
>  import java.util.Map;
>  import java.util.StringTokenizer;
>  import java.util.jar.JarFile;
>  import java.util.jar.Manifest;
>  import org.apache.avalon.excalibur.extension.Extension;
>  import org.apache.avalon.phoenix.components.extensions.pkgmgr.ExtensionManager;
>  import org.apache.avalon.phoenix.components.extensions.pkgmgr.OptionalPackage;
>  
>  /**
>   * <p>Interface used to contain "Optional Packages" (formerly known as
>   * "Standard Extensions"). It is assumed that each "Optional Package" is
>   * represented by a single file on the file system. This Repository searches
>   * a path to find the Optional Packages.</p>
>   *
>   * @author <a href="mailto:peter at apache.org">Peter Donald</a>
>   * @version $Revision: 1.1 $ $Date: 2003/04/30 10:03:52 $
>   * @see OptionalPackage
>   * @see ExtensionManager
>   */
>  public class DefaultExtensionManager
>      implements ExtensionManager
>  {
>      private static final boolean DEBUG = false;
>  
>      /**
>       * separator used to separate path elements in a string.
>       */
>      private static final String SEPARATOR = "|";
>  
>      /**
>       * Map between files and {@link OptionalPackage} objects.
>       */
>      private final Map m_packages = new HashMap();
>  
>      /**
>       * The set of directories in which to look for Optional Packages
>       */
>      private File[] m_path;
>  
>      /**
>       * Flag set when it is necessary to scan paths to
>       * build "Optional Package" list
>       */
>      private boolean m_needToScan;
>  
>      /**
>       * Construct a package repository with no path specified.
>       */
>      public DefaultExtensionManager()
>      {
>          this( new File[ 0 ] );
>      }
>  
>      /**
>       * Construct a package repository with path.
>       *
>       * @param path The set of directories in which to look for Optional Packages
>       */
>      public DefaultExtensionManager( final File[] path )
>      {
>          setPath( path );
>      }
>  
>      /**
>       * Return an array of path elements where each
>       * element in array represents a directory
>       * in which the ExtensionManager will look
>       * for Extensions.
>       *
>       * @return the list of paths to search in
>       */
>      public File[] getPaths()
>      {
>          return m_path;
>      }
>  
>      /**
>       * Return all the {@link OptionalPackage}s that satisfy specified
>       * {@link Extension}. It is expected that this {@link Extension}
>       * object will be one retrieved via getLocalExtension() method. If the
>       * specified {@link Extension} is not local then <code>null</code>
>       * is returned.
>       *
>       * @param extension the extension to search for
>       * @return an array of optional packages that satisfy the extension
>       *         (and the extensions dependencies)
>       */
>      public synchronized OptionalPackage[] getOptionalPackages( final Extension extension )
>      {
>          if( m_needToScan )
>          {
>              scanPath();
>          }
>  
>          final ArrayList results = new ArrayList();
>          final ArrayList candidates = (ArrayList)m_packages.get( extension.getExtensionName() );
>          if( null != candidates )
>          {
>              final int size = candidates.size();
>              for( int i = 0; i < size; i++ )
>              {
>                  final OptionalPackage optionalPackage = (OptionalPackage)candidates.get( i );
>                  final Extension[] extensions = optionalPackage.getAvailableExtensions();
>  
>                  for( int j = 0; j < extensions.length; j++ )
>                  {
>                      if( extensions[ j ].isCompatibleWith( extension ) )
>                      {
>                          results.add( optionalPackage );
>                      }
>                  }
>              }
>          }
>  
>          final OptionalPackageComparator comparator =
>              new OptionalPackageComparator( extension.getExtensionName() );
>          Collections.sort( results, comparator );
>          return (OptionalPackage[])results.toArray( new OptionalPackage[ 0 ] );
>      }
>  
>      /**
>       * Return all the OptionalPackages stored in ExtensionManager.
>       *
>       * @return all the OptionalPackages stored in ExtensionManager.
>       */
>      protected synchronized OptionalPackage[] getAllOptionalPackages()
>      {
>          //This is woefully inefficient - should rewrite it somehow
>          final ArrayList packages = new ArrayList();
>          final Iterator iterator = m_packages.values().iterator();
>          while( iterator.hasNext() )
>          {
>              final ArrayList list = (ArrayList)iterator.next();
>              final int size = list.size();
>              for( int i = 0; i < size; i++ )
>              {
>                  final OptionalPackage optionalPackage = (OptionalPackage)list.get( i );
>                  if( !packages.contains( optionalPackage ) )
>                  {
>                      packages.add( optionalPackage );
>                  }
>              }
>          }
>  
>          return (OptionalPackage[])packages.toArray( new OptionalPackage[ packages.size() ] );
>      }
>  
>      /**
>       * Add path elements to repository search path
>       *
>       * @param pathElements the path elements to add to repository search path
>       */
>      protected void addPathElements( final String[] pathElements )
>      {
>          final File[] path = toFiles( pathElements );
>          addPathElements( path );
>      }
>  
>      /**
>       * Add path elements to repository search path
>       *
>       * @param path the path elements to add to repository search path
>       */
>      protected synchronized void addPathElements( final File[] path )
>      {
>          validatePath( path );
>          final File[] files = resolvePath( path );
>          m_path = mergePaths( files );
>          m_needToScan = true;
>      }
>  
>      /**
>       * Add path elements to repository search path.
>       * Note that each path element is separated by a '|' character.
>       *
>       * @param pathString the path elements to add to repository search path
>       */
>      protected void addPathElements( final String pathString )
>      {
>          final String[] pathElements = split( pathString, SEPARATOR );
>          addPathElements( pathElements );
>      }
>  
>      /**
>       * Set the path for the Repository.
>       * Note thart each path element is separated by a '|' character.
>       *
>       * @param pathString the list of directories in which to search
>       */
>      protected synchronized void setPath( final String pathString )
>      {
>          final String[] pathElements = split( pathString, SEPARATOR );
>          setPath( pathElements );
>      }
>  
>      /**
>       * Set the path for the Repository.
>       *
>       * @param pathElements the list of directories in which to search
>       */
>      protected synchronized void setPath( final String[] pathElements )
>      {
>          final File[] path = toFiles( pathElements );
>          setPath( path );
>      }
>  
>      /**
>       * Set the path for the Repository.
>       *
>       * @param path the list of directories in which to search
>       */
>      protected synchronized void setPath( final File[] path )
>      {
>          validatePath( path );
>          m_path = resolvePath( path );
>          m_needToScan = true;
>      }
>  
>      /**
>       * Scan the path for this repository and reload all
>       * the "Optional Packages" found in the path.
>       * All of the old Extensions/Optional Packages will
>       * be removed.
>       */
>      protected final synchronized void scanPath()
>      {
>          clearCache();
>  
>          for( int i = 0; i < m_path.length; i++ )
>          {
>              scanDirectory( m_path[ i ] );
>          }
>      }
>  
>      /**
>       * Utility method to scan a directory for
>       * all jar fi;les in directory and add them as
>       * OptionalPackages.
>       *
>       * @param directory the directory to scan
>       */
>      private synchronized void scanDirectory( final File directory )
>      {
>          final File[] files = directory.listFiles();
>          for( int i = 0; i < files.length; i++ )
>          {
>              final File file = files[ i ];
>              final String name = file.getName();
>  
>              if( !name.endsWith( ".jar" ) )
>              {
>                  final String message =
>                      "Skipping " + file + " as it does not end with '.jar'";
>                  debug( message );
>                  continue;
>              }
>  
>              if( !file.isFile() )
>              {
>                  final String message =
>                      "Skipping " + file + " as it is not a file.";
>                  debug( message );
>                  continue;
>              }
>  
>              if( !file.canRead() )
>              {
>                  final String message =
>                      "Skipping " + file + " as it is not readable.";
>                  debug( message );
>                  continue;
>              }
>  
>              try
>              {
>                  final OptionalPackage optionalPackage = getOptionalPackage( file );
>                  cacheOptionalPackage( optionalPackage );
>              }
>              catch( final IOException ioe )
>              {
>                  final String message =
>                      "Skipping " + file + " as it could not be loaded " +
>                      "due to " + ioe;
>                  debug( message );
>              }
>          }
>      }
>  
>      /**
>       * Clear internal cache of optional packages.
>       */
>      protected final synchronized void clearCache()
>      {
>          m_packages.clear();
>          m_needToScan = true;
>      }
>  
>      /**
>       * Add OptionalPackage to internal cache of Optional Packages.
>       * Note that this method is only protected so that unit tests can sub-class
>       * and add entries to PackageRepository by calling this method.
>       *
>       * @param optionalPackage the OptionalPackage to be added to repository
>       */
>      protected final synchronized void cacheOptionalPackage( final OptionalPackage optionalPackage )
>      {
>          m_needToScan = false;
>  
>          // added to avoid out of bounds exception
>          if( optionalPackage.getAvailableExtensions().length == 0 )
>          {
>              return;
>          }
>  
>          final Extension extension = optionalPackage.getAvailableExtensions()[ 0 ];
>          ArrayList candidates = (ArrayList)m_packages.get( extension.getExtensionName() );
>          if( null == candidates )
>          {
>              candidates = new ArrayList();
>              m_packages.put( extension.getExtensionName(), candidates );
>          }
>  
>          candidates.add( optionalPackage );
>      }
>  
>      /**
>       * Construct an OptionalPackage out of the specified jar archive.
>       *
>       * @param archive the file object for Jar archive
>       * @return the OptionalPackage constructed
>       * @throws IOException if an error occurs
>       */
>      private OptionalPackage getOptionalPackage( final File archive )
>          throws IOException
>      {
>          final File file = archive.getCanonicalFile();
>          final JarFile jarFile = new JarFile( file );
>          try
>          {
>              final Manifest manifest = jarFile.getManifest();
>              if( null == manifest )
>              {
>                  return null;
>              }
>              final Extension[] available = Extension.getAvailable( manifest );
>              final Extension[] required = Extension.getRequired( manifest );
>  
>              return new OptionalPackage( file, available, required );
>          }
>          finally
>          {
>              jarFile.close();
>          }
>      }
>  
>      /**
>       * Output a debug message for repository.
>       *
>       * @param message the debug message
>       */
>      protected void debug( final String message )
>      {
>          if( DEBUG )
>          {
>              System.out.println( message );
>          }
>      }
>  
>      /**
>       * Get Canonical or failing that the absolute file
>       * for every specified file.
>       *
>       * @param path the files that make up path
>       * @return the resolved path
>       */
>      private File[] resolvePath( final File[] path )
>      {
>          final File[] resultPath = new File[ path.length ];
>          for( int i = 0; i < path.length; i++ )
>          {
>              resultPath[ i ] = resolveFile( path[ i ] );
>          }
>          return resultPath;
>      }
>  
>      /**
>       * Get Canonical or failing that the absolute file
>       * for specified file.
>       *
>       * @param file the file
>       * @return the resolved file
>       */
>      private File resolveFile( final File file )
>      {
>          try
>          {
>              return file.getCanonicalFile();
>          }
>          catch( IOException e )
>          {
>              return file.getAbsoluteFile();
>          }
>      }
>  
>      /**
>       * Validate each element in path to make sure they are valid.
>       *
>       * @param path the path
>       */
>      private void validatePath( final File[] path )
>      {
>          if( null == path )
>          {
>              throw new NullPointerException( "path" );
>          }
>  
>          for( int i = 0; i < path.length; i++ )
>          {
>              validatePathElement( path[ i ] );
>          }
>      }
>  
>      /**
>       * Make sure specified path element is valid.
>       * The elements should exist and should be a directory.
>       *
>       * @param file the path element
>       */
>      private void validatePathElement( final File file )
>      {
>          if( !file.exists() || !file.isDirectory() )
>          {
>              final String message = "path element " + file +
>                  " must exist and must be a directory";
>              throw new IllegalArgumentException( message );
>          }
>      }
>  
>      /**
>       * Merge the specified file list with existing path.
>       *
>       * @param files the files to merge
>       * @return the merged path
>       */
>      private File[] mergePaths( final File[] files )
>      {
>          final File[] resultPath =
>              new File[ m_path.length + files.length ];
>          System.arraycopy( m_path, 0, resultPath, 0, m_path.length );
>          System.arraycopy( files, m_path.length, resultPath, 0, files.length );
>          return resultPath;
>      }
>  
>      /**
>       * Convert set of string elements into file objects
>       *
>       * @param pathElements the string path elements
>       * @return the file array representing each element
>       */
>      private File[] toFiles( final String[] pathElements )
>      {
>          final File[] path = new File[ pathElements.length ];
>          for( int i = 0; i < path.length; i++ )
>          {
>              path[ i ] = new File( pathElements[ i ] );
>          }
>          return path;
>      }
>  
>      /**
>       * 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 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;
>      }
>  }
>  
>  
>  
>  1.1                  avalon-phoenix/src/java/org/apache/avalon/phoenix/components/extensions/pkgmgr/impl/DelegatingExtensionManager.java
>  
>  Index: DelegatingExtensionManager.java
>  ===================================================================
>  /*
>  
>   ============================================================================
>                     The Apache Software License, Version 1.1
>   ============================================================================
>  
>   Copyright (C) 1997-2003 The Apache Software Foundation. All rights reserved.
>  
>   Redistribution and use in source and binary forms, with or without modifica-
>   tion, 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  acknowledgment:  "This product includes  software
>      developed  by the  Apache Software Foundation  (http://www.apache.org/)."
>      Alternately, this  acknowledgment may  appear in the software itself,  if
>      and wherever such third-party acknowledgments normally appear.
>  
>   4. The names "Avalon", "Phoenix" 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 name,  without prior written permission  of the
>      Apache Software Foundation.
>  
>   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 (INCLU-
>   DING, 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 <http://www.apache.org/>.
>  
>  */
>  package org.apache.avalon.phoenix.components.extensions.pkgmgr.impl;
>  
>  import java.util.ArrayList;
>  import java.util.Collections;
>  import org.apache.avalon.excalibur.extension.Extension;
>  import org.apache.avalon.phoenix.components.extensions.pkgmgr.ExtensionManager;
>  import org.apache.avalon.phoenix.components.extensions.pkgmgr.OptionalPackage;
>  
>  /**
>   * A {@link ExtensionManager} that can delegate to multiple
>   * different package repositories.
>   *
>   * @author <a href="mailto:peter at apache.org">Peter Donald</a>
>   * @version $Revision: 1.1 $ $Date: 2003/04/30 10:03:52 $
>   */
>  public class DelegatingExtensionManager
>      implements ExtensionManager
>  {
>      /**
>       * The list containing the {@link ExtensionManager} objects.
>       */
>      private final ArrayList m_extensionManagers = new ArrayList();
>  
>      /**
>       * Default constructor that does not add any repositories.
>       */
>      public DelegatingExtensionManager()
>      {
>      }
>  
>      /**
>       * Default constructor that delegates to specified extensionManagers.
>       */
>      public DelegatingExtensionManager( final ExtensionManager[] extensionManagers )
>      {
>          for( int i = 0; i < extensionManagers.length; i++ )
>          {
>              addExtensionManager( extensionManagers[ i ] );
>          }
>      }
>  
>      /**
>       * Add a extensionManager to list of repositories delegated to
>       * to find Optional Packages.
>       *
>       * @param extensionManager the extensionManager to add
>       */
>      protected synchronized void addExtensionManager( final ExtensionManager extensionManager )
>      {
>          if( !m_extensionManagers.contains( extensionManager ) )
>          {
>              m_extensionManagers.add( extensionManager );
>          }
>      }
>  
>      /**
>       * Add a extensionManager to list of repositories delegated to
>       * to find Optional Packages.
>       *
>       * @param extensionManager the extensionManager to add
>       * @deprecated Use addExtensionManager instead
>       */
>      protected void addPackageRepository( final ExtensionManager extensionManager )
>      {
>          addExtensionManager( extensionManager );
>      }
>  
>      /**
>       * Remove a repository from list of repositories delegated to
>       * to find Optional Packages.
>       *
>       * @param repository the repository to remove
>       */
>      protected synchronized void removeExtensionManager( final ExtensionManager repository )
>      {
>          m_extensionManagers.remove( repository );
>      }
>  
>      /**
>       * Remove a extensionManager from list of repositories delegated to
>       * to find Optional Packages.
>       *
>       * @param extensionManager the extensionManager to remove
>       * @deprecated Use removeExtensionManager instead.
>       */
>      protected void removePackageRepository( final ExtensionManager extensionManager )
>      {
>          removeExtensionManager( extensionManager );
>      }
>  
>      /**
>       * Scan through list of respositories and return all the matching {@link OptionalPackage}
>       * objects that match in any repository.
>       *
>       * @param extension the extension to search for
>       * @return the matching {@link OptionalPackage} objects.
>       */
>      public synchronized OptionalPackage[] getOptionalPackages( final Extension extension )
>      {
>          final ArrayList resultPackages = new ArrayList();
>  
>          final int size = m_extensionManagers.size();
>          for( int i = 0; i < size; i++ )
>          {
>              final ExtensionManager repository =
>                  (ExtensionManager)m_extensionManagers.get( i );
>              final OptionalPackage[] packages =
>                  repository.getOptionalPackages( extension );
>              if( null == packages || 0 == packages.length )
>              {
>                  continue;
>              }
>  
>              for( int j = 0; j < packages.length; j++ )
>              {
>                  resultPackages.add( packages[ j ] );
>              }
>          }
>  
>          final OptionalPackageComparator comparator =
>              new OptionalPackageComparator( extension.getExtensionName() );
>          Collections.sort( resultPackages, comparator );
>          final OptionalPackage[] resultData =
>              new OptionalPackage[ resultPackages.size() ];
>          return (OptionalPackage[])resultPackages.toArray( resultData );
>      }
>  }
>  
>  
>  
>  1.1                  avalon-phoenix/src/java/org/apache/avalon/phoenix/components/extensions/pkgmgr/impl/NoopExtensionManager.java
>  
>  Index: NoopExtensionManager.java
>  ===================================================================
>  /*
>  
>   ============================================================================
>                     The Apache Software License, Version 1.1
>   ============================================================================
>  
>   Copyright (C) 1997-2003 The Apache Software Foundation. All rights reserved.
>  
>   Redistribution and use in source and binary forms, with or without modifica-
>   tion, 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  acknowledgment:  "This product includes  software
>      developed  by the  Apache Software Foundation  (http://www.apache.org/)."
>      Alternately, this  acknowledgment may  appear in the software itself,  if
>      and wherever such third-party acknowledgments normally appear.
>  
>   4. The names "Avalon", "Phoenix" 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 name,  without prior written permission  of the
>      Apache Software Foundation.
>  
>   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 (INCLU-
>   DING, 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 <http://www.apache.org/>.
>  
>  */
>  package org.apache.avalon.phoenix.components.extensions.pkgmgr.impl;
>  
>  import org.apache.avalon.excalibur.extension.Extension;
>  import org.apache.avalon.phoenix.components.extensions.pkgmgr.ExtensionManager;
>  import org.apache.avalon.phoenix.components.extensions.pkgmgr.OptionalPackage;
>  
>  /**
>   * A Noop ExtensionManager that can't provide any extensions.
>   * This is for use in certain environments (ala Servlets) that
>   * require apps to be be self-contained.
>   *
>   * @author <a href="mailto:peter at apache.org">Peter Donald</a>
>   * @version $Revision: 1.1 $ $Date: 2003/04/30 10:03:52 $
>   */
>  public class NoopExtensionManager
>      implements ExtensionManager
>  {
>      /**
>       * Return an empty array of {@link OptionalPackage}s.
>       *
>       * @param extension the extension looking for
>       * @see ExtensionManager#getOptionalPackages
>       */
>      public OptionalPackage[] getOptionalPackages( final Extension extension )
>      {
>          return new OptionalPackage[ 0 ];
>      }
>  }
>  
>  
>  
>  1.1                  avalon-phoenix/src/java/org/apache/avalon/phoenix/components/extensions/pkgmgr/impl/OptionalPackageComparator.java
>  
>  Index: OptionalPackageComparator.java
>  ===================================================================
>  /*
>  
>   ============================================================================
>                     The Apache Software License, Version 1.1
>   ============================================================================
>  
>   Copyright (C) 1997-2003 The Apache Software Foundation. All rights reserved.
>  
>   Redistribution and use in source and binary forms, with or without modifica-
>   tion, 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  acknowledgment:  "This product includes  software
>      developed  by the  Apache Software Foundation  (http://www.apache.org/)."
>      Alternately, this  acknowledgment may  appear in the software itself,  if
>      and wherever such third-party acknowledgments normally appear.
>  
>   4. The names "Avalon", "Phoenix" 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 name,  without prior written permission  of the
>      Apache Software Foundation.
>  
>   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 (INCLU-
>   DING, 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 <http://www.apache.org/>.
>  
>  */
>  package org.apache.avalon.phoenix.components.extensions.pkgmgr.impl;
>  
>  import java.util.Comparator;
>  import org.apache.avalon.excalibur.extension.DeweyDecimal;
>  import org.apache.avalon.excalibur.extension.Extension;
>  import org.apache.avalon.phoenix.components.extensions.pkgmgr.OptionalPackage;
>  
>  /**
>   * A simple class to compare two extensions and sort them
>   * on spec version and then on impl version. Unspecified
>   * versions rate lower than specified versions.
>   *
>   * @author <a href="mailto:peter at apache.org">Peter Donald</a>
>   * @version $Revision: 1.1 $ $Date: 2003/04/30 10:03:52 $
>   */
>  class OptionalPackageComparator
>      implements Comparator
>  {
>      /**
>       * The name of extension the comparator is working with.
>       */
>      private final String m_name;
>  
>      public OptionalPackageComparator( final String name )
>      {
>          if( null == name )
>          {
>              throw new NullPointerException( "name" );
>          }
>  
>          m_name = name;
>      }
>  
>      public int compare( final Object o1,
>                          final Object o2 )
>      {
>          final OptionalPackage pkg1 = (OptionalPackage)o1;
>          final OptionalPackage pkg2 = (OptionalPackage)o2;
>          final Extension e1 = getMatchingExtension( pkg1 );
>          final Extension e2 = getMatchingExtension( pkg2 );
>          int result = compareSpecVersion( e1, e2 );
>          if( 0 != result )
>          {
>              return result;
>          }
>          else
>          {
>              return compareImplVersion( e1, e2 );
>          }
>      }
>  
>      private Extension getMatchingExtension( final OptionalPackage pkg )
>      {
>          final Extension[] extensions = pkg.getAvailableExtensions();
>          for( int i = 0; i < extensions.length; i++ )
>          {
>              final Extension extension = extensions[ i ];
>              if( extension.getExtensionName().equals( m_name ) )
>              {
>                  return extension;
>              }
>          }
>  
>          final String message = "Unable to locate extension " +
>              m_name + " in package " + pkg;
>          throw new IllegalStateException( message );
>      }
>  
>      private int compareImplVersion( final Extension e1, final Extension e2 )
>      {
>          final String implVersion1 = e1.getImplementationVersion();
>          final String implVersion2 = e2.getImplementationVersion();
>          if( null == implVersion1 && null == implVersion2 )
>          {
>              return 0;
>          }
>          else if( null != implVersion1 && null == implVersion2 )
>          {
>              return -1;
>          }
>          else if( null == implVersion1 && null != implVersion2 )
>          {
>              return 1;
>          }
>          else
>          {
>              return -implVersion1.compareTo( implVersion2 );
>          }
>      }
>  
>      private int compareSpecVersion( final Extension e1,
>                                      final Extension e2 )
>      {
>          final DeweyDecimal specVersion1 = e1.getSpecificationVersion();
>          final DeweyDecimal specVersion2 = e2.getSpecificationVersion();
>          if( null == specVersion1 && null == specVersion2 )
>          {
>              return 0;
>          }
>          else if( null != specVersion1 && null == specVersion2 )
>          {
>              return -1;
>          }
>          else if( null == specVersion1 && null != specVersion2 )
>          {
>              return 1;
>          }
>          else
>          {
>              if( specVersion1.isEqual( specVersion2 ) )
>              {
>                  return 0;
>              }
>              else if( specVersion1.isGreaterThan( specVersion2 ) )
>              {
>                  return -1;
>              }
>              else
>              {
>                  return 1;
>              }
>          }
>      }
>  }
>  
>  
>  
>
>---------------------------------------------------------------------
>To unsubscribe, e-mail: cvs-unsubscribe@avalon.apache.org
>For additional commands, e-mail: cvs-help@avalon.apache.org
>
>
>
>  
>

-- 

Stephen J. McConnell
mailto:mcconnell@apache.org
http://www.osm.net

Sent via James running under Merlin as an NT service.



---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@avalon.apache.org
For additional commands, e-mail: dev-help@avalon.apache.org