You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@avalon.apache.org by do...@apache.org on 2001/02/24 04:59:43 UTC

cvs commit: jakarta-avalon/src/java/org/apache/avalon/util/thread DefaultThreadManager.java ThreadContext.java ThreadManager.java ThreadPool.java WorkerThread.java

donaldp     01/02/23 19:59:43

  Added:       src/java/org/apache/avalon/util ArrayEnumeration.java
                        ArrayStack.java BinaryHeap.java Circuit.java
                        CircularBuffer.java
                        CircularDependencyException.java
                        DependencyGraph.java Enum.java
                        IteratorEnumeration.java ListUtils.java Lock.java
                        LockException.java ObjectUtil.java Primes.java
                        PriorityQueue.java PropertyException.java
                        PropertyUtil.java ProxyClassLoader.java
                        ProxyGenerator.java StringUtil.java ValuedEnum.java
                        Version.java
               src/java/org/apache/avalon/util/cli AbstractMain.java
                        AbstractParserControl.java CLArgsParser.java
                        CLOption.java CLOptionDescriptor.java CLUtil.java
                        ParserControl.java
               src/java/org/apache/avalon/util/cli/test ClutilTestlet.java
               src/java/org/apache/avalon/util/datasource
                        DataSourceComponent.java J2eeDataSource.java
                        JdbcConnection.java JdbcConnectionPool.java
                        JdbcDataSource.java
               src/java/org/apache/avalon/util/datasource/test
                        DataSourceTestlet.java
               src/java/org/apache/avalon/util/i18n ResourceGroup.java
                        XMLResourceBundle.java
                        XMLResourceBundleFactory.java XPathAPI.java
               src/java/org/apache/avalon/util/internet
                        CRLFInputStream.java CRLFOutputStream.java
                        InternetException.java InternetReply.java
                        InternetStream.java LineReader.java LineWriter.java
               src/java/org/apache/avalon/util/io
                        ByteTerminatedInputStream.java
                        DirectoryFileFilter.java ExtensionFileFilter.java
                        FileUtil.java IOUtil.java MergedInputStreams.java
                        ResettableFileInputStream.java
               src/java/org/apache/avalon/util/io/test FileUtilTestlet.java
               src/java/org/apache/avalon/util/lang ThreadManager.java
               src/java/org/apache/avalon/util/log AvalonLogFormatter.java
                        DefaultLogManager.java
               src/java/org/apache/avalon/util/pool AbstractPool.java
                        DefaultObjectFactory.java DefaultPool.java
                        ObjectFactory.java Pool.java PoolController.java
                        ThreadSafePool.java
               src/java/org/apache/avalon/util/pool/test PoolProfile.java
               src/java/org/apache/avalon/util/security AbstractPolicy.java
                        DefaultPolicy.java PolicyClassLoader.java
               src/java/org/apache/avalon/util/test BinaryHeapTestlet.java
                        DependencyGraphTestlet.java
                        PropertyUtilTestlet.java ProxyGeneratorTestlet.java
                        StringUtilTestlet.java
               src/java/org/apache/avalon/util/thread
                        DefaultThreadManager.java ThreadContext.java
                        ThreadManager.java ThreadPool.java
                        WorkerThread.java
  Log:
  Rechecked in util sub-directory
  
  Revision  Changes    Path
  1.1                  jakarta-avalon/src/java/org/apache/avalon/util/ArrayEnumeration.java
  
  Index: ArrayEnumeration.java
  ===================================================================
  /* 
   * Copyright (C) The Apache Software Foundation. All rights reserved. 
   * 
   * This software is published under the terms of the Apache Software License 
   * version 1.1, a copy of which has been included with this distribution in 
   * the LICENSE file. 
   */ 
  package org.apache.avalon.util;
  
  import java.util.Enumeration;
  import java.util.List;
  import java.util.NoSuchElementException;
  
  /**
   * Enumeration wrapper for array.
   *
   * @author <a href="mailto:donaldp@apache.org">Peter Donald</a>
   */
  public final class ArrayEnumeration 
      implements Enumeration
  {
      protected Object[]       m_elements;
      protected int            m_index;
  
      public ArrayEnumeration( final List elements )
      {
          m_elements = elements.toArray();
      }
  
      public ArrayEnumeration( final Object[] elements )
      {
          m_elements = elements;
      }
  
      public boolean hasMoreElements()
      {
          return ( m_index < m_elements.length );
      }
  
      public Object nextElement()
      {
          if( !hasMoreElements() ) 
          {
              throw new NoSuchElementException("No more elements exist");
          }
  
          return m_elements[ m_index++ ];
      }
  }
  
  
  
  
  1.1                  jakarta-avalon/src/java/org/apache/avalon/util/ArrayStack.java
  
  Index: ArrayStack.java
  ===================================================================
  /* 
   * Copyright (C) The Apache Software Foundation. All rights reserved. 
   * 
   * This software is published under the terms of the Apache Software License 
   * version 1.1, a copy of which has been included with this distribution in 
   * the LICENSE file. 
   */ 
  package org.apache.avalon.util;
  
  import java.util.ArrayList;
  import java.util.EmptyStackException;
  
  /**
   * Unsynchronized stakc.
   *
   * @author <a href="mailto:donaldp@apache.org">Peter Donald</a>
   */
  public class ArrayStack 
      extends ArrayList
  {
  	public void setSize( final int size )
      {
  	    if( 0 == size ) clear();
  	    else 
          {
              removeRange( size, size() - 1 );
  	    }
  	}
  
      /**
       * Adds the object to the top of the stack.
       *
       * @param element object to add to stack
       * @return the object
       */
      public Object push( final Object element )
      {
  	    add( element );
  	    return element;
  	}
  
  	/**
       * Remove element from top of stack and return it
       *
       * @return the element from stack
       * @exception EmptyStackException if no elements left on stack
       */
      public Object pop()
          throws EmptyStackException 
      {
          final int size = size();
          if( 0 == size ) throw new EmptyStackException();
  
          return remove( size - 1 );
  	}
  }
  
  
  
  
  1.1                  jakarta-avalon/src/java/org/apache/avalon/util/BinaryHeap.java
  
  Index: BinaryHeap.java
  ===================================================================
  /* 
   * Copyright (C) The Apache Software Foundation. All rights reserved. 
   * 
   * This software is published under the terms of the Apache Software License 
   * version 1.1, a copy of which has been included with this distribution in 
   * the LICENSE file. 
   */ 
  package org.apache.avalon.util;
  
  import java.util.NoSuchElementException;
  
  /**
   * Iterface for priority queues.
   * This interface does not dictate whether it is min or max heap.
   *
   * @author  <a href="mailto:donaldp@apache.org">Peter Donald</a> 
   */
  public final class BinaryHeap 
      implements PriorityQueue
  {
      protected final static int      DEFAULT_CAPACITY   = 13;
  
      protected int                   m_size;
      protected Comparable[]          m_elements;
      protected boolean               m_isMinHeap;
  
      public BinaryHeap()
      {
          this( DEFAULT_CAPACITY, true );
      }
  
      public BinaryHeap( final int capacity )
      {
          this( capacity, true );
      }
  
      public BinaryHeap( final boolean isMinHeap )
      {
          this( DEFAULT_CAPACITY, isMinHeap );
      }
  
      public BinaryHeap( final int capacity, final boolean isMinHeap )
      {
          m_isMinHeap = isMinHeap;
  
          //+1 as 0 is noop
          m_elements = new Comparable[ capacity + 1 ];
      }
  
      /**
       * Clear all elements from queue.
       */
      public void clear()
      {
          m_size = 0;
      }
  
      /**
       * Test if queue is empty.
       *
       * @return true if queue is empty else false.
       */
      public boolean isEmpty()
      {
          return ( 0 == m_size );
      }
  
      /**
       * Test if queue is full.
       *
       * @return true if queue is full else false.
       */
      public boolean isFull()
      {
          return ( m_elements.length == m_size );
      }
  
      /**
       * Insert an element into queue.
       *
       * @param element the element to be inserted
       */
      public void insert( final Comparable element )
      {
          if( isFull() ) grow();
  
          //percolate element to it's place in tree
          if( m_isMinHeap ) percolateUpMinHeap( element );
          else percolateUpMaxHeap( element );
      }
  
      /**
       * Return element on top of heap but don't remove it.
       *
       * @return the element at top of heap
       * @exception NoSuchElementException if isEmpty() == true
       */
      public Comparable peek() throws NoSuchElementException
      {
          if( isEmpty() ) throw new NoSuchElementException();
          else return m_elements[ 1 ];
      }
  
      /**
       * Return element on top of heap and remove it.
       *
       * @return the element at top of heap
       * @exception NoSuchElementException if isEmpty() == true
       */
      public Comparable pop() throws NoSuchElementException
      {
          final Comparable result = peek();
          m_elements[ 1 ] = m_elements[ m_size-- ];
  
          if( m_size != 0 )
          {
              //percolate top element to it's place in tree
              if( m_isMinHeap ) percolateDownMinHeap( 1 );
              else percolateDownMaxHeap( 1 );
          }
  
          return result;
      }
  
      /**
       * Percolate element down heap from top. 
       * Assume it is a maximum heap.
       *
       * @param element the element
       */
      protected void percolateDownMinHeap( final int index )
      {
          final Comparable element = m_elements[ index ];
  
          int hole = index;
  
          while( (hole * 2) <= m_size )
          {
              int child = hole * 2;
  
              //if we have a right child and that child can not be percolated
              //up then move onto other child
              if( child != m_size && 
                  m_elements[ child + 1 ].compareTo( m_elements[ child ] ) < 0 )
              {
                  child++;
              }
  
              //if we found resting place of bubble then terminate search
              if( m_elements[ child ].compareTo( element ) >= 0 )
              {
                  break;
              }
  
              m_elements[ hole ] = m_elements[ child ];
              hole = child;
          }
          
          m_elements[ hole ] = element;
      }
  
      /**
       * Percolate element down heap from top. 
       * Assume it is a maximum heap.
       *
       * @param element the element
       */
      protected void percolateDownMaxHeap( final int index )
      {
          final Comparable element = m_elements[ index ];
  
          int hole = index;
  
          while( (hole * 2) <= m_size )
          {
              int child = hole * 2;
  
              //if we have a right child and that child can not be percolated
              //up then move onto other child
              if( child != m_size && 
                  m_elements[ child + 1 ].compareTo( m_elements[ child ] ) > 0 )
              {
                  child++;
              }
  
              //if we found resting place of bubble then terminate search
              if( m_elements[ child ].compareTo( element ) <= 0 )
              {
                  break;
              }
  
              m_elements[ hole ] = m_elements[ child ];
              hole = child;
          }
          
          m_elements[ hole ] = element;
      }
  
      /**
       * Percolate element up heap from bottom. 
       * Assume it is a maximum heap.
       *
       * @param element the element
       */
      protected void percolateUpMinHeap( final Comparable element )
      {
          int hole = ++m_size;
          
          m_elements[ hole ] = element;
  
          while( hole > 1 &&
                 element.compareTo( m_elements[ hole / 2 ] ) < 0 )
          {
              //save element that is being pushed down
              //as the element "bubble" is percolated up
              final int next = hole / 2;
              m_elements[ hole ] = m_elements[ next ];
              hole = next;
          }
  
          m_elements[ hole ] = element;
      }
  
      /**
       * Percolate element up heap from bottom. 
       * Assume it is a maximum heap.
       *
       * @param element the element
       */
      protected void percolateUpMaxHeap( final Comparable element )
      {
          int hole = ++m_size;
  
          while( hole > 1 &&
                 element.compareTo( m_elements[ hole / 2 ] ) > 0 )
          {
              //save element that is being pushed down
              //as the element "bubble" is percolated up
              final int next = hole / 2;
              m_elements[ hole ] = m_elements[ next ];
              hole = next;
          }
  
          m_elements[ hole ] = element;
      }
  
      protected void grow()
      {
          final Comparable[] elements = 
              new Comparable[ m_elements.length * 2 ]; 
          System.arraycopy( m_elements, 0, elements, 0, m_elements.length );
          m_elements = elements;
      }
  
      public String toString()
      {
          final StringBuffer sb = new StringBuffer();
  
          sb.append( "[ " );
  
          for( int i = 1; i < m_size + 1; i++ )
          {
              if( i != 1 ) sb.append( ", " );
              sb.append( m_elements[ i ] );
          }
  
          sb.append( " ]" );
  
          return sb.toString();
      }
  }
  
  
  
  
  1.1                  jakarta-avalon/src/java/org/apache/avalon/util/Circuit.java
  
  Index: Circuit.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE file.
   */
  package org.apache.avalon.util;
  
  import java.util.Enumeration;
  import java.util.Hashtable;
  import java.util.Vector;
  
  /**
   *
   * @version 0.0.20, 04/07/1998
   * @author  Federico Barbieri <fe...@apache.org>
   * @author  Stefano Mazzocchi <ma...@mbox.systemy.it>
   */
  public class Circuit
  {
      protected Hashtable m_map;
  
      public Circuit() 
      {
          m_map = new Hashtable();
      }
  
      public void addNode( final String name )
      {
          if( null == m_map.get( name ) )
          {
              m_map.put( name, new Node( name ) );
          }
      }
  
      public void removeNode( final String name )
      {
          String tmp = null;
          Enumeration e = m_map.keys();
          
          while( e.hasMoreElements() )
          {
              tmp = (String)e.nextElement();
              
              if( !tmp.equals( name ) )
              {
                  try { unlink( tmp, name ); } 
                  catch( final CircuitException ce) {}
                  try { unlink( name, tmp ); } 
                  catch( final CircuitException ce ) {}
              }
              
          }
          
          m_map.remove( name );
      }
  
      public void link( final String parent, final String child )
          throws CircuitException
      {
          Node tempNode = null;
          Node pnode = (Node)m_map.get( parent );
          Node cnode = (Node)m_map.get( child );
          if( null == pnode ) 
          {
              throw new CircuitException( "Unknown node " + parent );
          } 
          else if( null == cnode )
          {
              throw new CircuitException( "Unknown node " + child );
          } 
          else if( pnode.isChildOf( cnode ) )
          {
              throw new CircuitException( "Loop! Node " + parent + 
                                          " is already child of node " + child );
          } 
          else
          {
              final Enumeration e = m_map.elements();
  
              while( e.hasMoreElements() )
              {
                  tempNode = (Node)e.nextElement();
                  if( tempNode.isChildOf( cnode ) )
                  {
                      tempNode.m_parents.addAll( pnode.m_parents );
                  }
              }
          }
      }
  
      public void unlink( final String parent, final String child )
          throws CircuitException 
      {
          Node cnode = (Node)m_map.get( child );
          Node pnode = (Node)m_map.get( parent );
  
          if( cnode.m_parents.contains( pnode ) )
          {
              Node tempNode = null;
              Enumeration e = m_map.elements();
  
              while( e.hasMoreElements() )
              {
                  tempNode = (Node)e.nextElement();
  
                  if( tempNode.m_parents.contains( cnode ) )
                  {
                      tempNode.m_parents.removeAll( pnode.m_parents );
                  }
              }
          } 
          else
          {
              throw new CircuitException( "Node " + parent + " is not parent of node " + child );
          }
      }
  
      public Vector getAncestors() 
      {
          Vector ancestors = new Vector();
          String name = null;
          Node tempNode = null;
          Enumeration e = m_map.keys();
  
          while( e.hasMoreElements() )
          {
              name = (String)e.nextElement();
              tempNode = (Node)m_map.get( name );
  
              if( 1 == tempNode.m_parents.size() )
              {
                  ancestors.addElement( name );
              }
          }
  
          return ancestors;
      }
  
      public String getAncestor() 
      {
          String name = null;
          Node tempNode = null;
          Enumeration e = m_map.keys();
  
          while( e.hasMoreElements() )
          {
              name = (String)e.nextElement();
              tempNode = (Node)m_map.get( name );
  
              if( 1 == tempNode.m_parents.size() )
              {
                  return name;
              }
          }
  
          return null;
      }
      
      public boolean isEmpty() 
      {
          return m_map.isEmpty();
      }
      
      protected final class Node 
      {
          protected Vector m_parents;
          protected String m_name;
      
          protected Node( final String name )
          {
              m_parents = new Vector( 5 );
              m_parents.addElement( this );
              m_name = name;
          }
              
          protected boolean isChildOf( final Node parent ) 
          {
              return m_parents.contains( parent );
          }
              
          public String toString() 
          {
              StringBuffer buffer = new StringBuffer();
              Enumeration e = m_parents.elements();
              buffer.append( m_name + "[" );
              
              while( e.hasMoreElements() )
              {
                  buffer.append(((Node) e.nextElement()).m_name + " ");
              }
  
              buffer.append("]");
              return buffer.toString();
          }
      }
      
      public final class CircuitException 
          extends RuntimeException
      {
          public CircuitException()
          {
          }
          
          public CircuitException( final String message )
          {
              super( message );
          }
      }
      
      public String toString() 
      {
          StringBuffer buffer = new StringBuffer();
          String name = null;
          Node tempNode = null;
          Enumeration e = m_map.keys();
  
          while( e.hasMoreElements() )
          {
              name = (String)e.nextElement();
              tempNode = (Node)m_map.get( name );
              buffer.append( name + "(" + ( tempNode.m_parents.size() - 1 ) + ") " );
          }
  
          return buffer.toString();
      }
  }
  
  
  
  
  1.1                  jakarta-avalon/src/java/org/apache/avalon/util/CircularBuffer.java
  
  Index: CircularBuffer.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE file.
   */
  package org.apache.avalon.util;
  
  /**
   *
   * @author  Federico Barbieri <fe...@apache.org>
   */
  public class CircularBuffer
  {
      protected Object[]   m_buffer;
      protected int        m_bufferSize;
      protected int        m_contentSize;
      protected int        m_head;
      protected int        m_tail;
  
      public CircularBuffer( int size )
      {
          m_buffer = new Object[size];
          m_bufferSize = size;
          m_contentSize = 0;
          m_head = 0;
          m_tail = 0;
      }
  
      public CircularBuffer() 
      {
          this( 32 );
      }
  
      public boolean isEmpty() 
      {
          return (m_contentSize == 0);
      }
  
      public int getContentSize() 
      {
          return m_contentSize;
      }
  
      public int getBufferSize() 
      {
          return m_bufferSize;
      }
  
      public void append( final Object o )
      {
          if( m_contentSize >= m_bufferSize )
          {
              int j = 0;
              int i = m_tail;
              Object[] tmp = new Object[ m_bufferSize * 2 ];
              
              while( m_contentSize > 0 )
              {
                  i++;
                  i %= m_bufferSize;
                  j++;
                  m_contentSize--;
                  tmp[ j ] = m_buffer[ i ];
              }
              m_buffer = tmp;
              m_tail = 0;
              m_head = j;
              m_contentSize = j;
              m_bufferSize *= 2;
          }
          
          m_buffer[ m_head ] = o;
          m_head++;
          m_head %= m_bufferSize;
          m_contentSize++;
      }
  
      public Object get() 
      {
          if( m_contentSize <= 0 )
          {
              return null;
          }
  
          Object o = m_buffer[ m_tail ];
          m_tail++;
          m_tail %= m_bufferSize;
          m_contentSize--;
          return o;
      }
  }
  
  
  
  
  1.1                  jakarta-avalon/src/java/org/apache/avalon/util/CircularDependencyException.java
  
  Index: CircularDependencyException.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE file.
   */
  package org.apache.avalon.util;
  
  import java.util.List;
  import org.apache.avalon.CascadingException;
  
  /**
   *
   * @author <a href="mailto:donaldp@apache.org">Peter Donald</a> 
   */
  public class CircularDependencyException
      extends CascadingException
  {
      protected List   m_stack;
  
      public CircularDependencyException( final String dependee, 
                                          final String dependent, 
                                          final List stack )
      {
          super( dependee + " depends upon " + dependent + " which depends upong " + dependee );
          m_stack = stack;
      }
      
      public List getStack()
      {
          return m_stack;
      }
  }
  
  
  
  1.1                  jakarta-avalon/src/java/org/apache/avalon/util/DependencyGraph.java
  
  Index: DependencyGraph.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE file.
   */
  package org.apache.avalon.util;
  
  import java.util.ArrayList;
  import java.util.HashMap;
  import java.util.Iterator;
  import java.util.List;
  
  /**
   * DirectedGraph is a acyclic Directed graph implementation.  
   *
   * @author <a href="mailto:donaldp@apache.org">Peter Donald</a> 
   */
  public class DependencyGraph 
  {
      protected final HashMap  m_map               = new HashMap();
      protected boolean        m_allowCircularity  = true;      
  
      public void setAllowCircularity( final boolean allowCircularity )
      {
          m_allowCircularity = allowCircularity;
      }
  
      public void add( final String name, final String[] dependencies )
      {
          m_map.put( name, new GraphNode( name, dependencies ) );
      }
      
      public void remove( final String name ) 
      {
          m_map.remove( name );
      }
  
      public Dependency[] getDependencyList( final String name )
          throws CircularDependencyException
      {
          final ArrayList list = new ArrayList();
          final Dependency dependency = new Dependency( name , null );
          list.add( dependency );
  
          if( null != m_map.get( name ) )
          {
              final ArrayList stack = new ArrayList();
              stack.add( name );
              buildDependencyList( name, list, new ArrayList(), stack );
          }
  
          return (Dependency[])list.toArray( new Dependency[ 0 ] );        
      }
  
      protected void buildDependencyList( final String name, 
                                          final ArrayList list, 
                                          final ArrayList done,
                                          final ArrayList stack )
          throws CircularDependencyException
      {
          if( done.contains( name ) ) return;
          done.add( name );
  
          final GraphNode node = (GraphNode)m_map.get( name );
          if( null == node ) return;
  
          final String[] dependencies = node.getDependencies();
          for( int i = 0; i < dependencies.length; i++ )
          {
              if( stack.contains( dependencies[ i ] ) )
              {
                  if( m_allowCircularity ) continue;
                  else
                  {
                      throw new CircularDependencyException( dependencies[ i ], name, stack );
                  }
              }
  
              if( done.contains( dependencies[ i ] ) ) continue;
   
              final Dependency dependency = new Dependency( dependencies[ i ], name );
              list.add( dependency );
  
              stack.add( dependencies[ i ] );
              buildDependencyList( dependencies[ i ], list, done, stack );
              stack.remove( stack.size() - 1 );
          }        
      }
  
      public final static class Dependency
      {
          protected final String       m_name;
          protected final String       m_requiredBy;
  
          protected Dependency( final String name, final String requiredBy )
          {
              m_name = name;
              m_requiredBy = requiredBy;
          }
  
          public String getName()
          {
              return m_name;
          }
  
          public String getRequiredBy()
          {
              return m_requiredBy;
          }
          
          public String toString()
          {
              return getName();
          }
      }
  
      protected final static class GraphNode 
      {
          protected final String     m_name;
          protected final String[]   m_dependencies;
  
          protected GraphNode( final String name, final String[] dependencies ) 
          {
              m_name = name;
              m_dependencies = dependencies;
          }
  
          public String getName()
          {
              return m_name;
          }
  
          public String[] getDependencies()
          {
              return m_dependencies;
          }
      }
  }
  
  
  
  1.1                  jakarta-avalon/src/java/org/apache/avalon/util/Enum.java
  
  Index: Enum.java
  ===================================================================
  /* 
   * Copyright (C) The Apache Software Foundation. All rights reserved. 
   * 
   * This software is published under the terms of the Apache Software License 
   * version 1.1, a copy of which has been included with this distribution in 
   * the LICENSE file. 
   */ 
  package org.apache.avalon.util;
  
  import java.util.Map;
  
  /**
   * Basic enum class for type-safe enums. Should be used as an abstract base.
   *
   * @author <a href="mailto:donaldp@apache.org">Peter Donald</a>
   */
  public abstract class Enum 
  {
      protected final String        m_name;
      
      public Enum( final String name )
      {
          this( name, null );
      } 
   
      public Enum( final String name, final Map map )
      {
          m_name = name;
          if( null != map )
          {
              map.put( name, this );
          }
      } 
  
      public final String getName()
      {
          return m_name;
      }
      
      public String toString()
      {
          return getClass().getName() + "[" + m_name + "]";
      }
  }
  
  
  
  1.1                  jakarta-avalon/src/java/org/apache/avalon/util/IteratorEnumeration.java
  
  Index: IteratorEnumeration.java
  ===================================================================
  /* 
   * Copyright (C) The Apache Software Foundation. All rights reserved. 
   * 
   * This software is published under the terms of the Apache Software License 
   * version 1.1, a copy of which has been included with this distribution in 
   * the LICENSE file. 
   */ 
  package org.apache.avalon.util;
  
  import java.util.Enumeration;
  import java.util.Iterator;
  import java.util.NoSuchElementException;
  
  /**
   * Enumeration wrapper for iterator.
   *
   * @author <a href="mailto:donaldp@apache.org">Peter Donald</a>
   */
  public final class IteratorEnumeration 
      implements Enumeration
  {
      protected Iterator       m_iterator;
  
      public IteratorEnumeration( final Iterator iterator )
      {
          m_iterator = iterator;
      }
  
      public boolean hasMoreElements()
      {
          return m_iterator.hasNext();
      }
  
      public Object nextElement()
      {
          return m_iterator.next();
      }
  }
  
  
  
  
  1.1                  jakarta-avalon/src/java/org/apache/avalon/util/ListUtils.java
  
  Index: ListUtils.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE file.
   */
  package org.apache.avalon.util;
  
  import java.util.ArrayList;
  import java.util.Iterator;
  import java.util.List;
  
  /**
   * Miscelaneous utilities to manipulate Lists.
   *
   * @author  <a href="mailto:fede@apache.org">Federico Barbieri</a>
   * @author  <a href="mailto:donaldp@apache.org">Peter Donald</a>
   */
  public class ListUtils
  {
      public static List intersection( final List list1, final List list2 ) 
      {
          final ArrayList result = new ArrayList();
          final Iterator iterator = list2.iterator();
  
          while( iterator.hasNext() ) 
          {
              final Object o = iterator.next();
  
              if ( list1.contains( o ) ) 
              {
                  result.add( o );
              }
          }
  
          return result;
      }
      
      public static List subtract( final List list1, final List list2 ) 
      {
          final ArrayList result = new ArrayList( list1 );
          final Iterator iterator = list2.iterator();
  
          while( iterator.hasNext() ) 
          {
              result.remove( iterator.next() );
          }
  
          return result;
      }
      
      public static List sum( final List list1, final List list2 ) 
      {
          return subtract( union( list1, list2 ), 
                           intersection( list1, list2 ) );
      }
      
      public static List union( final List list1, final List list2 ) 
      {
          final ArrayList result = new ArrayList( list1 );
          result.addAll( list2 );
          return result;
      }
  }
  
  
  
  1.1                  jakarta-avalon/src/java/org/apache/avalon/util/Lock.java
  
  Index: Lock.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE file.
   */
  package org.apache.avalon.util;
  
  import java.util.Hashtable;
  
  /**
   * @author Federico Barbieri <fe...@apache.org>
   */
  public class Lock
  {
      private Hashtable locks = new Hashtable();
  
      public boolean isLocked( final Object key )
      {
          return (locks.get(key) != null);
      }
  
      public boolean canI( final Object key )
      {
          Object o = locks.get( key );
  
          if( null == o || o == this.getCallerId() )
          {
              return true;
          }
  
          return false;
      }
  
      public boolean lock( final Object key )
      {
          Object theLock;
          
          synchronized( this )
          {
              theLock = locks.get( key );
          }
  
          if( null == theLock )
          {
              locks.put( key, getCallerId() );
              return true;
          } 
          else if( getCallerId() == theLock )
          {
              return true;
          } 
          else
          {
              return false;
          }
      }
  
      public boolean unlock( final Object key ) 
      {
          Object theLock;
          synchronized( this )
          {
              theLock = locks.get( key );
          }
  
          if( null == theLock )
          {
              return true;
          } 
          else if( getCallerId() == theLock )
          {
              locks.remove( key );
              return true;
          } 
          else
          {
              return false;
          }
      }
  
      private Object getCallerId() 
      {
          return Thread.currentThread();
      }
  }
  
  
  
  1.1                  jakarta-avalon/src/java/org/apache/avalon/util/LockException.java
  
  Index: LockException.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE file.
   */
  package org.apache.avalon.util;
  
  public class LockException 
      extends RuntimeException
  {
      public LockException( final String message )
      {
          super( message );
      }
      
      public LockException() 
      {
      }
  }
  
  
  
  1.1                  jakarta-avalon/src/java/org/apache/avalon/util/ObjectUtil.java
  
  Index: ObjectUtil.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE file.
   */
  package org.apache.avalon.util;
  
  /**
   * This class provides basic facilities for manipulating objects.
   *
   * @author <a href="mailto:donaldp@apache.org">Peter Donald</a>
   */
  public final class ObjectUtil
  {
      /**
       * Private constructor to prevent instantiation.
       */
      private ObjectUtil()
      {
      }
  
      public static boolean isEqual( final Object o1, final Object o2 )
      {
          if( null == o1 )
          {
              if( null == o2 ) 
              {
                  return true;
              }
              else
              {
                  return false;
              }
          }
          else if( null == o2 )
          {
              return false;
          }
          else 
          {
              return o1.equals( o2 );
          }
      }
  
      public static Object createObject( final ClassLoader classLoader, final String classname )
          throws ClassNotFoundException, InstantiationException, IllegalAccessException
      {
          final Class clazz = classLoader.loadClass( classname );
          return clazz.newInstance();
      }
  
      
      public static Object createObject( final String classname )
          throws ClassNotFoundException, InstantiationException, IllegalAccessException
      {
          final Class clazz = Class.forName( classname );
          return clazz.newInstance();
      }
  }
  
  
  
  1.1                  jakarta-avalon/src/java/org/apache/avalon/util/Primes.java
  
  Index: Primes.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included  with this distribution in
   * the LICENSE file.
   */
  package org.apache.avalon.util;
  
  /**
   *
   * @author  Federico Barbieri <fe...@apache.org>
   * @author  Stefano Mazzocchi <ma...@mbox.systemy.it>
   */
  public class Primes
  {
      /**
       * Last prime found.
       *
       */
      protected static long                c_lastPrime              = 1;
  
      /**
       * Return next prime.
       *
       */
      public static long nextPrime() 
      {
          long l = c_lastPrime + 1;
          long v = 2;
  
          while( true )
          {
              l++;
                  
              while( v < l )
              {
                  v++;
  
                  if( (l % v) == 0 )
                  {
                      v = 0;
                      break;
                  }
              } // while v < l
                  
              if( v == l )
              {
                  c_lastPrime = l;
                  return l;
              } // if v is l
          } // while true (break is used to escape)
      }
  }
  
  
  
  1.1                  jakarta-avalon/src/java/org/apache/avalon/util/PriorityQueue.java
  
  Index: PriorityQueue.java
  ===================================================================
  /* 
   * Copyright (C) The Apache Software Foundation. All rights reserved. 
   * 
   * This software is published under the terms of the Apache Software License 
   * version 1.1, a copy of which has been included with this distribution in 
   * the LICENSE file. 
   */ 
  package org.apache.avalon.util;
  
  import java.util.NoSuchElementException;
  
  /**
   * Iterface for priority queues.
   * This interface does not dictate whether it is min or max heap.
   *
   * @author  <a href="mailto:donaldp@apache.org">Peter Donald</a> 
   */
  public interface PriorityQueue
  {
      /**
       * Clear all elements from queue.
       */
      void clear();
  
      /**
       * Test if queue is empty.
       *
       * @return true if queue is empty else false.
       */
      boolean isEmpty();
  
      /**
       * Insert an element into queue.
       *
       * @param element the element to be inserted
       */
      void insert( Comparable element );
  
      /**
       * Return element on top of heap but don't remove it.
       *
       * @return the element at top of heap
       * @exception NoSuchElementException if isEmpty() == true
       */
      Comparable peek() throws NoSuchElementException;
  
      /**
       * Return element on top of heap and remove it.
       *
       * @return the element at top of heap
       * @exception NoSuchElementException if isEmpty() == true
       */
      Comparable pop() throws NoSuchElementException;
  }
  
  
  
  
  1.1                  jakarta-avalon/src/java/org/apache/avalon/util/PropertyException.java
  
  Index: PropertyException.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE file.
   */
  package org.apache.avalon.util;
  
  import org.apache.avalon.CascadingException;
  
  /**
   * Thrown when a property can not be resolved properly.
   *
   * @author <a href="mailto:donaldp@apache.org">Peter Donald</a>
   */
  public class PropertyException 
      extends CascadingException
  {
      /**
       * Construct a new <code>PropertyException</code> instance.
       *
       * @param message The detail message for this exception.
       */
      public PropertyException( final String message ) 
      {
          this( message, null );
      }
      
      /**
       * Construct a new <code>PropertyException</code> instance.
       *
       * @param message The detail message for this exception.
       * @param throwable the root cause of the exception
       */
      public PropertyException( final String message, final Throwable throwable ) 
      {
          super( message, throwable );
      }
  }
  
  
  
  1.1                  jakarta-avalon/src/java/org/apache/avalon/util/PropertyUtil.java
  
  Index: PropertyUtil.java
  ===================================================================
  package org.apache.avalon.util;
  
  import org.apache.avalon.Context;
  import org.apache.avalon.Resolvable;
  
  /**
   * This provides utility methods for properties.
   *
   * @author <a href="mailto:donaldp@apache.org">Peter Donald</a>
   */
  public final class PropertyUtil
  {
      private PropertyUtil()
      {
      }
      
      /**
       * Resolve property. 
       * This evaluates all property substitutions based on current context.
       *
       * @param property the property to resolve
       * @param context the context in which to resolve property
       * @param ignoreUndefined if false will throw an PropertyException if property is not found 
       * @return the reolved property
       * @exception PropertyException if an error occurs
       */
      public static Object resolveProperty( final String property, 
                                            final Context context, 
                                            final boolean ignoreUndefined )
          throws PropertyException
      {
          int start = property.indexOf( "${" );
          if( -1 == start ) return property;
          
          int end = property.indexOf( '}', start );
          if( -1 == end ) return property;
          
          final int length = property.length();
          
          if( 0 == start && end == (length - 1) )
          {
              return resolveValue( property.substring( start + 2, end ), 
                                   context, 
                                   ignoreUndefined );
          }
          
          final StringBuffer sb = new StringBuffer();
          int lastPlace = 0;
          
          while( true )
          {
              final Object value = 
                  resolveValue( property.substring( start + 2, end ), 
                                context, 
                                ignoreUndefined );
  
              sb.append( property.substring( lastPlace, start ) );
              sb.append( value );
  
              lastPlace = end + 1;
              
              start = property.indexOf( "${", end );
              if( -1 == start ) break;
              
              end = property.indexOf( '}', start );
              if( -1 == end ) break;
          }
          
          sb.append( property.substring( lastPlace, length ) );
  
          return sb.toString();
      }
      
      protected static Object resolveValue( final String key, 
                                            final Context context,
                                            final boolean ignoreUndefined )
          throws PropertyException
      {
          Object value = context.get( key );
  
          while( null != value && value instanceof Resolvable )
          {
              value = ((Resolvable)value).resolve( context );
          }
  
          if( null == value )
          {
              if( ignoreUndefined )
              {
                  return "";
              }
              else
              {
                  throw new PropertyException( "Unable to find " + key + " to expand during " + 
                                               "property resolution." );
              }
          }
  
          return value;
      }
  }
  
  
  
  1.1                  jakarta-avalon/src/java/org/apache/avalon/util/ProxyClassLoader.java
  
  Index: ProxyClassLoader.java
  ===================================================================
  /* 
   * Copyright (C) The Apache Software Foundation. All rights reserved. 
   * 
   * This software is published under the terms of the Apache Software License 
   * version 1.1, a copy of which has been included with this distribution in 
   * the LICENSE file. 
   */ 
  package org.apache.avalon.util;
  
  /**
   * Utility class to help load dynamically generated classes.
   *
   * @author <a href="mailto:donaldp@apache.org">Peter Donald</a> 
   */
  public class ProxyClassLoader 
      extends ClassLoader
  {
      public ProxyClassLoader( final ClassLoader parent )
      {
          super( parent );
      }
  
      public Class loadClass( final String name, 
                              final boolean resolve, 
                              final byte[] classData )
          throws ClassNotFoundException
      {
          final Class result =
              defineClass( name, classData, 0, classData.length );
          
          if( resolve )
          {
              resolveClass( result );
          }
          
          return result;
      }
  }
  
  
  
  
  1.1                  jakarta-avalon/src/java/org/apache/avalon/util/ProxyGenerator.java
  
  Index: ProxyGenerator.java
  ===================================================================
  /** 
   * Copyright (C) The Apache Software Foundation. All rights reserved. 
   * 
   * This software is published under the terms of the Apache Software License 
   * version 1.1, a copy of which has been included with this distribution in 
   * the LICENSE file. 
   */ 
  package org.apache.avalon.util;
  
  import gnu.bytecode.Access;
  import gnu.bytecode.ClassType;
  import gnu.bytecode.ClassTypeWriter;
  import gnu.bytecode.CodeAttr;
  import gnu.bytecode.Field;
  import gnu.bytecode.Scope;
  import gnu.bytecode.Type;
  import gnu.bytecode.Variable;
  import java.lang.reflect.Constructor;
  import java.lang.reflect.Method;
  import java.util.HashMap;
  import java.util.Iterator;
  import org.apache.log.LogKit; 
  import org.apache.log.Logger; 
  
  /**
   * A class to generate proxies for objects.
   *
   * @author <a href="mailto:donaldp@apache.org">Peter Donald</a> 
   */
  public final class ProxyGenerator
  {
      protected final static boolean    DEBUG       = false; 
      protected final static Logger     LOGGER      =  
          ( DEBUG ) ? LogKit.getLoggerFor( "ProxyGenerator" ) : null; 
  
      protected final static Object     MONITOR     = new Object();
      protected final static ClassType  BASE_CLASS  = 
          (ClassType)Type.getType( "java.lang.Object" );
  
      protected static long             c_currentId;          
  
      /**
       * Private constructor to block subclassing.
       *
       */
      private ProxyGenerator()
      {
      }
  
      /**
       * Way to generate unique id for each class.
       *
       * @return a unique id
       */
      protected static long getNextId()
      {
          synchronized( MONITOR )
          {
              return c_currentId++;
          }
      }
  
      /**
       * Generate a proxy for object with certain interfaces.
       *
       * @param object the object
       * @param interfaces[] the interfaces
       * @return the proxy object
       * @exception IllegalArgumentException if an error occurs
       */
      public static Object generateProxy( final Object object, 
                                          final Class[] interfaces )
          throws IllegalArgumentException
      {
          if( DEBUG )
          {
              LOGGER.debug( "Generating proxy for " + object.getClass().getName() );
              LOGGER.debug( "Interfaces generating:" );
  
              for( int i = 0; i < interfaces.length; i++ )
              {
                  LOGGER.debug( interfaces[ i ].getName() );
              }
          }
  
          for( int i = 0; i < interfaces.length; i++ )
          {
              if( !interfaces[ i ].isInterface() )
              {
                  throw new IllegalArgumentException( "Class " + interfaces[ i ].getName() +
                                                      " is not an interface" );
              }
              else if( !interfaces[ i ].isInstance( object ) )
              {
                  throw new IllegalArgumentException( "Object does not implement interface " +
                                                      interfaces[ i ].getName() );
              }
          }
  
          final HashMap methodSet = determineMethods( interfaces );
          
          final String classname = "org.apache.avalon.tmp.Proxy" + getNextId();
  
          if( DEBUG ) { LOGGER.debug( "Generating proxy named " + classname ); }
  
          final ClassType proxy = createProxyType( classname );
  
          //generate all interface declarations
          generateInterfaces( proxy, interfaces );
  
          final ClassType target = 
              (ClassType)Type.make( object.getClass() );
  
          target.doFixups();
  
          //generate variables/constructor
          generateBase( proxy, target );
  
          //generate methods
          final Iterator methods = methodSet.values().iterator();
          while( methods.hasNext() )
          {
              generateMethod( proxy, target, (Method)methods.next() );
          }
  
          if( DEBUG )
          {
              //help while debugging
              //ClassTypeWriter.print( target, System.out, 0 );
              //try { proxy.writeToFile( "/tmp/" + classname.replace('.','/') + ".class" ); }
              //catch( final Throwable throwable ) { throwable.printStackTrace(); }
          }
  
          proxy.doFixups();
          
          Class proxyClass = null;
          try 
          { 
              final byte[] classData = proxy.writeToArray();
  
              //extremely inneficient - must fix in future
              final ProxyClassLoader classLoader = 
                  new ProxyClassLoader( object.getClass().getClassLoader() );
              
              proxyClass = classLoader.loadClass( classname, true, classData );
              final Constructor ctor = 
                  proxyClass.getConstructor( new Class[] { object.getClass() } );
              return ctor.newInstance( new Object[] { object } );
          }
          catch( final Throwable throwable ) { throwable.printStackTrace(); }
  
          return null;
      }
  
      /**
       * Create Proxy class.
       *
       * @param classname name of class
       * @return the proxy class
       */
      protected static ClassType createProxyType( final String classname )
      {
          final ClassType proxy = new ClassType( classname );
          proxy.setModifiers( Access.PUBLIC | /*ACC_SUPER*/ 0x0020 | Access.FINAL );
          proxy.setSuper( BASE_CLASS );
  
          return proxy;
      }
  
      /**
       * generate the list of Interfaces class implements.
       *
       * @param proxy the proxy class
       * @param interfaces[] the interfaces to add
       */
      protected static void generateInterfaces( final ClassType proxy, 
                                                final Class[] interfaces )
      {
          final ClassType[] interfaceTypes = new ClassType[ interfaces.length ];
          
          for( int i = 0; i < interfaceTypes.length; i++ )
          {
              interfaceTypes[ i ] = (ClassType)Type.getType( interfaces[ i ].getName() );
          }
          
          proxy.setInterfaces( interfaceTypes );
      }
  
      /**
       * Generate code for wrapper method.
       *
       * @param proxy the class to add to
       * @param target the class wrapping
       * @param method the method to wrap
       */
      protected static void generateMethod( final ClassType proxy, 
                                            final ClassType target, 
                                            final Method method )
      {
          final Class[] parameters = method.getParameterTypes();
          final Type[] parameterTypes = new Type[ parameters.length ];
  
          for( int i = 0; i < parameterTypes.length; i++ )
          {
              parameterTypes[ i ] = Type.getType( parameters[ i ].getName() );
          }
  
          final Type returnType = 
              Type.getType( method.getReturnType().getName() );
          
          final gnu.bytecode.Method newMethod = 
              proxy.addMethod( method.getName(), 
                               Access.PUBLIC, 
                               parameterTypes,
                               returnType );
  
          newMethod.init_param_slots();
          newMethod.pushScope();
          final CodeAttr code = newMethod.getCode();
  
          //put m_core on stack;
          final Field field = proxy.getField( "m_core" );
  
          code.emitPushThis();
          code.emitGetField( field );
  
          for( int i = 0; i < parameterTypes.length; i++ )
          {
              code.emitLoad( code.getArg( 1 + i ) );
          }
  
          //call target method
          final gnu.bytecode.Method targetMethod = 
              target.getMethod( method.getName(), parameterTypes );
          code.emitInvokeVirtual( targetMethod );
  
          //return
          code.emitReturn();
          newMethod.popScope();    
      }
  
      /**
       * Generate constructor code and field data.
       *
       * @param proxy the representation of class so far
       * @param target the type that is wrapped
       */
      protected static void generateBase( final ClassType proxy,
                                          final Type target )
      {
          final Field field = proxy.addField( "m_core", target );
          field.flags |= Access.PRIVATE;
  
          final gnu.bytecode.Method constructor = 
              proxy.addMethod( "<init>", 
                               Access.PUBLIC, 
                               new Type[] { target },
                               Type.void_type );
  
          final gnu.bytecode.Method superConstructor
              = proxy.getSuperclass().addMethod( "<init>", 
                                                 Access.PUBLIC,
                                                 null, 
                                                 Type.void_type );
  
          constructor.init_param_slots();
          constructor.pushScope();
          final CodeAttr code = constructor.getCode();
  
          //super();
          code.emitPushThis();
          code.emitInvokeSpecial( superConstructor );
  
          //m_core = param1;
          code.emitPushThis();
          code.emitLoad( code.getArg( 1 ) );
          code.emitPutField( field );
  
          //return
          code.emitReturn();
  
          constructor.popScope();
      }
  
      /**
       * Determine the methods that must be implemented to 
       * implement interface, eliminating duplicates.
       *
       * @param interfaces[] the interfaces to extract methods from
       * @return methods
       */
      protected static HashMap determineMethods( final Class[] interfaces )
      {
          final HashMap methodSet = new HashMap();
          final StringBuffer sb = new StringBuffer();
   
          for( int i = 0; i < interfaces.length; i++ )
          {
              if( DEBUG )
              {
                  LOGGER.debug( "Scanning interface " + interfaces[ i ].getName() +
                                " for methods" );
              }
  
              final Method[] methods = interfaces[ i ].getMethods();
  
              //for each method generate a pseudo signature
              //Add the method to methodSet under that signature.
              //This is to ensure that only one version of a method is 
              //entered into set even if multiple interfaces declare it
  
              for( int j = 0; j < methods.length; j++ )
              {
                  sb.append( methods[ j ].getName() );
                  sb.append( '(' );
  
                  final Class[] parameters = methods[ j ].getParameterTypes();
  
                  for( int k = 0; k < parameters.length; k++ )
                  {
                      sb.append( parameters[ k ].getName() );
                      sb.append( ' ' );
                  }
  
                  sb.append( ";)" );
  
                  if( DEBUG )
                  {
                      LOGGER.debug( "Found method with pseudo-signature " + sb );
                  }
  
                  methodSet.put( sb.toString(), methods[ j ] );
                  sb.setLength( 0 );
              }
          }
  
          return methodSet;
      }
  }
  
  
  
  
  
  1.1                  jakarta-avalon/src/java/org/apache/avalon/util/StringUtil.java
  
  Index: StringUtil.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE file.
   */
  package org.apache.avalon.util;
  
  import java.io.PrintWriter;
  import java.io.StringWriter;
  import java.util.ArrayList;
  import java.util.StringTokenizer;
  import org.apache.avalon.CascadingThrowable;
  
  /**
   * This class provides basic facilities for manipulating strings.
   *
   * Some exception handling stuff thieved from Turbine...
   * 
   * @author <a href="mailto:donaldp@apache.org">Peter Donald</a>
   * @author <a href="mailto:Rafal.Krzewski@e-point.pl">Rafal Krzewski</a>
   */
  public final class StringUtil
  {
      /**
       * Private constructor to prevent instantiation.
       */
      private StringUtil()
      {
      }
      
      /**
       * Replace substrings of one string with another string and return altered string.
       *
       * @param original input string
       * @param oldString the substring section to replace
       * @param newString the new substring replacing old substring section
       * @return converted string
       */
      public static String replaceSubString( final String original,
                                             final String oldString,
                                             final String newString )
      {
          final StringBuffer sb = new StringBuffer();
          
          int end = original.indexOf( oldString );
          int start = 0;
          final int stringSize = oldString.length();
          
          while( end != -1 )
          {
              sb.append( original.substring( start, end ) );
              sb.append( newString );
              start = end + stringSize;
              end = original.indexOf( oldString, start );
          }
          
          end = original.length();
          sb.append( original.substring( start, end ) );
          
          return sb.toString();
      }
      
      public static String printStackTrace( final Throwable throwable )
      {
          return printStackTrace( throwable, 0, true );
      }
      
      public static String printStackTrace( final Throwable throwable, 
                                            final boolean printCascading )
      {
          return printStackTrace( throwable, 0, printCascading );
      }
      
      public static String printStackTrace( final Throwable throwable, int depth )
      {
          final String[] lines = captureStackTrace( throwable );
  
          if( 0 == depth || depth > lines.length ) depth = lines.length;
  
          final StringBuffer sb = new StringBuffer();
  
          for( int i = 0; i < depth; i++ )
          {
              sb.append( lines[ i ] );
              sb.append( '\n' );
          }
  
          return sb.toString();
      }
  
      public static String printStackTrace( Throwable throwable, 
                                            final int depth,
                                            final boolean printCascading )
      {
          final String result = printStackTrace( throwable, depth );
  
          if( !printCascading || !(throwable instanceof CascadingThrowable) ) 
          {
              return result;
          }
          else
          {
              final StringBuffer sb = new StringBuffer();
              sb.append( result );
  
              throwable = ((CascadingThrowable)throwable).getCause();
  
              while( null != throwable )
              {
                  sb.append( "rethrown from\n" );
                  sb.append( printStackTrace( throwable, depth ) );
  
                  if( throwable instanceof CascadingThrowable )
                  {
                      throwable = ((CascadingThrowable)throwable).getCause();
                  }
                  else
                  {
                      throwable = null;
                  }
              }
  
              return sb.toString();
          }
      }
                                            
      /**
       * Captures the stack trace associated with this exception.
       *
       * @return an array of Strings describing stack frames.
       */ 
      public static String[] captureStackTrace( final Throwable throwable ) 
      {
          final StringWriter sw = new StringWriter();
          throwable.printStackTrace( new PrintWriter( sw, true ) );
          return splitString( sw.toString(), "\n" );
      }
                                                    
      /**
       * Splits the string on every token into an array of stack frames.
       * 
       * @param string the string
       * @param onToken the token
       * @return the resultant array
       */
      public static String[] splitString( final String string, final String onToken ) 
      {
          final StringTokenizer tokenizer = new StringTokenizer( string, onToken );
          
          final ArrayList lines = new ArrayList();
          
          while( tokenizer.hasMoreTokens() ) 
          {
              lines.add( tokenizer.nextToken() );
          }
          
          return (String[])lines.toArray( new String[ 0 ] );
      }
  }
  
  
  
  1.1                  jakarta-avalon/src/java/org/apache/avalon/util/ValuedEnum.java
  
  Index: ValuedEnum.java
  ===================================================================
  /* 
   * Copyright (C) The Apache Software Foundation. All rights reserved. 
   * 
   * This software is published under the terms of the Apache Software License 
   * version 1.1, a copy of which has been included with this distribution in 
   * the LICENSE file. 
   */ 
  package org.apache.avalon.util;
  
  /**
   * Basic enum class for type-safe enums with values. Should be used as an abstract base.
   *
   * @author <a href="mailto:donaldp@apache.org">Peter Donald</a>
   */
  public abstract class ValuedEnum 
      extends Enum
  {
      protected final int        m_value;
      
      public ValuedEnum( final String name, final int value )
      {
          super( name );
          m_value = value;
      } 
  
      public final int getValue()
      {
          return m_value;
      }
  
      public final boolean isEqualTo( final ValuedEnum enum )
      {
          return m_value == enum.m_value;
      }
  
      public final boolean isGreaterThan( final ValuedEnum enum )
      {
          return m_value > enum.m_value;
      }
      
      public final boolean isGreaterThanOrEqual( final ValuedEnum enum )
      {
          return m_value >= enum.m_value;
      }
      
      public final boolean isLessThan( final ValuedEnum enum )
      {
          return m_value < enum.m_value;
      }
      
      public final boolean isLessThanOrEqual( final ValuedEnum enum )
      {
          return m_value <= enum.m_value;
      }
      
      public String toString()
      {
          return getClass().getName() + "[" + m_name + "=" + m_value + "]";
      }
  }
  
  
  
  
  1.1                  jakarta-avalon/src/java/org/apache/avalon/util/Version.java
  
  Index: Version.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included  with this distribution in
   * the LICENSE file.
   */
  package org.apache.avalon.util;
  
  /**
   * This document is NOT RIGHT.
   * <p />
   *
   * The version number of a <code>Block</code> is made up of three
   * dot-separated fields:
   * <p />
   * &quot;<b>major.minor.patchlevel</b>&quot;
   * <p />
   * and (optionally) by a fourth field (always <b>&quot;-dev&quot;</b>)
   * specifying that this version is under development.
   * <p />
   * The <b>major</b>, <b>minor</b> and <b>patchlevel</b> fields are
   * <i>integer</i> numbers represented in decimal notation and have the
   * following meaning:
   * <ul>
   * <p /><li><b>major</b> - When the major version changes (in ex. from
   * &quot;1.5.12&quot; to &quot;2.0.0&quot;), then backward compatibility
   * with previous releases is not granted (this usually happens this
   * <code>Block</code> is implementing a new major version of an interface
   * specified in <b>org.apache.avalon.blocks</b> package).
   * </li><p />
   * <p /><li><b>minor</b> - When the minor version changes (in ex. from
   * &quot;1.5.12&quot; to &quot;1.6.0&quot;), then backward compatibility
   * with previous releases is granted, but something changed in the
   * implementation (in ex. new features were added, the configuration
   * syntax may be different, or the <code>Block</code> is implementing a
   * new minor version of an interface specified in
   * <b>org.apache.avalon.blocks</b> package).
   * </li><p />
   * <p /><li><b>patchlevel</b> - When the patchlevel version changes (in ex.
   * from &quot;1.5.12&quot; to &quot;1.5.13&quot;), then the only changed
   * things are fixes in the code implementation, but no new features or
   * changes were made to the behaviour of the code.
   * </li>
   * </ul>
   * <p />
   * The fourth field, optional and always &quot;<b>-dev</b>&quot; (in ex.
   * &quot;1.5.12-dev&quot;) specifies that current <code>Block</code>
   * implementation is under development, and so may contain not-working
   * code or not all features were implemented.
   * <p />
   * <p />
   * <b>NOTE: The absence of the &quot;-dev&quot; tag does not endorse
   * any warranty of particular stability, safety or compliancy.
   * The only source for such informations is the (usually provided) license
   * file accompaining the block itself.</b>
   *
   * The class defining versioning pattern.
   * <p />
   * <p />
   * Any interface in <b>org.apache.avalon.blocks</b> package <b>MUST</b> provides
   * a Version instance containing versioning informations on this interface.<p />
   * Any BlockInfo returned by a Block implementation <b>MUST</b> provides a
   * Version instances containing versioning informations on this implementation.
   * <p /><p />
   * Version numbers are:<p />
   * &quot;<b>major.minor.revision.dev</b>&quot;
   * <p />
   * The <b>major</b> , <b>minor</b> and <b>revision</b>fields are <i>integer</i>
   * numbers represented in decimal notation and have the following meaning:
   * <ul><b> - Refering to an interface</b>
   * <ul>
   * <li><b>major</b> - When the major version changes (in ex. from
   * &quot;1.5&quot; to &quot;2.0&quot;), then backward compatibility with
   * previous releases is not granted.
   * </li><p />
   * <p /><li><b>minor</b> - When the minor version changes (in ex. from
   * &quot;1.5&quot; to &quot;1.6&quot;), then backward compatibility
   * with previous releases is granted, but something changed in the
   * interface (in ex. new methods were added).
   * </li><p />
   * <li><b>revision</b> - When refering to an interface may represent a change
   * in documentation or other minor changes. If some methods are modified a minor
   * version changes is needed.<p />
   * - When refering to a Block implementation this represent minor changes in
   * implementation like bugs fix.
   * </li><p />
   * <li><b>dev</b> - The boolean dev field specify if this Block or interface
   * is under development and not yet approved by the Java Apache org.apache.avalon.interfaces;
   * developers group (mailing-list).
   * </li><p />
   * </ul>
   * </ul>
   * <ul><b> - Refering to a Block</b>
   * <ul>
   * <li><b>major</b> - When the major version changes (in ex. from
   * &quot;1.5&quot; to &quot;2.0&quot;), then backward compatibility with
   * previous releases is not granted.
   * </li><p />
   * <p /><li><b>minor</b> - When the minor version changes (in ex. from
   * &quot;1.5&quot; to &quot;1.6&quot;), then backward compatibility
   * with previous releases is granted, but something changed in the
   * interface (in ex. new methods were added).
   * </li><p />
   * <li><b>revision</b> - When refering to an interface may represent a change
   * in documentation or other minor changes. If some methods are modified a minor
   * version changes is needed.<p />
   * - When refering to a Block implementation this represent minor changes in
   * implementation like bugs fix.
   * </li><p />
   * <li><b>dev</b> - The boolean dev field specify if this Block or interface
   * is under development and not yet approved by the Java Apache org.apache.avalon.interfaces;
   * developers group (mailing-list).
   * </li><p />
   * </ul>
   * </ul>
   * The third field, optional and always &quot;<b>-dev</b>&quot; (in ex.
   * &quot;1.5-dev&quot;) specifies that the interface is currently under
   * development, or it was not yet approved by the Java Apache org.apache.avalon.interfaces;
   * developers group (mailing-list) and so, not yet integrated with the
   * org.apache.avalon.interfaces; distributions.
   *
   * @author <a href="mailto:fede@apache.org">Federico Barbieri</a>
   * @author <a href="mailto:pier@apache.org">Pierpaolo Fumagalli</a>
   * @author <a href="mailto:stefano@apache.org">Stefano Mazzocchi</a>
   * @author <a href="mailto:rlogiacco@mail.com">Roberto Lo Giacco</a>
   * @author <a href="http://java.apache.org/">Java Apache Project</a>
  
   */
  public final class Version
  {
      protected int                   m_major;
      protected int                   m_minor;
      protected int                   m_revision;
  
      /**
       * Create a new instance of a <code>Version</code> object with the
       * specified version numbers.
       *
       * @param major This <code>Version</code> major number.
       * @param minor This <code>Version</code> minor number.
       * @param rev This <code>Version</code> revision number.
       */
      public Version( final int major, final int minor, final int revision )
      {
          m_major = major;
          m_minor = minor;
          m_revision = revision;
      }
  
      /**
       * Check this <code>Version</code> against another for equality.
       * <p />
       * If this <code>Version</code> is compatible with the specified one, then
       * <b>true</b> is returned, otherwise <b>false</b>.
       *
       * @param other The other <code>Version</code> object to be compared with this
       *          for equality.
       */
      public boolean equals( final Version other )
      {
          if( m_major != other.m_major) return false;
          else if( m_minor != other.m_minor) return false;
          else if( m_revision != other.m_revision ) return false;
          else return true;
      }
  
      /**
       * Check this <code>Version</code> against another for compliancy
       * (compatibility).
       * <p />
       * If this <code>Version</code> is compatible with the specified one, then
       * <b>true</b> is returned, otherwise <b>false</b>. Be careful when using
       * this method since, in example, version 1.3.7 is compliant to version
       * 1.3.6, while the opposite is not.
       *
       * @param v The other <code>Version</code> object to be compared with this
       *          for compliancy (compatibility).
       */
      public boolean complies( final Version other )
      {
          if( m_major != other.m_major) return false;
          else if( m_minor < other.m_minor) return false;
          else return true;
      }
  
      /**
       * Overload toString to report version correctly.
       *
       * @return the dot seperated version string
       */
      public String toString()
      {
          return m_major + "." + m_minor + "." + m_revision;
      }
  }
  
  
  
  1.1                  jakarta-avalon/src/java/org/apache/avalon/util/cli/AbstractMain.java
  
  Index: AbstractMain.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE file.
   */
  package org.apache.avalon.util.cli;
  
  import java.util.List;
  import org.apache.avalon.AbstractLoggable;
  
  /**
   * Abstract main entry point.
   * 
   * @author <a href="mailto:donaldp@apache.org">Peter Donald</a>
   */
  public abstract class AbstractMain
      extends AbstractLoggable
  {
      protected CLOptionDescriptor[]          m_options;
  
      /**
       * Return string describing how command is executed.
       *
       * @return the string describing exectution command
       */
      protected String getExecutionCommand()
      {
          return "java " + getClass().getName() + " [options]";
      }    
  
      /**
       * Display usage report.
       *
       */
      protected void usage()
      {
          System.out.println( getExecutionCommand() );
          System.out.println( "\tAvailable options:");
          System.out.println( CLUtil.describeOptions( m_options ) );
      }
  
      /**
       * Initialise the options for command line parser.
       *
       */
      protected abstract CLOptionDescriptor[] createCLOptions();
  
      /**
       * Main entry point.
       *
       * @param args[] the command line arguments
       * @Throwable Throwable if an error occurs
       */
      public void execute( final String[] args )
          throws Exception
      { 
          m_options = createCLOptions();
          final CLArgsParser parser = new CLArgsParser( args, m_options );
          
          if( null != parser.getErrorString() ) 
          {
              System.err.println( "Error: " + parser.getErrorString() );
              return;
          }
  
          execute( parser.getArguments() );
      }
  
      /**
       * Overide this method to provide functionality for your application.
       *
       * @param clOptions the list of command line options
       */
      protected abstract void execute( final List clOptions )
          throws Exception;
  }
  
  
  
  
  1.1                  jakarta-avalon/src/java/org/apache/avalon/util/cli/AbstractParserControl.java
  
  Index: AbstractParserControl.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE file.
   */
  package org.apache.avalon.util.cli;
  
  /**
   * Class to inherit from so when in future when new controls are added
   * clients will no have to implement them.
   *
   * @author <a href="mailto:donaldp@apache.org">Peter Donald</a>
   */
  public class AbstractParserControl 
      implements ParserControl
  {
      public boolean isFinished( int lastOptionCode )
      {
          return false;
      }
  }
  
  
  
  1.1                  jakarta-avalon/src/java/org/apache/avalon/util/cli/CLArgsParser.java
  
  Index: CLArgsParser.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE file.
   */
  package org.apache.avalon.util.cli;
  
  import java.text.ParseException;
  import java.util.Arrays;
  import java.util.Vector;
  
  /**
   * Parser for command line arguments.
   *
   * This parses command lines according to the standard (?) of 
   * gnu utilities.
   *
   * Note: This is still used in 1.1 libraries so do not add 1.2+ dependancies.
   *
   * @author <a href="mailto:donaldp@apache.org">Peter Donald</a>
   */
  public final class CLArgsParser
  {
      protected class Token
      {
          protected final int                m_type;
          protected final String             m_value;
  
          public Token( final int type, final String value )
          {
              m_type = type;
              m_value = value;
          }
  
          public String getValue()
          {
              return m_value;
          }
  
          public int getType()
          {
              return m_type;
          }
  
          public String toString()
          {
              return "" + m_type + ":" + m_value;
          }
      }
  
      private final static int                 STATE_NORMAL           = 0;
      private final static int                 STATE_REQUIRE_2ARGS    = 1;
      private final static int                 STATE_REQUIRE_ARG      = 2;
      private final static int                 STATE_OPTIONAL_ARG     = 3;
      private final static int                 STATE_NO_OPTIONS       = 4;
      private final static int                 STATE_OPTION_MODE      = 5;
  
      protected final static int               TOKEN_SEPERATOR        = 0;
      protected final static int               TOKEN_STRING           = 1;
  
  
      protected final static char[]            ARG2_SEPERATORS        = 
          new char[] { (char)0, '=', '-' };
  
      protected final static char[]            ARG_SEPERATORS         = 
          new char[] { (char)0, '=' };
  
      protected final static char[]            NULL_SEPERATORS        = 
          new char[] { (char)0 };
  
      protected final CLOptionDescriptor[]     m_optionDescriptors;
      protected final Vector                   m_options;
      protected final ParserControl            m_control;
  
      protected String                         m_errorMessage;
      protected String[]                       m_unparsedArgs         = new String[] {};
  
      //variables used while parsing options.
      protected char                           ch;
      protected String[]                       args;
      protected boolean                        isLong;
      protected int                            argIndex;
      protected int                            stringIndex;
      protected int                            stringLength;
  
      //cached character == Integer.MAX_VALUE when invalid
      protected final static int               INVALID         = Integer.MAX_VALUE;
      protected int                            m_lastChar      = INVALID;
  
      protected int                            m_lastOptionId;
      protected CLOption                       m_option;
      protected int                            m_state         = STATE_NORMAL;
  
      public String[] getUnparsedArgs()
      {
          return m_unparsedArgs;
      }
  
      /**
       * Retrieve a list of options that were parsed from command list.
       *
       * @return the list of options
       */
      public Vector getArguments()
      {
          //System.out.println( "Arguments: " + m_options );
          return m_options; 
      }  
  
      /**
       * Get Descriptor for option id.
       *
       * @param id the id
       * @return the descriptor
       */
      private CLOptionDescriptor getDescriptorFor( final int id )
      {
          for( int i = 0; i < m_optionDescriptors.length; i++ )
          {
              if( m_optionDescriptors[i].getId() == id )
              {
                  return m_optionDescriptors[i];
              }
          }
  
          return null;
      }
  
      /**
       * Retrieve a descriptor by name.
       *
       * @param name the name
       * @return the descriptor
       */
      private CLOptionDescriptor getDescriptorFor( final String name )
      {
          for( int i = 0; i < m_optionDescriptors.length; i++ )
          {
              if( m_optionDescriptors[i].getName().equals( name ) )
              {
                  return m_optionDescriptors[i];
              }
          }
  
          return null;
      }  
  
      /**
       * Retrieve an error message that occured during parsing if one existed.
       *
       * @return the error string
       */
      public String getErrorString() 
      {
          //System.out.println( "ErrorString: " + m_errorMessage );
          return m_errorMessage; 
      }
  
      /**
       * Requier state to be placed in for option.
       *
       * @param descriptor the Option Descriptor
       * @return the state
       */
      private int getStateFor( final CLOptionDescriptor descriptor )
      {
          int flags = descriptor.getFlags();
          if( ( flags & CLOptionDescriptor.ARGUMENTS_REQUIRED_2 ) == 
              CLOptionDescriptor.ARGUMENTS_REQUIRED_2 )
          {
              return STATE_REQUIRE_2ARGS;
          }
          else if( ( flags & CLOptionDescriptor.ARGUMENT_REQUIRED ) == 
                   CLOptionDescriptor.ARGUMENT_REQUIRED )
          {
              return STATE_REQUIRE_ARG;
          }
          else if( ( flags & CLOptionDescriptor.ARGUMENT_OPTIONAL ) == 
                   CLOptionDescriptor.ARGUMENT_OPTIONAL )
          {
              return STATE_OPTIONAL_ARG;
          }
          else
          {
              return STATE_NORMAL;
          }
      }  
  
      /**
       * Create a parser that can deals with options and parses certain args.
       *
       * @param args[] the args 
       * @param optionDescriptors[] the option descriptors
       */
      public CLArgsParser( final String[] args, 
                           final CLOptionDescriptor[] optionDescriptors,
                           final ParserControl control )
      {
          m_optionDescriptors = optionDescriptors;
          m_control = control;
          m_options = new Vector();
          this.args = args;
  
          try 
          {
              parse(); 
              checkIncompatabilities( m_options );
          }
          catch( final ParseException pe )
          {
              m_errorMessage = pe.getMessage();
          }
  
          //System.out.println( "Built : " + m_options );
          //System.out.println( "From : " + Arrays.asList( args ) );
      }
  
      /**
       * Check for duplicates of an option. 
       * It is an error to have duplicates unless appropriate flags is set in descriptor.
       *
       * @param arguments the arguments
       */
      protected void checkIncompatabilities( final Vector arguments )
          throws ParseException
      {
          final int size = arguments.size();
  
          for( int i = 0; i < size; i++ )
          {
              final CLOption option = (CLOption)arguments.elementAt( i );
              final int id = option.getId();
              final CLOptionDescriptor descriptor = getDescriptorFor( id );
  
              //this occurs when id == 0 and user has not supplied a descriptor 
              //for arguments
              if( null == descriptor ) continue;
  
              final int[] incompatable = descriptor.getIncompatble();
  
              checkIncompatable( arguments, incompatable, i );
          }
      }
      
      protected void checkIncompatable( final Vector arguments, 
                                        final int[] incompatable,
                                        final int original )
          throws ParseException
      {
          final int size = arguments.size();
          
          for( int i = 0; i < size; i++ )
          {
              if( original == i ) continue;
  
              final CLOption option = (CLOption)arguments.elementAt( i );
              final int id = option.getId();
              final CLOptionDescriptor descriptor = getDescriptorFor( id );
              
              for( int j = 0; j < incompatable.length; j++ )
              {
                  if( id == incompatable[ j ] )
                  {
                      final CLOption originalOption = (CLOption)arguments.elementAt( original );
                      final int originalId = originalOption.getId();
  
                      String message = null;
  
                      if( id == originalId )
                      {
                          message = 
                              "Duplicate options for " + describeDualOption( originalId ) +
                              " found.";
                      }
                      else
                      {
                          message = "Incompatable options -" + 
                              describeDualOption( id ) + " and " + 
                              describeDualOption( originalId ) + " found.";
                      }
                      throw new ParseException( message, 0 );
                  }
              }
          }
      }
  
      protected String describeDualOption( final int id )
      {
          final CLOptionDescriptor descriptor = getDescriptorFor( id );
          if( null == descriptor ) return "<parameter>";
          else
          {
              final StringBuffer sb = new StringBuffer();
              boolean hasCharOption = false;
  
              if( Character.isLetter( (char)id ) )
              {
                  sb.append( '-' );
                  sb.append( (char)id );
                  hasCharOption = true;
              }
              
              final String longOption = descriptor.getName();
              if( null != longOption )
              {
                  if( hasCharOption ) sb.append( '/' );
                  sb.append( "--" );
                  sb.append( longOption );
              }
  
              return sb.toString();
          }            
      }
  
      /**
       * Create a parser that can deals with options and parses certain args.
       *
       * @param args[] the args 
       * @param optionDescriptors[] the option descriptors
       */
      public CLArgsParser( final String[] args, 
                           final CLOptionDescriptor[] optionDescriptors )
      {
          this( args, optionDescriptors, null );
      }
  
      /**
       * Create a string array that is subset of input array. 
       * The sub-array should start at array entry indicated by index. That array element
       * should only include characters from charIndex onwards.
       *
       * @param array[] the original array
       * @param index the cut-point in array
       * @param charIndex the cut-point in element of array
       * @return the result array
       */
      protected String[] subArray( final String[] array,
                                   final int index,
                                   final int charIndex )
      {
          final int remaining = array.length - index;
          final String[] result = new String[ remaining ];
  
          if( remaining > 1 )
          {
              System.arraycopy( array, index + 1, result, 1, remaining - 1 );
          }
  
          result[0] = array[ index ].substring( charIndex - 1 );
          
          return result;
      }
  
      /**
       * Actually parse arguments
       *
       * @param args[] arguments
       */
      protected void parse()
          throws ParseException
      {
          if( 0 == args.length ) return;
  
          stringLength = args[ argIndex ].length();
  
          //ch = peekAtChar();
  
          while( true )
          {
              ch = peekAtChar();
  
              if( argIndex >= args.length ) break;
              
              if( null != m_control && m_control.isFinished( m_lastOptionId ) )
              {
                  //this may need mangling due to peeks
                  m_unparsedArgs = subArray( args, argIndex, stringIndex );
                  return;
              }
  
              //System.out.println( "State=" + m_state );
              //System.out.println( "Char=" + (char)ch );
  
              if( STATE_OPTION_MODE == m_state ) 
              {
                  //if get to an arg barrier then return to normal mode
                  //else continue accumulating options
                  if( 0 == ch ) 
                  {
                      getChar(); //strip the null
                      m_state = STATE_NORMAL;
                  }
                  else parseShortOption();
              }
              else if( STATE_NORMAL == m_state )
              {
                  parseNormal();
              }
              else if( STATE_NO_OPTIONS == m_state )
              {
                  //should never get to here when stringIndex != 0
                  addOption( new CLOption( args[ argIndex++ ] ) );
              }
              else if( STATE_OPTIONAL_ARG == m_state && '-' == ch )
              {
                  m_state = STATE_NORMAL;
                  addOption( m_option );
              }
              else 
              {
                  parseArguments();
              }
          }
  
          if( m_option != null )
          {
              if( STATE_OPTIONAL_ARG == m_state )
              {
                  m_options.addElement( m_option );
              }
              else if( STATE_REQUIRE_ARG == m_state )
              {
                  final CLOptionDescriptor descriptor = getDescriptorFor( m_option.getId() );
                  final String message = 
                      "Missing argument to option " + getOptionDescription( descriptor );
                  throw new ParseException( message, 0 );
              }
              else if( STATE_REQUIRE_2ARGS == m_state )
              {
                  if( 1 == m_option.getArgumentCount() )
                  {
                      m_option.addArgument( "" );
                      m_options.addElement( m_option );
                  }
                  else
                  {
                      final CLOptionDescriptor descriptor = getDescriptorFor( m_option.getId() );
                      final String message = 
                          "Missing argument to option " + getOptionDescription( descriptor );
                      throw new ParseException( message, 0 );
                  }
              }
              else
              {
                  throw new ParseException( "IllegalState " + m_state + ": " + m_option, 0 );
              }
          }
      }
  
      protected final String getOptionDescription( final CLOptionDescriptor descriptor )
      {
          if( isLong ) return "--" + descriptor.getName();
          else return "-" + (char)descriptor.getId();
      }
  
      protected final char peekAtChar()
      {
          if( INVALID == m_lastChar ) m_lastChar = readChar();
          return (char)m_lastChar;
      }
  
      protected final char getChar()
      {
          if( INVALID != m_lastChar ) 
          {
              final char result = (char)m_lastChar;
              m_lastChar = INVALID;
              return result;
          }
          else return readChar();
      }
  
      private final char readChar()
      {
          if( stringIndex >= stringLength )
          { 
              argIndex++;
              stringIndex = 0;
  
              if( argIndex < args.length ) stringLength = args[ argIndex ].length();
              else stringLength = 0;
  
              return 0;
          }
  
          if( argIndex >= args.length ) return 0;
  
          return args[ argIndex ].charAt( stringIndex++ );
      }
  
      protected final Token nextToken( final char[] seperators )
      {
          ch = getChar();
  
          if( isSeperator( ch, seperators ) ) 
          {
              ch = getChar();
              return new Token( TOKEN_SEPERATOR, null );
          }
  
          final StringBuffer sb = new StringBuffer();
  
          do
          {
              sb.append( ch );
              ch = getChar();
          }
          while( !isSeperator( ch, seperators ) );
  
          return new Token( TOKEN_STRING, sb.toString() );
      }
  
      private final boolean isSeperator( final char ch, final char[] seperators )
      {
          for( int i = 0; i < seperators.length; i++ )
          {
              if( ch == seperators[ i ] ) return true;
          }
  
          return false;
      }
  
      protected void addOption( final CLOption option )
      {
          m_options.addElement( option );
          m_lastOptionId = option.getId();
          m_option = null;
      }
  
      protected void parseOption( final CLOptionDescriptor descriptor, 
                                  final String optionString )
          throws ParseException
      {
          if( null == descriptor )
          {
              throw new ParseException( "Unknown option " + optionString, 0 );
          }
          
          m_state = getStateFor( descriptor );
          m_option = new CLOption( descriptor.getId() );
          
          if( STATE_NORMAL == m_state ) addOption( m_option );
      }
  
      protected void parseShortOption()
          throws ParseException
      {
          ch = getChar();
          final CLOptionDescriptor descriptor = getDescriptorFor( (int)ch );
          isLong = false;
          parseOption( descriptor, "-" + ch );
          
          if( STATE_NORMAL == m_state ) m_state = STATE_OPTION_MODE;
      }
  
      protected boolean parseArguments()
          throws ParseException
      {
          if( STATE_REQUIRE_ARG == m_state )
          {
              if( '=' == ch || 0 == ch ) getChar();
  
              final Token token = nextToken( NULL_SEPERATORS );
              m_option.addArgument( token.getValue() );
  
              addOption( m_option );
              m_state = STATE_NORMAL;
          }
          else if( STATE_REQUIRE_2ARGS == m_state )
          {
              if( 0 == m_option.getArgumentCount() )
              {
                  final Token token = nextToken( ARG_SEPERATORS );
  
                  if( TOKEN_SEPERATOR == token.getType() )
                  {
                      final CLOptionDescriptor descriptor = getDescriptorFor( m_option.getId() );
                      final String message = 
                          "Unable to parse first argument for option " +
                          getOptionDescription( descriptor );
                      throw new ParseException( message, 0 );
                  }
                  else
                  {
                      m_option.addArgument( token.getValue() );
                  }
              }
              else //2nd argument
              {
                  final StringBuffer sb = new StringBuffer();
  
                  ch = getChar();
                  if( '-' == ch ) m_lastChar = ch;
  
                  while( !isSeperator( ch, ARG2_SEPERATORS ) )
                  {
                      sb.append( ch );
                      ch = getChar();
                  }
  
                  final String argument = sb.toString();
  
                  //System.out.println( "Arguement:" + argument );
  
                  m_option.addArgument( argument );
                  addOption( m_option );
                  m_option = null;
                  m_state = STATE_NORMAL;
              }
          }
  
          return true;
      }
  
      /**
       * Parse Options from Normal mode.
       */
      protected void parseNormal()
          throws ParseException
      {
          if( '-' != ch )
          {
              //Parse the arguments that are not options
              final String argument = nextToken( NULL_SEPERATORS ).getValue();
              addOption( new CLOption( argument ) );
              m_state = STATE_NORMAL;
          }
          else
          {
              getChar(); // strip the -
  
              if( 0 == peekAtChar() )
              {
                  throw new ParseException( "Malformed option -", 0 );
              }
              else
              {
                  ch = peekAtChar();
                  
                  //if it is a short option then parse it else ...
                  if( '-' != ch ) parseShortOption();
                  else
                  {
                      getChar(); // strip the - 
                      //-- sequence .. it can either mean a change of state
                      //to STATE_NO_OPTIONS or else a long option
                      
                      if( 0 == peekAtChar() )
                      {
                          getChar();
                          m_state = STATE_NO_OPTIONS;
                      }
                      else
                      {
                          //its a long option
                          final String optionName = nextToken( ARG_SEPERATORS ).getValue();
                          final CLOptionDescriptor descriptor = getDescriptorFor( optionName );
                          isLong = true;
                          parseOption( descriptor, "--" + optionName );
                      }
                  }
              }
          }
      }
  }
  
  
  
  
  
  1.1                  jakarta-avalon/src/java/org/apache/avalon/util/cli/CLOption.java
  
  Index: CLOption.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE file.
   */
  package org.apache.avalon.util.cli;
  
  import java.util.Arrays;
  
  /**
   * Basic class describing an instance of option.
   *
   * @author <a href="mailto:donaldp@apache.org">Peter Donald</a>
   */
  public class CLOption
  {
      protected final int                      m_id;
      protected String[]                       m_arguments;
  
      /**
       * Retrieve argument to option if it takes arguments.
       *
       * @return the argument
       */
      public final String getArgument()
      {
          return getArgument( 0 );
      }
      
      /**
       * Retrieve argument to option if it takes arguments.
       *
       * @return the argument
       */
      public final String getArgument( final int index )
      {
          if( null == m_arguments || index < 0 || index >= m_arguments.length ) 
          {
              return null;
          }
          else return m_arguments[ index ]; 
      }
  
      /**
       * Retrieve id of option. 
       * 
       * The id is eqivelent to character code if it can be a single letter option.
       *
       * @return the id
       */
      public final int getId() 
      {
          return m_id; 
      }
  
      /**
       * Constructor taking an id (that must be a proper character code)
       *
       * @param id the new id
       */
      public CLOption( final int id ) 
      {
          m_id = id; 
      }
  
      /**
       * Constructor taking argument for option.
       *
       * @param argument the argument
       */
      public CLOption( final String argument ) 
      {
          this( 0 );
          addArgument( argument );
      }  
  
      /**
       * Mutator fo Argument property.
       *
       * @param argument the argument
       */
      public final void addArgument( final String argument ) 
      {
          if( null == m_arguments ) m_arguments = new String[] { argument };
          else
          {
              final String[] arguments = new String[ m_arguments.length + 1 ];
              System.arraycopy( m_arguments, 0, arguments, 0, m_arguments.length );
              arguments[ m_arguments.length ] = argument;
              m_arguments = arguments;
          }
      }  
  
      public int getArgumentCount()
      {
          if( null == m_arguments ) return 0;
          else return m_arguments.length;
      }
  
      /**
       * Convert to String.
       *
       * @return the string value
       */
      public String toString()
      {
          final StringBuffer sb = new StringBuffer();
          sb.append( "[Option " );
          sb.append( (char)m_id );
  
          if( null != m_arguments )
          {
              sb.append( ", " );
              sb.append( Arrays.asList( m_arguments ) );
          }
  
          sb.append( " ]" );
          
          return sb.toString();
      }  
  }
  
  
  
  1.1                  jakarta-avalon/src/java/org/apache/avalon/util/cli/CLOptionDescriptor.java
  
  Index: CLOptionDescriptor.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE file.
   */
  package org.apache.avalon.util.cli;
  
  /**
   * Basic class describing an type of option.
   *
   * @author <a href="mailto:donaldp@apache.org">Peter Donald</a>
   */
  public class CLOptionDescriptor
  {
      public final static int                  ARGUMENT_REQUIRED         = 1 << 1;
      public final static int                  ARGUMENT_OPTIONAL         = 1 << 2;
      public final static int                  ARGUMENT_DISALLOWED       = 1 << 3;
      public final static int                  ARGUMENTS_REQUIRED_2      = 1 << 4;
  
      protected final int                      m_id;
      protected final int                      m_flags;
      protected final String                   m_name;
      protected final String                   m_description;
      protected final int[]                    m_incompatable;
  
      /**
       * Constructor.
       *
       * @param name the name/long option
       * @param flags the flags
       * @param id the id/character option
       * @param description description of option usage
       */
      public CLOptionDescriptor( final String name, 
                                 final int flags, 
                                 final int id,
                                 final String description )
      {
          this( name, flags, id, description, new int[] { id } );
      }
  
      /**
       * Constructor.
       *
       * @param name the name/long option
       * @param flags the flags
       * @param id the id/character option
       * @param description description of option usage
       */
      public CLOptionDescriptor( final String name, 
                                 final int flags, 
                                 final int id,
                                 final String description,
                                 final int[] incompatable )
      {
          m_id = id;
          m_name = name;
          m_flags = flags;
          m_description = description;
          m_incompatable = incompatable;
      }  
  
      protected int[] getIncompatble()
      {
          return m_incompatable;
      }
  
      /**
       * Retrieve textual description.
       *
       * @return the description 
       */
      public final String getDescription() 
      { 
          return m_description; 
      }
    
      /**
       * Retrieve flags about option.
       * Flags include details such as whether it allows parameters etc.
       *
       * @return the flags
       */
      public final int getFlags() 
      {
          return m_flags; 
      }
    
      /**
       * Retrieve the id for option.
       * The id is also the character if using single character options.
       *
       * @return the id
       */
      public final int getId() 
      { 
          return m_id; 
      }  
    
      /**
       * Retrieve name of option which is also text for long option.
       *
       * @return name/long option
       */
      public final String getName() 
      { 
          return m_name; 
      }  
  
      /**
       * Convert to String.
       *
       * @return the converted value to string.
       */
      public String toString()
      {
          return 
              "[OptionDescriptor " + m_name + 
              ", " + m_id + ", " + m_flags + 
              ", " + m_description + " ]";
      }  
  }
  
  
  
  1.1                  jakarta-avalon/src/java/org/apache/avalon/util/cli/CLUtil.java
  
  Index: CLUtil.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE file.
   */
  package org.apache.avalon.util.cli;
  
  /**
   * CLUtil offers basic utility operations for use both internal and external to package.
   *
   * @author <a href="mailto:donaldp@apache.org">Peter Donald</a>
   */
  public final class CLUtil
  {
      protected static int              MAX_DESCRIPTION_COLUMN_LENGTH = 60;
  
      /**
       * Format options into StringBuffer and return.
       *
       * @param options[] the option descriptors
       * @return the formatted description/help for options
       */
      public static StringBuffer describeOptions( final CLOptionDescriptor[] options )
      {
          StringBuffer sb = new StringBuffer();
          for (int i = 0; i < options.length; i++)
          {
              final char ch = (char) options[i].getId();
              final String name = options[i].getName();
              String description = options[i].getDescription();
              boolean needComma = false;
          
              sb.append('\t');
          
              if( Character.isLetter(ch) )
              {
                  sb.append("-");
                  sb.append(ch);
                  needComma = true;
              }
          
              if (null != name)
              {
                  if( needComma ) sb.append(", ");
              
                  sb.append("--");
                  sb.append(name);
                  sb.append('\n');
              }
          
              if( null != description )
              {
                  while( description.length() > MAX_DESCRIPTION_COLUMN_LENGTH )
                  {
                      final String descriptionPart = 
                          description.substring( 0, MAX_DESCRIPTION_COLUMN_LENGTH );
                      description = 
                          description.substring( MAX_DESCRIPTION_COLUMN_LENGTH );
                      sb.append( "\t\t" );
                      sb.append( descriptionPart );
                      sb.append( '\n' );
                  }
              
                  sb.append( "\t\t" );
                  sb.append( description );
                  sb.append( '\n' );
              }
          }
          return sb;
      }
  
      /**
       * Private Constructor so that no instance can ever be created.
       *
       */
      private CLUtil() 
      {
      }  
  }
  
  
  
  1.1                  jakarta-avalon/src/java/org/apache/avalon/util/cli/ParserControl.java
  
  Index: ParserControl.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE file.
   */
  package org.apache.avalon.util.cli;
  
  /**
   * ParserControl is used to control particular behaviour of the parser.
   *
   * @author <a href="mailto:donaldp@apache.org">Peter Donald</a>
   */
  public interface ParserControl
  {
      boolean isFinished( int lastOptionCode );
  }
  
  
  
  1.1                  jakarta-avalon/src/java/org/apache/avalon/util/cli/test/ClutilTestlet.java
  
  Index: ClutilTestlet.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE file.
   */
  package org.apache.avalon.util.cli.test;
  
  import java.util.List;
  import org.apache.avalon.util.cli.AbstractParserControl;
  import org.apache.avalon.util.cli.CLArgsParser;
  import org.apache.avalon.util.cli.CLOption;
  import org.apache.avalon.util.cli.CLOptionDescriptor;
  import org.apache.avalon.util.cli.ParserControl;
  import org.apache.testlet.AbstractTestlet;
  
  /**
   *
   * @author <a href="mailto:donaldp@apache.org">Peter Donald</a>
   */
  public final class ClutilTestlet
      extends AbstractTestlet
  { 
      protected final static String[] ARGLIST1 = 
      {
          "--you","are","--all","-cler","kid"
      };
  
      protected final static String[] ARGLIST2 = 
      {
          "-Dstupid=idiot","are","--all","here"
      };
      
      protected final static String[] ARGLIST3 = 
      {
          //duplicates
          "-Dstupid=idiot","are","--all","--all","here"
      };
      
      protected final static String[] ARGLIST4 = 
      {
          //incompatable (blee/all)
          "-Dstupid=idiot","are","--all","--blee","here"
      };
  
      protected final static String[] ARGLIST5 = 
      {
          "-f","myfile.txt"
      };
  
      private static final int                DEFINE_OPT        = 'D';
      private static final int                YOU_OPT           = 'y';
      private static final int                ALL_OPT           = 'a';
      private static final int                CLEAR1_OPT        = 'c';
      private static final int                CLEAR2_OPT        = 'l';
      private static final int                CLEAR3_OPT        = 'e';
      private static final int                CLEAR5_OPT        = 'r';
      private static final int                BLEE_OPT          = 'b';
      private static final int                FILE_OPT          = 'f';
  
      protected final static CLOptionDescriptor DEFINE          =
          new CLOptionDescriptor( "define", 
                                  CLOptionDescriptor.ARGUMENTS_REQUIRED_2, 
                                  DEFINE_OPT, 
                                  "define" );
      protected final static CLOptionDescriptor YOU             =
          new CLOptionDescriptor( "you", CLOptionDescriptor.ARGUMENT_DISALLOWED, YOU_OPT, "you" );
  
      protected final static CLOptionDescriptor ALL             =
          new CLOptionDescriptor( "all", 
                                  CLOptionDescriptor.ARGUMENT_DISALLOWED, 
                                  ALL_OPT, 
                                  "all",
                                  new int[] { BLEE_OPT } );
  
      protected final static CLOptionDescriptor CLEAR1          =
          new CLOptionDescriptor( "c", CLOptionDescriptor.ARGUMENT_DISALLOWED, CLEAR1_OPT, "c" );
      protected final static CLOptionDescriptor CLEAR2          =
          new CLOptionDescriptor( "l", CLOptionDescriptor.ARGUMENT_DISALLOWED, CLEAR2_OPT, "l" );
      protected final static CLOptionDescriptor CLEAR3          =
          new CLOptionDescriptor( "e", CLOptionDescriptor.ARGUMENT_DISALLOWED, CLEAR3_OPT, "e" );
      protected final static CLOptionDescriptor CLEAR5          =
          new CLOptionDescriptor( "r", CLOptionDescriptor.ARGUMENT_DISALLOWED, CLEAR5_OPT, "r" );
      protected final static CLOptionDescriptor BLEE            =
          new CLOptionDescriptor( "blee", 
                                  CLOptionDescriptor.ARGUMENT_DISALLOWED, 
                                  BLEE_OPT, 
                                  "blee" );
      protected final static CLOptionDescriptor FILE            =
          new CLOptionDescriptor( "file",
                                  CLOptionDescriptor.ARGUMENT_REQUIRED,
                                  FILE_OPT,
                                  "the build file." );
  
      public void testFullParse()
      {
          final CLOptionDescriptor[] options = new CLOptionDescriptor[] 
          {
              YOU, ALL, CLEAR1, CLEAR2, CLEAR3, CLEAR5
          };
          
          final CLArgsParser parser = new CLArgsParser( ARGLIST1, options );
          
          assertNull( parser.getErrorString() );
          
          final List clOptions = parser.getArguments();
          final int size = clOptions.size();
          
          assertEquality( size, 8 );
          assertEquality( ((CLOption)clOptions.get( 0 )).getId(), YOU_OPT );
          assertEquality( ((CLOption)clOptions.get( 1 )).getId(), 0 );
          assertEquality( ((CLOption)clOptions.get( 2 )).getId(), ALL_OPT );
          assertEquality( ((CLOption)clOptions.get( 3 )).getId(), CLEAR1_OPT );
          assertEquality( ((CLOption)clOptions.get( 4 )).getId(), CLEAR2_OPT );
          assertEquality( ((CLOption)clOptions.get( 5 )).getId(), CLEAR3_OPT );
          assertEquality( ((CLOption)clOptions.get( 6 )).getId(), CLEAR5_OPT );
          assertEquality( ((CLOption)clOptions.get( 7 )).getId(), 0 );
      }
  
      public void testDuplicateOptions()
      {
          //"-Dstupid=idiot","are","--all","--all","here"
          final CLOptionDescriptor[] options = new CLOptionDescriptor[] 
          {
              DEFINE, ALL, CLEAR1
          };
  
          final CLArgsParser parser = new CLArgsParser( ARGLIST3, options );
  
          assertNull( parser.getErrorString() );
  
          final List clOptions = parser.getArguments();
          final int size = clOptions.size();
  
          assertEquality( size, 5 );
          assertEquality( ((CLOption)clOptions.get( 0 )).getId(), DEFINE_OPT );
          assertEquality( ((CLOption)clOptions.get( 1 )).getId(), 0 );
          assertEquality( ((CLOption)clOptions.get( 2 )).getId(), ALL_OPT );
          assertEquality( ((CLOption)clOptions.get( 3 )).getId(), ALL_OPT );
          assertEquality( ((CLOption)clOptions.get( 4 )).getId(), 0 );
      }
      
      public void testIncompatableOptions()
      {
          final CLOptionDescriptor[] options = new CLOptionDescriptor[] 
          {
              DEFINE, ALL, CLEAR1, BLEE
          };
          
          final CLArgsParser parser = new CLArgsParser( ARGLIST4, options );
          
          assertNotNull( parser.getErrorString() );
          
          final List clOptions = parser.getArguments();
          final int size = clOptions.size();
          
          assertEquality( size, 5 );
          assertEquality( ((CLOption)clOptions.get( 0 )).getId(), DEFINE_OPT );
          assertEquality( ((CLOption)clOptions.get( 1 )).getId(), 0 );
          assertEquality( ((CLOption)clOptions.get( 2 )).getId(), ALL_OPT );
          assertEquality( ((CLOption)clOptions.get( 3 )).getId(), BLEE_OPT );
          assertEquality( ((CLOption)clOptions.get( 4 )).getId(), 0 );
      }        
  
      public void testSingleArg()
      {
          final CLOptionDescriptor[] options = new CLOptionDescriptor[] 
          {
              FILE
          };
          
          final CLArgsParser parser = new CLArgsParser( ARGLIST5, options );
          
          assertNull( parser.getErrorString() );
          
          final List clOptions = parser.getArguments();
          final int size = clOptions.size();
          
          assertEquality( size, 1 );
          assertEquality( ((CLOption)clOptions.get( 0 )).getId(), FILE_OPT );
          assertEquality( ((CLOption)clOptions.get( 0 )).getArgument(), "myfile.txt" );
      }        
  
      public void test2ArgsParse()
      {
          //"-Dstupid=idiot","are","--all","here"
          final CLOptionDescriptor[] options = new CLOptionDescriptor[] 
          {
              DEFINE, ALL, CLEAR1
          };
          
          final CLArgsParser parser = new CLArgsParser( ARGLIST2, options );
          
          assertNull( parser.getErrorString() );
          
          final List clOptions = parser.getArguments();
          final int size = clOptions.size();
          
          assertEquality( size, 4 );
          assertEquality( ((CLOption)clOptions.get( 0 )).getId(), DEFINE_OPT );
          assertEquality( ((CLOption)clOptions.get( 1 )).getId(), 0 );
          assertEquality( ((CLOption)clOptions.get( 2 )).getId(), ALL_OPT );
          assertEquality( ((CLOption)clOptions.get( 3 )).getId(), 0 );
          
          final CLOption option = (CLOption)clOptions.get( 0 );
          assertEquality( "stupid", option.getArgument( 0 ) );
          assertEquality( "idiot", option.getArgument( 1 ) );
      }
  
      public void testPartParse()
      {
          final CLOptionDescriptor[] options = new CLOptionDescriptor[] 
          {
              YOU
          };
  
          final ParserControl control = new AbstractParserControl() 
          {
              public boolean isFinished( int lastOptionCode )
              {
                  return (lastOptionCode == YOU_OPT);
              }
          };
  
          final CLArgsParser parser = new CLArgsParser( ARGLIST1, options, control );
  
          assertNull( parser.getErrorString() );
  
          final List clOptions = parser.getArguments();
          final int size = clOptions.size();
  
          assertEquality( size, 1 );
          assertEquality( ((CLOption)clOptions.get( 0 )).getId(), YOU_OPT );
      }
  
      public void test2PartParse()
      {
          final CLOptionDescriptor[] options1 = new CLOptionDescriptor[] 
          {
              YOU
          };
  
          final CLOptionDescriptor[] options2 = new CLOptionDescriptor[] 
          {
              ALL, CLEAR1, CLEAR2, CLEAR3, CLEAR5
          };
  
          final ParserControl control1 = new AbstractParserControl() 
          {
              public boolean isFinished( int lastOptionCode )
              {
                  return (lastOptionCode == YOU_OPT);
              }
          };
  
          final CLArgsParser parser1 = new CLArgsParser( ARGLIST1, options1, control1 );
  
          assertNull( parser1.getErrorString() );
  
          final List clOptions1 = parser1.getArguments();
          final int size1 = clOptions1.size();
  
          assertEquality( size1, 1 );
          assertEquality( ((CLOption)clOptions1.get( 0 )).getId(), YOU_OPT );
  
          final CLArgsParser parser2 = 
              new CLArgsParser( parser1.getUnparsedArgs(), options2 );
  
          assertNull( parser2.getErrorString() );
  
          final List clOptions2 = parser2.getArguments();
          final int size2 = clOptions2.size();
  
          assertEquality( size2, 7 );
          assertEquality( ((CLOption)clOptions2.get( 0 )).getId(), 0 );
          assertEquality( ((CLOption)clOptions2.get( 1 )).getId(), ALL_OPT );
          assertEquality( ((CLOption)clOptions2.get( 2 )).getId(), CLEAR1_OPT );
          assertEquality( ((CLOption)clOptions2.get( 3 )).getId(), CLEAR2_OPT );
          assertEquality( ((CLOption)clOptions2.get( 4 )).getId(), CLEAR3_OPT );
          assertEquality( ((CLOption)clOptions2.get( 5 )).getId(), CLEAR5_OPT );
          assertEquality( ((CLOption)clOptions2.get( 6 )).getId(), 0 );
      }
  
      public void test2PartPartialParse()
      {
          final CLOptionDescriptor[] options1 = new CLOptionDescriptor[] 
          {
              YOU, ALL, CLEAR1
          };
  
          final CLOptionDescriptor[] options2 = new CLOptionDescriptor[] {};
  
          final ParserControl control1 = new AbstractParserControl() 
          {
              public boolean isFinished( final int lastOptionCode )
              {
                  return (lastOptionCode == CLEAR1_OPT);
              }
          };
  
          final CLArgsParser parser1 = new CLArgsParser( ARGLIST1, options1, control1 );
  
          assertNull( parser1.getErrorString() );
  
          final List clOptions1 = parser1.getArguments();
          final int size1 = clOptions1.size();
  
          assertEquality( size1, 4 );
          assertEquality( ((CLOption)clOptions1.get( 0 )).getId(), YOU_OPT );
          assertEquality( ((CLOption)clOptions1.get( 1 )).getId(), 0 );
          assertEquality( ((CLOption)clOptions1.get( 2 )).getId(), ALL_OPT );
          assertEquality( ((CLOption)clOptions1.get( 3 )).getId(), CLEAR1_OPT );
  
          assert( parser1.getUnparsedArgs()[0].equals("ler") );
          
          final CLArgsParser parser2 = 
              new CLArgsParser( parser1.getUnparsedArgs(), options2 );
  
          assertNull( parser2.getErrorString() );
  
          final List clOptions2 = parser2.getArguments();
          final int size2 = clOptions2.size();
  
          assertEquality( size2, 2 );
          assertEquality( ((CLOption)clOptions2.get( 0 )).getId(), 0 );
          assertEquality( ((CLOption)clOptions2.get( 1 )).getId(), 0 );
      }
  
      
      public void testDuplicatesFail()
      {
          final CLOptionDescriptor[] options = new CLOptionDescriptor[] 
          {
              YOU, ALL, CLEAR1, CLEAR2, CLEAR3, CLEAR5
          };
  
          //duplicate as
          final String[] DUPLICATE_ARGLIST = 
          {
              "--you","are","--all","-clear","kid"
          };
          
          final CLArgsParser parser = new CLArgsParser( ARGLIST1, options );
          
          assertNull( parser.getErrorString() );
      }
  
      public void testIncomplete2Args()
      {
          //"-Dstupid="
          final CLOptionDescriptor[] options = new CLOptionDescriptor[] 
          {
              DEFINE
          };
  
          final CLArgsParser parser = new CLArgsParser( new String[] { "-Dstupid=" }, options );
  
          assertNull( parser.getErrorString() );
  
          final List clOptions = parser.getArguments();
          final int size = clOptions.size();
  
          assertEquality( size, 1 );
          final CLOption option = (CLOption)clOptions.get( 0 );
          assertEquality( option.getId(), DEFINE_OPT );
          assertEquality( option.getArgument( 0 ), "stupid" );
          assertEquality( option.getArgument( 1 ), "" );
      }
      
      public void testIncomplete2ArgsMixed()
      {
          //"-Dstupid=","-c"
          final CLOptionDescriptor[] options = new CLOptionDescriptor[] 
          {
              DEFINE, CLEAR1
          };
  
          final String[] args = new String[] { "-Dstupid=", "-c" };
  
          final CLArgsParser parser = new CLArgsParser( args, options );
          
          assertNull( parser.getErrorString() );
          
          final List clOptions = parser.getArguments();
          final int size = clOptions.size();
          
          assertEquality( size, 2 );
          assertEquality( ((CLOption)clOptions.get( 1 )).getId(), CLEAR1_OPT );
          final CLOption option = (CLOption)clOptions.get( 0 );
          assertEquality( option.getId(), DEFINE_OPT );
          assertEquality( option.getArgument( 0 ), "stupid" );
          assertEquality( option.getArgument( 1 ), "" );
      }
  
      public void fail_testIncomplete2ArgsMixedNoEq()
      {
          //"-Dstupid","-c"
          final CLOptionDescriptor[] options = new CLOptionDescriptor[] 
          {
              DEFINE, CLEAR1
          };
          
          final String[] args = new String[] { "-Dstupid", "-c" };
          
          final CLArgsParser parser = new CLArgsParser( args, options );
          
          assertNull( parser.getErrorString() );
          
          final List clOptions = parser.getArguments();
          final int size = clOptions.size();
          
          assertEquality( size, 2 );
          assertEquality( ((CLOption)clOptions.get( 1 )).getId(), CLEAR1_OPT );
          final CLOption option = (CLOption)clOptions.get( 0 );
          assertEquality( option.getId(), DEFINE_OPT );
          assertEquality( option.getArgument( 0 ), "stupid" );
          assertEquality( option.getArgument( 1 ), "" );
      }
  }
  
  
  
  1.1                  jakarta-avalon/src/java/org/apache/avalon/util/datasource/DataSourceComponent.java
  
  Index: DataSourceComponent.java
  ===================================================================
  /* 
   * Copyright (C) The Apache Software Foundation. All rights reserved. 
   * 
   * This software is published under the terms of the Apache Software License 
   * version 1.1, a copy of which has been included with this distribution in 
   * the LICENSE file. 
   */ 
  package org.apache.avalon.util.datasource;
  
  import java.sql.Connection;
  import java.sql.SQLException;
  import org.apache.avalon.Component;
  import org.apache.avalon.Configurable;
  import org.apache.avalon.ThreadSafe;
  
  /**
   * The standard interface for DataSources in Avalon.
   *
   * @author <a href="mailto:bloritsch@apache.org">Berin Loritsch</a>
   * @version CVS $Revision: 1.1 $ $Date: 2001/02/24 03:59:38 $
   */
  public interface DataSourceComponent 
      extends Component, Configurable, ThreadSafe
  {
      /**
       * Gets the Connection to the database
       */
      Connection getConnection() 
          throws SQLException;
  }
  
  
  
  1.1                  jakarta-avalon/src/java/org/apache/avalon/util/datasource/J2eeDataSource.java
  
  Index: J2eeDataSource.java
  ===================================================================
  /* 
   * Copyright (C) The Apache Software Foundation. All rights reserved. 
   * 
   * This software is published under the terms of the Apache Software License 
   * version 1.1, a copy of which has been included with this distribution in 
   * the LICENSE file. 
   */ 
  package org.apache.avalon.util.datasource;
  
  import java.sql.Connection;
  import java.sql.SQLException;
  import javax.naming.Context;
  import javax.naming.InitialContext;
  import javax.naming.NamingException;
  import javax.sql.DataSource;
  import org.apache.avalon.Configuration;
  import org.apache.avalon.ConfigurationException;
  import org.apache.avalon.AbstractLoggable;
  
  /**
   * The J2EE implementation for DataSources in Cocoon.  This uses the
   * <code>javax.sql.DataSource</code> object and assumes that the
   * J2EE container pools the datasources properly.
   *
   * @author <a href="mailto:bloritsch@apache.org">Berin Loritsch</a>
   * @version CVS $Revision: 1.1 $ $Date: 2001/02/24 03:59:38 $
   */
  public class J2eeDataSource 
      extends AbstractLoggable
      implements DataSourceComponent
  {
      public final static String  JDBC_NAME     = "java:comp/env/jdbc/";
      protected DataSource        m_dataSource  = null;
  
      /**
       *  Configure and set up DB connection.  Here we set the connection
       *  information needed to create the Connection objects.  It must
       *  be called only once.
       *
       * @param conf The Configuration object needed to describe the
       *             connection.
       *
       * @throws ConfigurationException
       */
      public void configure( final Configuration configuration )
          throws ConfigurationException
      {
          if( null == m_dataSource ) 
          {
              final String databaseName = configuration.getChild("dbname").getValue();
  
              try
              {
                  final Context initialContext = new InitialContext();
                  m_dataSource = (DataSource)initialContext.lookup( JDBC_NAME + databaseName );
              } 
              catch( final NamingException ne ) 
              {
                  getLogger().error( "Problem with JNDI lookup of datasource", ne );
                  throw new ConfigurationException( "Could not use JNDI to find datasource", ne );
              }
          }
      }
  
      /** Get the database connection */
      public Connection getConnection()
          throws SQLException 
      {
          if( null == m_dataSource )
          {
              throw new SQLException( "Can not access DataSource object" );
          }
  
          return m_dataSource.getConnection();
      }
  }
  
  
  
  1.1                  jakarta-avalon/src/java/org/apache/avalon/util/datasource/JdbcConnection.java
  
  Index: JdbcConnection.java
  ===================================================================
  /* 
   * Copyright (C) The Apache Software Foundation. All rights reserved. 
   * 
   * This software is published under the terms of the Apache Software License 
   * version 1.1, a copy of which has been included with this distribution in 
   * the LICENSE file. 
   */ 
  package org.apache.avalon.util.datasource;
  
  import java.sql.CallableStatement;
  import java.sql.Connection;
  import java.sql.DatabaseMetaData;
  import java.sql.PreparedStatement;
  import java.sql.SQLException;
  import java.sql.SQLWarning;
  import java.sql.Statement;
  import java.util.Map;
  import org.apache.avalon.AbstractLoggable;
  import org.apache.avalon.Recyclable;
  import org.apache.avalon.util.pool.Pool;
  
  /**
   * The Connection object used in conjunction with the JdbcDataSource
   * object.
   *
   * TODO: Implement a configurable closed end Pool, where the Connection
   * acts like JDBC PooledConnections work.  That means we can limit the
   * total number of Connection objects that are created.
   *
   * @author <a href="mailto:bloritsch@apache.org">Berin Loritsch</a>
   * @version CVS $Revision: 1.1 $ $Date: 2001/02/24 03:59:38 $
   */
  public class JdbcConnection 
      extends AbstractLoggable
      implements Connection, Recyclable
  {
      private Connection         m_connection;
      private Pool               m_pool;
  
      public JdbcConnection( final Connection connection, final Pool pool )
      {
          m_connection = connection;
          m_pool = pool;
      }
  
      public Statement createStatement() 
          throws SQLException
      {
          return m_connection.createStatement();
      }
  
      public PreparedStatement prepareStatement( final String sql ) 
          throws SQLException
      {
          return m_connection.prepareStatement( sql );
      }
  
      public CallableStatement prepareCall( final String sql ) 
          throws SQLException
      {
          return m_connection.prepareCall( sql );
      }
  
      public String nativeSQL( final String sql ) 
          throws SQLException
      {
          return m_connection.nativeSQL( sql );
      }
  
      public void setAutoCommit( final boolean autoCommit ) 
          throws SQLException
      {
          m_connection.setAutoCommit( autoCommit );
      }
  
      public boolean getAutoCommit() 
          throws SQLException
      {
          return m_connection.getAutoCommit();
      }
  
      public void commit() 
          throws SQLException
      {
          m_connection.commit();
      }
  
      public void rollback() 
          throws SQLException
      {
          m_connection.rollback();
      }
  
      public void close() 
          throws SQLException
      {
          setAutoCommit( false );
          m_pool.put( this );
      }
  
      public void recycle() 
      {
          try { m_connection.close(); } 
          catch( final SQLException se )
          {
              getLogger().warn( "Could not close connection", se );
          }
      }
  
      public boolean isClosed() 
          throws SQLException
      {
          return m_connection.isClosed();
      }
  
      public DatabaseMetaData getMetaData() 
          throws SQLException
      {
          return m_connection.getMetaData();
      }
  
      public void setReadOnly( final boolean readOnly ) 
          throws SQLException
      {
          m_connection.setReadOnly( readOnly );
      }
  
      public boolean isReadOnly() 
          throws SQLException
      {
          return m_connection.isReadOnly();
      }
  
      public void setCatalog( final String catalog ) 
          throws SQLException
      {
          m_connection.setCatalog( catalog );
      }
  
      public String getCatalog() 
          throws SQLException
      {
          return m_connection.getCatalog();
      }
  
      public void setTransactionIsolation( final int level ) 
          throws SQLException
      {
          m_connection.setTransactionIsolation(level);
      }
  
      public int getTransactionIsolation() 
          throws SQLException
      {
          return m_connection.getTransactionIsolation();
      }
  
      public SQLWarning getWarnings() 
          throws SQLException
      {
          return m_connection.getWarnings();
      }
  
      public void clearWarnings() 
          throws SQLException
      {
          m_connection.clearWarnings();
      }
  
      public Statement createStatement( final int resultSetType, 
                                        final int resultSetConcurrency ) 
          throws SQLException
      {
          return m_connection.createStatement(resultSetType, resultSetConcurrency);
      }
  
      public PreparedStatement prepareStatement( final String sql, 
                                                 final int resultSetType, 
                                                 final int resultSetConcurrency ) 
          throws SQLException
      {
          return m_connection.prepareStatement( sql, resultSetType, resultSetConcurrency );
      }
  
      public CallableStatement prepareCall( final String sql, 
                                            final int resultSetType, 
                                            final int resultSetConcurrency )
          throws SQLException
      {
          return m_connection.prepareCall( sql, resultSetType, resultSetConcurrency );
      }
  
      public Map getTypeMap() 
          throws SQLException
      {
          return m_connection.getTypeMap();
      }
  
      public void setTypeMap( final Map map )
          throws SQLException
      {
          m_connection.setTypeMap( map );
      }
  }
  
  
  
  1.1                  jakarta-avalon/src/java/org/apache/avalon/util/datasource/JdbcConnectionPool.java
  
  Index: JdbcConnectionPool.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE file.
   */
  package org.apache.avalon.util.datasource;
  
  import java.sql.Connection;
  import java.sql.DriverManager;
  import java.sql.SQLException;
  import java.util.ArrayList;
  import java.util.List;
  import org.apache.avalon.AbstractLoggable;
  import org.apache.avalon.Disposable;
  import org.apache.avalon.Initializable;
  import org.apache.avalon.Poolable;
  import org.apache.avalon.Recyclable;
  import org.apache.avalon.util.pool.Pool;
  
  /**
   * The Pool implementation for JdbcConnections.  It uses a background
   * thread to manage the number of SQL Connections.
   *
   * @author <a href="mailto:bloritsch@apache.org">Berin Loritsch</a>
   * @version CVS $Revision: 1.1 $ $Date: 2001/02/24 03:59:38 $
   */
  public class JdbcConnectionPool
      extends AbstractLoggable
      implements Pool, Runnable, Disposable, Initializable
  {
      private final String           m_dburl;
      private final String           m_username;
      private final String           m_password;
      private final int              m_min;
      private final int              m_max;
      private int                    m_currentCount;
      private List                   m_active        = new ArrayList();
      private List                   m_ready         = new ArrayList();
      private boolean                m_monitoring    = true;
  
      public JdbcConnectionPool( final String url,
                                 final String username,
                                 final String password,
                                 final int min,
                                 final int max )
      {
          m_dburl = url;
          m_username = username;
          m_password = password;
  
          if( min < 0 )
          {
              getLogger().warn( "Minumum number of connections specified is " +
                                "less than 0, using 0" );
              m_min = 0;
          }
          else
          {
              m_min = min;
          }
  
          if( ( max < min ) || ( max < 1 ) )
          {
              getLogger().warn( "Maximum number of connections specified must be at " +
                                "least 1 and must be greater than the minumum number " +
                                "of connections" );
              m_max = ( min > 1 ) ? min : 1;
          }
          else
          {
              m_max = max;
          }
      }
  
      public void init()
      {
          for( int i = 0; i < m_min; i++ )
          {
              m_ready.add( createJdbcConnection() );
          }
  
          new Thread( this );
      }
  
      private JdbcConnection createJdbcConnection()
      {
          JdbcConnection connection = null;
  
          try
          {
              if( null == m_username )
              {
                  connection = new JdbcConnection( DriverManager.getConnection( m_dburl ), this );
                  connection.setLogger(getLogger());
                  m_currentCount++;
              }
              else
              {
                  connection =
                      new JdbcConnection( DriverManager.getConnection( m_dburl,
                                                                       m_username,
                                                                       m_password ),
                                          this);
                  connection.setLogger(getLogger());
                  m_currentCount++;
              }
          }
  
          catch( final SQLException se )
          {
              getLogger().error( "Could not create connection to database", se );
          }
  
          getLogger().debug( "JdbcConnection object created" );
          return connection;
      }
  
      private void recycle( final Recyclable obj )
      {
          getLogger().debug( "JdbcConnection object recycled" );
          obj.recycle();
      }
  
      public Poolable get()
          throws Exception
      {
          Poolable obj = null;
  
          if( 0 == m_ready.size() )
          {
              if( m_currentCount < m_max )
              {
                  synchronized( m_active )
                  {
                      obj = createJdbcConnection();
                      m_active.add( obj );
                  }
              }
              else
              {
                  throw new SQLException("There are no more Connections available");
              }
          }
          else
          {
              synchronized( m_active )
              {
                  obj = (Poolable)m_ready.remove( 0 );
                  m_active.add( obj );
              }
          }
  
          getLogger().debug( "JdbcConnection '" + m_dburl +
                             "' has been requested from pool." );
  
          return obj;
      }
  
      public synchronized void put( final Poolable obj )
      {
          int location = m_active.indexOf( obj );
          m_active.remove( obj );
  
          if( m_monitoring )
          {
              m_ready.add( obj );
          }
  
          getLogger().debug( "JdbcConnection '" + m_dburl + "' has been returned to the pool." );
      }
  
      public void run()
      {
          while( m_monitoring )
          {
              synchronized( m_ready )
              {
                  if( m_ready.size() < m_min )
                  {
                      getLogger().debug( "There are not enough Connections for pool: " + m_dburl );
                      
                      while( ( m_ready.size() < m_min ) && ( m_currentCount < m_max ) )
                      {
                          m_ready.add( createJdbcConnection() );
                      }
                  }
                  else
                  {
                      getLogger().debug( "Trimming excess fat from pool: " + m_dburl );
  
                      while( m_ready.size() > m_min ) 
                      {
                          recycle( (Recyclable)m_ready.remove( 0 ) );
                      } 
                  }
              }
  
              try
              {
                  Thread.sleep( 1 * 60 * 1000 );
              } 
              catch( final InterruptedException ie )
              {
                  getLogger().warn( "Caught an InterruptedException", ie );
              }
          }
      }
  
      public void dispose()
      {
          m_monitoring = false;
  
          synchronized (m_ready)
          {
              while( !m_ready.isEmpty() )
              {
                  recycle( (Recyclable)m_ready.remove( 0 ) );
              }
          }
      }
  }
  
  
  
  1.1                  jakarta-avalon/src/java/org/apache/avalon/util/datasource/JdbcDataSource.java
  
  Index: JdbcDataSource.java
  ===================================================================
  /* 
   * Copyright (C) The Apache Software Foundation. All rights reserved. 
   * 
   * This software is published under the terms of the Apache Software License 
   * version 1.1, a copy of which has been included with this distribution in 
   * the LICENSE file. 
   */ 
  package org.apache.avalon.util.datasource;
  
  import java.sql.Connection;
  import java.sql.SQLException;
  import org.apache.avalon.Configuration;
  import org.apache.avalon.ConfigurationException;
  import org.apache.avalon.Disposable;
  import org.apache.avalon.AbstractLoggable;
  
  /**
   * The Default implementation for DataSources in Avalon.  This uses the
   * normal <code>java.sql.Connection</code> object and
   * <code>java.sql.DriverManager</code>.
   *
   * @author <a href="mailto:bloritsch@apache.org">Berin Loritsch</a>
   * @version CVS $Revision: 1.1 $ $Date: 2001/02/24 03:59:38 $
   */
  public class JdbcDataSource 
      extends AbstractLoggable
      implements DataSourceComponent
  {
      protected JdbcConnectionPool        m_pool;
  
      /**
       *  Configure and set up DB connection.  Here we set the connection
       *  information needed to create the Connection objects.  It must
       *  be called only once.
       *
       * @param conf The Configuration object needed to describe the
       *             connection.
       *
       * @throws ConfigurationException
       */
      public void configure( final Configuration configuration )
          throws ConfigurationException
      {
          if( null == m_pool )
          {
              final String dburl = configuration.getChild( "dburl" ).getValue();
              final String user = configuration.getChild( "user" ).getValue( null );
              final String passwd = configuration.getChild( "password" ).getValue( null );
              final Configuration controler = configuration.getChild( "pool-controller" );
  
              final int min = controler.getAttributeAsInt( "min", 0 );
              final int max = controler.getAttributeAsInt( "max", 3 );
  
              m_pool = new JdbcConnectionPool( dburl, user, passwd, min, max );
              m_pool.setLogger(getLogger());
              m_pool.init();
          }
      }
  
      /** Get the database connection */
      public Connection getConnection()
          throws SQLException 
      {
          try { return (Connection) m_pool.get(); } 
          catch( final Exception e )
          {
              getLogger().error( "Could not return Connection", e );
              throw new SQLException( e.getMessage() );
          }
      }
  
      /** Dispose properly of the pool */
      public void dispose() 
      {
          m_pool.dispose();
          m_pool = null;
      }
  }
  
  
  
  1.1                  jakarta-avalon/src/java/org/apache/avalon/util/datasource/test/DataSourceTestlet.java
  
  Index: DataSourceTestlet.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE file.
   */
  package org.apache.avalon.util.datasource.test;
  
  import org.apache.testlet.AbstractTestlet;
  import org.apache.avalon.Configuration;
  import org.apache.avalon.ConfigurationException;
  import org.apache.avalon.DefaultConfiguration;
  import org.apache.avalon.util.datasource.DataSourceComponent;
  import org.apache.avalon.util.datasource.JdbcDataSource;
  import org.apache.log.LogKit;
  import java.sql.SQLException;
  import java.sql.Connection;
  import java.util.Random;
  
  /**
   * Test the DataSource Component.  I don't know how to make this generic,
   * so I'll throw some bones out there, and hope someone can set this up
   * better.
   *
   * @author <a href="mailto:bloritsch@apache.org">Berin Loritsch</a>
   */
  public class DataSourceTestlet extends AbstractTestlet {
      static final Configuration conf;
      static final String LOCATION = "Testlet Framework";
  
      static {
          DefaultConfiguration dc = new DefaultConfiguration("", LOCATION);
          DefaultConfiguration pool = new DefaultConfiguration("pool-controller", LOCATION);
          DefaultConfiguration dburl = new DefaultConfiguration("dburl", LOCATION);
          DefaultConfiguration user = new DefaultConfiguration("user", LOCATION);
          DefaultConfiguration password = new DefaultConfiguration("password", LOCATION);
          pool.addAttribute("min", "5");
          pool.addAttribute("max", "10");
          dc.addChild(pool);
          dburl.appendValueData("jdbc:odbc://test");
          dc.addChild(dburl);
          user.appendValueData("test");
          dc.addChild(user);
          password.appendValueData("test");
          dc.addChild(password);
          conf = dc;
  
          LogKit.setGlobalPriority(org.apache.log.Priority.INFO);
  
          try {
              Class.forName("Your Driver Class Here");
          } catch (Exception e) {
              LogKit.getLoggerFor("test").error(e.getMessage(), e);
          }
      }
  
      public void testOverAllocation() {
          boolean result = false;
          JdbcDataSource ds = new JdbcDataSource();
          ds.setLogger(LogKit.getLoggerFor("test"));
  
          try {
              ds.configure(conf);
          } catch (ConfigurationException ce) {
              assert("Over Allocation Test", false);
          }
  
          try {
              for (int i = 0; i < 11; i++) {
                  ds.getConnection();
              }
          } catch (SQLException se) {
              result = true;
              LogKit.getLoggerFor("test").info("The test was successful");
          }
  
          assert("Over Allocation Test", result);
      }
  
      public void testNormalUse() {
          boolean result = true;
          JdbcDataSource ds = new JdbcDataSource();
          ds.setLogger(LogKit.getLoggerFor("test"));
  
          try {
              ds.configure(conf);
          } catch (ConfigurationException ce) {
              LogKit.getLoggerFor("test").error(ce.getMessage(), ce);
              assert("Over Allocation Test", false);
          }
  
          Thread one = new Thread(new ConnectionThread(ds));
          Thread two = new Thread(new ConnectionThread(ds));
  
  
          one.start();
          two.start();
  
          while (one.isAlive() || two.isAlive()) {
              try {
                  Thread.sleep(100);
              } catch (InterruptedException ie) {
                  // Ignore
              }
          }
  
          LogKit.getLoggerFor("test").info("If you saw no failure messages, then the test passed");
          assert("Normal Use Test", result);
      }
  
      class ConnectionThread implements Runnable {
          DataSourceComponent datasource;
  
          ConnectionThread(DataSourceComponent dc) {
              this.datasource = dc;
          }
  
          public void run() {
              long end = System.currentTimeMillis() + 5000; // run for 5 seconds
  
              while (System.currentTimeMillis() < end) {
                  try {
                      Connection con = datasource.getConnection();
                      long sleeptime = (long) (Math.random() * 100.0);
                      Thread.sleep(sleeptime);
                      con.close();
                  } catch (SQLException se) {
                      LogKit.getLoggerFor("test").info("Failed to get Connection, test failed");
                      assert("Normal Use Test", false);
                  } catch (InterruptedException ie) {
                      // Ignore
                  }
              }
          }
      }
  }
  
  
  1.1                  jakarta-avalon/src/java/org/apache/avalon/util/i18n/ResourceGroup.java
  
  Index: ResourceGroup.java
  ===================================================================
  /* 
   * Copyright (C) The Apache Software Foundation. All rights reserved. 
   * 
   * This software is published under the terms of the Apache Software License 
   * version 1.1, a copy of which has been included with this distribution in 
   * the LICENSE file. 
   */ 
  package org.apache.avalon.util.i18n;
  
  import java.text.MessageFormat;
  import java.util.HashMap;
  import java.util.Locale;
  import java.util.MissingResourceException;
  import java.util.Random;
  import java.util.ResourceBundle;
  
  /**
   * A class used to manage resource bundles.
   */
  public class ResourceGroup
  {
      protected final static Random  RANDOM        = new Random();
      protected final HashMap        m_bundles     = new HashMap();
      protected final Locale         m_locale;
  
      /**
       * Create a ResourceGroup to manage resource bundles for a particular locale.
       *
       * @param locale the locale
       */
      public ResourceGroup( final Locale locale ) 
      {
          m_locale = locale;
      }
  
      public Locale getLocale()
      {
          return m_locale;
      }
  
      public String format( final String base, final String key, final Object[] args ) 
      {
          final String pattern = getPattern( base, key );
          final MessageFormat messageFormat = new MessageFormat( pattern );
          messageFormat.setLocale( m_locale );
          return messageFormat.format( args );
      }
  
      public ResourceBundle getBundle( final String base ) 
          throws MissingResourceException
      {
          ResourceBundle result = (ResourceBundle) m_bundles.get( base );
          if( null != result ) return result;
          
          // bundle wasn't cached, so load it, cache it, and return it.
          final ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
          result = ResourceBundle.getBundle( base, m_locale, classLoader );
  
          m_bundles.put( base, result );
  
          return result;                
      }
  
      public String getPattern( final String base, final String key ) 
          throws MissingResourceException
      {
          final ResourceBundle bundle = getBundle( base );
          final Object object = bundle.getObject( key );
          
          // is the resource a single string
          if( object instanceof String ) 
          {
              return (String)object;
          }
          else if( object instanceof String[] )
          {
              //if string array then randomly pick one
              final String[] strings = (String[])object;
              return strings[ RANDOM.nextInt( strings.length ) ];
          }
          else
          {
              throw new MissingResourceException( "Unable to find resource of appropriate type.",
                                                  "java.lang.String",
                                                  key );
          }
      }
  }
  
  
  
  1.1                  jakarta-avalon/src/java/org/apache/avalon/util/i18n/XMLResourceBundle.java
  
  Index: XMLResourceBundle.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE file.
   */
  package org.apache.avalon.util.i18n;
  
  /**
   * @author <a href="mailto:mengelhart@earthtrip.com">Mike Engelhart</a>
   * @author <a href="mailto:neeme@one.lv">Neeme Praks</a>
   * @author <a href="mailto:oleg@one.lv">Oleg Podolsky</a>
   * @version $Id: XMLResourceBundle.java,v 1.1 2001/02/24 03:59:39 donaldp Exp $
   */
  
  /** JDK classes **/
  import java.io.IOException;
  import java.lang.ref.SoftReference;
  import java.util.Hashtable;
  import java.util.Locale;
  import java.util.MissingResourceException;
  
  /** W3C DOM classes **/
  import org.w3c.dom.Document;
  import org.w3c.dom.Element;
  import org.w3c.dom.Node;
  import org.w3c.dom.NodeList;
  import org.w3c.dom.NamedNodeMap;
  
  /** Xerces classes **/
  import org.apache.xerces.dom.DocumentImpl;
  import org.apache.xerces.dom.TextImpl;
  import org.apache.xerces.parsers.DOMParser;
  import org.xml.sax.SAXException;
  
  /** Xalan classes **/
  import org.apache.xalan.xpath.XPathSupport;
  import org.apache.xalan.xpath.XPath;
  import org.apache.xalan.xpath.XPathProcessorImpl;
  import org.apache.xalan.xpath.xml.XMLParserLiaisonDefault;
  import org.apache.xalan.xpath.xml.PrefixResolverDefault;
  import org.apache.xalan.xpath.XObject;
  
  public class XMLResourceBundle {
      // Cache for storing string values for existing XPaths
      private Hashtable cacheIS = new Hashtable();
      // Cache for storing non-existing XPaths
      private Hashtable cacheNO = new Hashtable();
  
      private Document resource;
      public String bundleName = ""; //used by getLocale()
      protected XMLResourceBundle parent = null;
  
  
      public XMLResourceBundle( Document doc, String name, XMLResourceBundle p ) {
          System.out.print( "Constructing XMLResourceBundle: " + name );
          if ( p != null )
              System.out.println( "  --> parent: " + p.bundleName );
          else
              System.out.println( "  --> parent: " + p );
  
          this.resource = doc;
          this.bundleName = name;
          this.parent = p;
      }
  
      public void addToCache( String key, String value ) {
          cacheIS.put( key, value );
      }
  
      public Document getResource() {
          return this.resource;
      }
  
      // gets string without throwing an exception, returns empty string instead
      public String getStringSimple( String xPathKey ) {
          String result = "";
          try {
              result = getString( xPathKey );
          } catch ( MissingResourceException e ) {
              // do nothing
          }
  
  
  
          return result;
      }
  
      public String getString( String xPathKey ) throws MissingResourceException {
          if ( cacheIS.containsKey( xPathKey ) )
              return ( String ) cacheIS.get( xPathKey );
          if ( cacheNO.containsKey( xPathKey ) )
              new MissingResourceException( "Unable to locate resource: " + xPathKey, "XMLResourceBundle", xPathKey );
  
          Node root = this.resource.getDocumentElement();
          try {
              Node node = XPathAPI.selectSingleNode( root, xPathKey );
              if ( node != null ) {
                  String temp = getTextNodeAsString( node );
                  addToCache( xPathKey, temp );
                  return temp;
              } else {
                  if ( this.parent != null )
                      return this.parent.getString( xPathKey );
                  else
                      throw new Exception();
              }
          } catch ( Exception e ) {
              // no nodes returned??
              cacheNO.put( xPathKey, "" );
              throw new MissingResourceException( "Unable to locate resource: " + xPathKey, "XMLResourceBundle", xPathKey );
          }
      }
  
      public String getString( Node role, String key ) throws MissingResourceException {
          try {
              Node node = XPathAPI.selectSingleNode( role, key );
              if ( node != null )
                  return getTextNodeAsString( node );
              else
                  throw new Exception();
          } catch ( Exception e ) {
              // no nodes returned??
              throw new MissingResourceException( "Unable to locate resource: " + key, "XMLResourceBundle", key );
          }
      }
  
      private String getTextNodeAsString( Node node ) throws MissingResourceException {
          node = node.getFirstChild();
          if ( node.getNodeType() == Node.TEXT_NODE )
              return ( ( TextImpl ) node ).getData();
          else
              throw new MissingResourceException( "Unable to locate XMLResourceBundle", "XMLResourceBundleFactory", "" );
      }
  
      public Node getRole( String xPath ) {
          Node root = resource.getDocumentElement();
          try {
              Node node = XPathAPI.selectSingleNode( root, xPath );
              if ( node != null )
                  return node;
              else
                  throw new Exception();
          } catch ( Exception e ) {
              // no nodes returned??
              throw new MissingResourceException( "Unable to locate resource: " + xPath, "XMLResourceBundle", xPath );
          }
      }
  
      public Node getRole( Node role, String xPath ) {
          try {
              Node node = XPathAPI.selectSingleNode( role, xPath );
              if ( node != null )
                  return node;
              else
                  throw new Exception();
          } catch ( Exception e ) {
              // no nodes returned??
              throw new MissingResourceException( "Unable to locate resource: " + xPath, "XMLResourceBundle", xPath );
          }
      }
  
      public XPath createXPath( String str, Node namespaceNode ) throws SAXException {
          XPathSupport xpathSupport = new XMLParserLiaisonDefault();
  
          if ( null == namespaceNode )
              throw new SAXException( "A namespace node is required to resolve prefixes!" );
  
          PrefixResolverDefault prefixResolver = new PrefixResolverDefault( ( namespaceNode.getNodeType() == Node.DOCUMENT_NODE ) ? ( ( Document ) namespaceNode ).getDocumentElement() : namespaceNode );
  
          // Create the XPath object.
          XPath xpath = new XPath();
  
          // Create a XPath parser.
          XPathProcessorImpl parser = new XPathProcessorImpl( xpathSupport );
          parser.initXPath( xpath, str, prefixResolver );
  
          return xpath;
      }
  
      public Locale getLocale() {
          String bundle = bundleName.substring( 0, bundleName.indexOf( ".xml" ) );
          int localeStart = bundle.indexOf( "_" );
          if ( localeStart == -1 )
              return new Locale( "", "", "" );
          bundle = bundle.substring( localeStart + 1 );
          localeStart = bundle.indexOf( "_" );
          if ( localeStart == -1 )
              return new Locale( bundle, "", "" );
  
          String lang = bundle.substring( 0, localeStart );
          bundle = bundle.substring( localeStart + 1 );
          localeStart = bundle.indexOf( "_" );
          if ( localeStart == -1 )
              return new Locale( lang, bundle, "" );
  
          String country = bundle.substring( 0, localeStart );
          bundle = bundle.substring( localeStart + 1 );
          return new Locale( lang, country, bundle );
      }
  }
  
  
  
  
  1.1                  jakarta-avalon/src/java/org/apache/avalon/util/i18n/XMLResourceBundleFactory.java
  
  Index: XMLResourceBundleFactory.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included  with this distribution in
   * the LICENSE file.
   */
  package org.apache.avalon.util.i18n;
  
  /**
   * @author <a href="mailto:mengelhart@earthtrip.com">Mike Engelhart</a>
   * @author <a href="mailto:neeme@one.lv">Neeme Praks</a>
   * @author <a href="mailto:oleg@one.lv">Oleg Podolsky</a>
   * @version $Id: XMLResourceBundleFactory.java,v 1.1 2001/02/24 03:59:39 donaldp Exp $
    */
  
  /** JDK classes **/
  
  
  /** W3C DOM classes **/
  /** Xerces-J classes **/
  //import java.lang.ref.SoftReference;
  import java.io.IOException;
  import java.util.Hashtable;
  import java.util.Locale;
  import java.util.MissingResourceException;
  import java.util.Vector;
  import org.apache.xerces.dom.DocumentImpl;
  import org.apache.xerces.dom.TextImpl;
  import org.apache.xerces.parsers.DOMParser;
  import org.w3c.dom.Document;
  import org.w3c.dom.Element;
  import org.w3c.dom.NamedNodeMap;
  import org.w3c.dom.Node;
  import org.w3c.dom.NodeList;
  import org.xml.sax.SAXException;
  
  public class XMLResourceBundleFactory {
      protected static Hashtable cache = new Hashtable();
      protected static String directory;
  
      protected XMLResourceBundleFactory() {}
  
  
  
  
      public static XMLResourceBundle getBundle( String name ) throws MissingResourceException {
          return getBundle( name, Locale.getDefault() );
      }
  
      public static XMLResourceBundle getBundle( String name, Locale loc ) throws MissingResourceException {
          return getBundle( name, loc, false );
      }
  
      public static XMLResourceBundle getBundle( String name, Locale loc, boolean cacheAtStartup ) throws MissingResourceException {
          XMLResourceBundle parent = null;
          String bundleName = getBundleName( name, loc );
          // first look in the cache - if there grab it
          XMLResourceBundle bundle = getCachedBundle( bundleName );
          if ( bundle != null )
              return bundle;
  
          // if bundle is not in cache try loading the bundle using the given name and locale bundleName
          Document doc = null;
          doc = loadResourceBundle( bundleName );
          if ( doc != null ) {
              if ( ! loc.getLanguage().equals( "" ) )
                  parent = getParentBundle( name, loc, cacheAtStartup );
              bundle = new XMLResourceBundle( doc, bundleName, parent );
              if ( cacheAtStartup )
                  storeTextElements( bundle, bundle.getResource(), "" );
              updateCache( bundleName, bundle );
              return bundle;
          }
          // if the locale's language is "" then we've already tried to load the default resource and it's not available
          while ( ! loc.getLanguage().equals( "" ) ) {
              // if the given bundle name is not found, then try loading using a shortened Locale
              loc = getParentLocale( loc );
              bundleName = getBundleName( name, loc );
              // first look in the cache - if there grab it and return
              bundle = getCachedBundle( bundleName );
              if ( bundle != null )
                  return bundle;
  
              // try loading the bundle using the given name and locale bundleName
              doc = loadResourceBundle( bundleName );
              if ( doc != null ) {
                  if ( ! loc.getLanguage().equals( "" ) )
                      parent = getParentBundle( name, loc, cacheAtStartup );
                  bundle = new XMLResourceBundle( doc, bundleName, parent );
                  if ( cacheAtStartup )
                      storeTextElements( bundle, bundle.getResource(), "" );
                  updateCache( bundleName, bundle );
                  return bundle;
              }
          }
          throw new MissingResourceException( "Unable to locate resource: " + bundleName, "XMLResourceBundleFactory", "" );
      }
  
      protected synchronized static XMLResourceBundle getParentBundle( String name, Locale loc ) {
          return getParentBundle( name, loc, false );
      }
  
      protected synchronized static XMLResourceBundle getParentBundle( String name, Locale loc, boolean cacheAtStartup ) {
          loc = getParentLocale( loc );
          String bundleName = getBundleName( name, loc );
          Document doc = loadResourceBundle( bundleName );
          XMLResourceBundle bundle = null;
          if ( doc != null ) {
              if ( ! loc.getLanguage().equals( "" ) )
                  bundle = getParentBundle( name, loc );
              bundle = new XMLResourceBundle( doc, bundleName, bundle );
              if ( cacheAtStartup )
                  storeTextElements( bundle, bundle.getResource(), "" );
              updateCache( bundleName, bundle );
          }
          return bundle;
      }
  
      // this method returns the next locale up the parent hierarchy
      // e.g.; the parent of new Locale("en","us","mac")
      // would be new Locale("en", "us", "");
      protected static Locale getParentLocale( Locale loc ) {
          if ( loc.getVariant().equals( "" ) ) {
              if ( loc.getCountry().equals( "" ) )
                  loc = new Locale( "", "", "" );
              else
                  loc = new Locale( loc.getLanguage(), "", "" );
          } else
              loc = new Locale( loc.getLanguage(), loc.getCountry(), "" );
  
          return loc;
      }
  
      protected synchronized static XMLResourceBundle getCachedBundle( String bundleName ) {
          /*
            SoftReference ref = (SoftReference)(cache.get(bundleName));
            if (ref != null)
            return (XMLResourceBundle) ref.get();
            else
            return null;
          */ 
          return ( XMLResourceBundle ) ( cache.get( bundleName ) );
      }
  
      protected synchronized static void updateCache( String bundleName, XMLResourceBundle bundle ) {
          cache.put( bundleName, bundle );
      }
  
      /*        protected static String getBundleName(String name, Locale loc)
              {
          StringBuffer sb = new StringBuffer(name);
          if (! loc.getLanguage().equals(""))
          {
          sb.append("_");
          sb.append(loc.getLanguage());
          }
          if (! loc.getCountry().equals(""))
          {
          sb.append("_");
          sb.append(loc.getCountry());
          }
          if (! loc.getVariant().equals(""))
          {
          sb.append("_");
          sb.append(loc.getVariant());
          }
          // should all the files have an extension of .xml?  Seems reasonable
          sb.append(".xml");
       
          return sb.toString();
              }
      */
  
      protected static String getBundleName( String name, Locale loc ) {
          String lang = loc.getLanguage();
          StringBuffer sb = new StringBuffer( getDirectory() );
  
          if ( lang.length() > 0 ) sb.append( "/" ).append( lang );
          sb.append( "/" ).append( name ).append( ".xml" );
  
          return sb.toString();
      }
  
      public static XMLResourceBundle getBundle( String fileName, String localeName ) throws MissingResourceException {
          return getBundle( fileName, new Locale( localeName, localeName ) );
      }
  
      public static XMLResourceBundle getBundleFromFilename( String bundleName ) throws MissingResourceException {
          return getBundleFromFilename( bundleName, true );
      }
  
      public static XMLResourceBundle getBundleFromFilename( String bundleName, boolean cacheAtStartup ) throws MissingResourceException {
          Document doc = null;
          doc = loadResourceBundle( getDirectory() + "/" + bundleName );
  
          XMLResourceBundle bundle = getCachedBundle( bundleName );
          if ( bundle != null )
              return bundle;
  
          if ( doc != null ) {
              bundle = new XMLResourceBundle( doc, bundleName, null );
              if ( cacheAtStartup )
                  storeTextElements( bundle, bundle.getResource(), "" );
              updateCache( bundleName, bundle );
              return bundle;
          }
          throw new MissingResourceException( "Unable to locate resource: " + bundleName, "XMLResourceBundleFactory", "" );
      }
  
      // Load the XML document based on bundleName
      protected static Document loadResourceBundle( String bundleName ) {
          try {
              DOMParser parser = new DOMParser();
              parser.parse( bundleName );
              return parser.getDocument();
          } catch ( IOException e ) {
              return null;
          }
          catch ( SAXException e ) {
              return null;
          }
      }
  
      public static void setDirectory( String dir ) {
          directory = dir;
      }
  
      public static String getDirectory() {
          return ( directory != null ? directory : "" );
      }
  
      // Steps through the bundle tree and stores all text element values
      // in bundle's cache, and also stores attributes for all element nodes.
      // Parent must be am element-type node.
      private static void storeTextElements( XMLResourceBundle bundle, Node parent, String pathToParent ) {
          NodeList children = parent.getChildNodes();
          int childnum = children.getLength();
  
          for ( int i = 0; i < childnum; i++ ) {
              Node child = children.item( i );
  
              if ( child.getNodeType() == Node.ELEMENT_NODE ) {
                  String pathToChild = pathToParent + '/' + child.getNodeName();
  
                  NamedNodeMap attrs = child.getAttributes();
                  if ( attrs != null ) {
                      Node temp = null;
                      String pathToAttr = null;
                      int attrnum = attrs.getLength();
                      for ( int j = 0; j < attrnum; j++ ) {
                          temp = attrs.item( j );
                          pathToAttr = "/@" + temp.getNodeName();
                          bundle.addToCache( pathToChild + pathToAttr, temp.getNodeValue() );
                      }
                  }
  
                  String childValue = getTextValue( child );
                  if ( childValue != null )
                      bundle.addToCache( pathToChild, childValue );
                  else
                      storeTextElements( bundle, child, pathToChild );
              }
          }
      }
  
      private static String getTextValue( Node element ) {
          NodeList list = element.getChildNodes();
          int listsize = list.getLength();
  
          Node item = null;
          String itemValue = null;
  
          for ( int i = 0; i < listsize; i++ ) {
              item = list.item( i );
              if ( item.getNodeType() != Node.TEXT_NODE ) return null;
              itemValue = item.getNodeValue(); if ( itemValue == null ) return null;
              itemValue = itemValue.trim(); if ( itemValue.length() == 0 ) return null;
              return itemValue;
          }
          return null;
      }
  }
  
  
  
  1.1                  jakarta-avalon/src/java/org/apache/avalon/util/i18n/XPathAPI.java
  
  Index: XPathAPI.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included  with this distribution in
   * the LICENSE file.
   */
  package org.apache.avalon.util.i18n;
  
  import org.xml.sax.SAXException;
  import org.w3c.dom.Node;
  import org.w3c.dom.Document;
  import org.w3c.dom.NodeList;
  import org.apache.xalan.xpath.XPathSupport;
  import org.apache.xalan.xpath.XPath;
  import org.apache.xalan.xpath.XPathProcessorImpl;
  import org.apache.xalan.xpath.xml.XMLParserLiaisonDefault;
  import org.apache.xalan.xpath.xml.PrefixResolverDefault;
  import org.apache.xalan.xpath.XObject;
  
  /**
   * The methods in this class are convenience methods into the
   * low-level XPath API.  We would like to eventually move these
   * methods into the XPath core, but would like to do some peer
   * review first to make sure we have it right.
   * Please note that these methods execute pure XPaths. They do not
   * implement those parts of XPath extended by XSLT, such as the
   * document() function).  If you want to install XSLT functions, you
   * have to use the low-level API.
   * These functions tend to be a little slow, since a number of objects must be
   * created for each evaluation.  A faster way is to precompile the
   * XPaths using the low-level API, and then just use the XPaths
   * over and over.
   *
   * @author <a href="mailto:mengelhart@earthtrip.com">Mike Engelhart</a>
   * @see http://www.w3.org/TR/xpath
   * @version $Id: XPathAPI.java,v 1.1 2001/02/24 03:59:39 donaldp Exp $
   */
  public class XPathAPI {
      /**
       * Use an XPath string to select a single node. XPath namespace
       * prefixes are resolved from the context node, which may not
       * be what you want (see the next method).
       *
       * @param contextNode The node to start searching from.
       * @param str A valid XPath string.
       * @return The first node found that matches the XPath, or null.
       */
      public static Node selectSingleNode( Node contextNode, String str )
      throws SAXException {
          return selectSingleNode( contextNode, str, contextNode );
      }
  
      /**
       * Use an XPath string to select a single node.
       * XPath namespace prefixes are resolved from the namespaceNode.
       *
       * @param contextNode The node to start searching from.
       * @param str A valid XPath string.
       * @param namespaceNode The node from which prefixes in the XPath will be resolved to namespaces.
       * @return The first node found that matches the XPath, or null.
       */
      public static Node selectSingleNode( Node contextNode, String str, Node namespaceNode )
      throws SAXException {
          // Have the XObject return its result as a NodeSet.
          NodeList nl = selectNodeList( contextNode, str, namespaceNode );
  
          // Return the first node, or null
          return ( nl.getLength() > 0 ) ? nl.item( 0 ) : null;
      }
  
      /**
       * Use an XPath string to select a nodelist.
       * XPath namespace prefixes are resolved from the contextNode.
       *
       * @param contextNode The node to start searching from.
       * @param str A valid XPath string.
       * @return A nodelist, should never be null.
       */
      public static NodeList selectNodeList( Node contextNode, String str )
      throws SAXException {
          return selectNodeList( contextNode, str, contextNode );
      }
  
      /**
        * Use an XPath string to select a nodelist.
        * XPath namespace prefixes are resolved from the namespaceNode.
        *
        * @param contextNode The node to start searching from.
        * @param str A valid XPath string.
        * @param namespaceNode The node from which prefixes in the XPath will be resolved to namespaces.
        * @return A nodelist, should never be null.
        */
      public static NodeList selectNodeList( Node contextNode, String str, Node namespaceNode )
      throws SAXException {
          // Execute the XPath, and have it return the result
          XObject list = eval( contextNode, str, namespaceNode );
  
          // Have the XObject return its result as a NodeSet.
          return list.nodeset();
  
      }
  
      /**
       * Evaluate XPath string to an XObject.  Using this method,
       * XPath namespace prefixes will be resolved from the namespaceNode.
       * @param contextNode The node to start searching from.
       * @param str A valid XPath string.
       * @param namespaceNode The node from which prefixes in the XPath will be resolved to namespaces.
       * @return An XObject, which can be used to obtain a string, number, nodelist, etc, should never be null.
       * @see org.apache.xalan.xpath.XObject
       * @see org.apache.xalan.xpath.XNull
       * @see org.apache.xalan.xpath.XBoolean
       * @see org.apache.xalan.xpath.XNumber
       * @see org.apache.xalan.xpath.XString
       * @see org.apache.xalan.xpath.XRTreeFrag
       */
      public static XObject eval( Node contextNode, String str )
      throws SAXException {
          return eval( contextNode, str, contextNode );
      }
  
      /**
       * Evaluate XPath string to an XObject.
       * XPath namespace prefixes are resolved from the namespaceNode.
       * The implementation of this is a little slow, since it creates
       * a number of objects each time it is called.  This could be optimized
       * to keep the same objects around, but then thread-safety issues would arise.
       *
       * @param contextNode The node to start searching from.
       * @param str A valid XPath string.
       * @param namespaceNode The node from which prefixes in the XPath will be resolved to namespaces.
       * @return An XObject, which can be used to obtain a string, number, nodelist, etc, should never be null.
       * @see org.apache.xalan.xpath.XObject
       * @see org.apache.xalan.xpath.XNull
       * @see org.apache.xalan.xpath.XBoolean
       * @see org.apache.xalan.xpath.XNumber
       * @see org.apache.xalan.xpath.XString
       * @see org.apache.xalan.xpath.XRTreeFrag   */
      public static XObject eval( Node contextNode, String str, Node namespaceNode )
      throws SAXException {
          // Since we don't have a XML Parser involved here, install some default support
          // for things like namespaces, etc.
          // (Changed from: XPathSupportDefault xpathSupport = new XPathSupportDefault();
          //    because XPathSupportDefault is weak in a number of areas... perhaps
          //    XPathSupportDefault should be done away with.)
          XPathSupport xpathSupport = new XMLParserLiaisonDefault();
  
          if ( null == namespaceNode )
              namespaceNode = contextNode;
  
          // Create an object to resolve namespace prefixes.
          // XPath namespaces are resolved from the input context node's document element
          // if it is a root node, or else the current context node (for lack of a better
          // resolution space, given the simplicity of this sample code).
          PrefixResolverDefault prefixResolver = new PrefixResolverDefault( ( namespaceNode.getNodeType() == Node.DOCUMENT_NODE )
                                                 ? ( ( Document ) namespaceNode ).getDocumentElement() :
                                                 namespaceNode );
  
          // Create the XPath object.
          XPath xpath = new XPath();
  
          // Create a XPath parser.
          XPathProcessorImpl parser = new XPathProcessorImpl( xpathSupport );
          parser.initXPath( xpath, str, prefixResolver );
  
          // Execute the XPath, and have it return the result
          return xpath.execute( xpathSupport, contextNode, prefixResolver );
      }
  }
  
  
  
  1.1                  jakarta-avalon/src/java/org/apache/avalon/util/internet/CRLFInputStream.java
  
  Index: CRLFInputStream.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE file.
   */
  package org.apache.avalon.util.internet;
  
  import java.io.FilterInputStream;
  import java.io.IOException;
  import java.io.InputStream;
  
  /**
   * Transform line endings to CRLF in input stream.
   *
   * @author <a href="mailto:donaldp@apache.org">Peter Donald</a>
   */
  public class CRLFInputStream
      extends FilterInputStream
  {
      protected int       m_lastChar;
  
      public CRLFInputStream( final InputStream inputStream )
      {
          super( inputStream );
          m_lastChar = -1;
      }
      
      public int read()
          throws IOException
      {
          if( '\r' != m_lastChar )
          {
              final int result = m_lastChar;
              m_lastChar = -1;
              return result;
          }
  
          final int data = in.read();
  
          if( -1 == data )
          {
              if( -1 != m_lastChar ) return m_lastChar;
              else return data;
          }
          else if( '\r' == data )
          {
              m_lastChar = data;
              return read();
          }
          else if( '\n' != data ) 
          {
              if( -1 != m_lastChar )
              {
                  final int result = m_lastChar;
                  m_lastChar = -1;
                  return result;
              }
              else return data;
          }
          else return data;
      }
  }
  
  
  
  1.1                  jakarta-avalon/src/java/org/apache/avalon/util/internet/CRLFOutputStream.java
  
  Index: CRLFOutputStream.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE file.
   */
  package org.apache.avalon.util.internet;
  
  import java.io.FilterOutputStream;
  import java.io.IOException;
  import java.io.OutputStream;
  
  /**
   * Transform line endings to CRLF in output stream.
   *
   * @author <a href="mailto:donaldp@apache.org">Peter Donald</a>
   */
  public class CRLFOutputStream
      extends FilterOutputStream
  {
      public CRLFOutputStream( final OutputStream outputStream )
      {
          super( outputStream );
      }
      
      public void write( final int data )
          throws IOException
      {
          if( '\n' == data ) out.write( '\r' );
          out.write( data );
      }
      
      public void write( final byte data[], final int offset, final int len )
          throws IOException
      {
          for( int i = 0; i < len; i++)
          {
              final byte element = data[ offset + i ];
              if( '\n' == element ) out.write( '\r' );
              out.write( element );
          }
      }
  }
  
  
  
  1.1                  jakarta-avalon/src/java/org/apache/avalon/util/internet/InternetException.java
  
  Index: InternetException.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE file.
   */
  package org.apache.avalon.util.internet;
  
  import org.apache.avalon.CascadingException;
  
  /**
   * Connection thrown during various internet related protocol handling.
   * The code field will handle the common 3 digit code + message
   * 
   * @author <a href="mailto:donaldp@apache.org">Peter Donald</a>
   */
  public class InternetException
      extends CascadingException
  {
      protected InternetReply   m_reply;
  
      public InternetException( final int code, final String description )
      {
          this( code, description, null );
      }
      
      public InternetException( final int code, 
                                final String description, 
                                final Throwable throwable )
      {
          super( description, throwable );
          m_reply = new InternetReply( code, description );
      }
  
      public InternetReply getReply()
      {
          return m_reply;
      }
  }
  
  
  
  1.1                  jakarta-avalon/src/java/org/apache/avalon/util/internet/InternetReply.java
  
  Index: InternetReply.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE file.
   */    
  package org.apache.avalon.util.internet;
  
  /**
   * This is for holding Internet reply codes + descriptions.
   *
   * @author <a href="mailto:donaldp@apache.org">Peter Donald</a>
   */
  public class InternetReply
  {
      protected int     m_code;
      protected String  m_description;
  
      public InternetReply( final int code, final String description )
      {
          m_code = code;
          m_description = description;
      }
      
      public int getCode()
      {
          return m_code;
      }
      
      public String getDescription()
      {
          return m_description;
      }
  }
  
  
  
  1.1                  jakarta-avalon/src/java/org/apache/avalon/util/internet/InternetStream.java
  
  Index: InternetStream.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE file.
   */
  package org.apache.avalon.util.internet;
  
  import java.io.IOException;
  import java.io.InputStream;
  import java.io.OutputStream;
  import java.net.ProtocolException;
  
  /**
   * This is the Internet output/input stream.
   * Used for such things as SMTP, NNTP, FTP? etc.
   *
   * TODO: Need to be able to set a flag to allow lax input-reading
   * to cope with some non-compliant sources
   *
   * @author <a href="mailto:donaldp@apache.org">Peter Donald</a>
   */
  public class InternetStream
  {
      protected final static int           MAX_OUTGOING_LINE_LENGTH   = 512;
  
      protected LineReader                 m_reader;
      protected LineWriter                 m_writer;
      protected String                     m_lastLine;
  
      protected String                     m_responseText;
      protected int                        m_responseCode;
      protected String                     m_requestVerb;
      protected String                     m_requestParameter;
  
      /**
       * Constructor taking an input and output.
       *
       * @param input the InputStream
       * @param output the OutputStream
       */
      public InternetStream( final InputStream input, final OutputStream output )
      {
          m_reader = new LineReader( input );
          m_writer = new LineWriter( output );
      }
  
      /**
       * Retrieve request verb last received.
       *
       * @return the request verb
       */
      public String getRequestVerb()
      {
          return m_requestVerb;
      }
  
      /**
       * Retrieve request parameter
       *
       * @return the request parameter
       */
      public String getRequestParameter()
      {
          return m_requestParameter;
      }
      
      public String getResponseText()
      {
          return m_responseText;
      }
  
      public int getResponseCode()
      {
          return m_responseCode;
      }
  
      /**
       * Retrieve last line received from connection. 
       *
       * @return the last line received
       */
      public String getLastLine()
      {
          return m_lastLine;
      }
  
      /**
       * Send a request to server.
       *
       * @param verb the request verb
       * @exception IOException if an error occurs
       */
      public void sendRequest( final String verb )
          throws IOException
      {
          sendRequest( verb, null );
      }
  
      /**
       * Send a Request to server.
       *
       * @param verb the request verb
       * @param parameter the parameter (or null if none)
       * @exception IOException if an error occurs
       */
      public void sendRequest( final String verb, final String parameter )
          throws IOException
      {
          final StringBuffer sb = new StringBuffer();
          sb.append( verb );
  
          if( null != parameter )
          {
              sb.append( ' ' );
              sb.append( parameter );
          }
  
          m_writer.println( sb.toString() );
      }
  
      /**
       * Send a response. 
       * Format the message so that it conforms to line length/contents rules.
       *
       * @param responseCode the response code
       * @param message the message
       * @exception IOException if an error occurs
       */
      public void sendResponse( final int responseCode, final String message )
          throws IOException
      {
          int start = 0;
          int end = message.indexOf( '\n' );
          
          while( -1 != end )
          {
              sendResponseLines( responseCode, false, message.substring( start, end ) );
              start = end + 1;
              end = message.indexOf( '\n', start );
          }
          
          end = message.length();
  
          sendResponseLines( responseCode, true, message.substring( start, end ) );        
      }
  
      /**
       * Receive a Request from client.
       *
       * @exception IOException if an error occurs
       */
      public void receiveRequest()
          throws IOException
      {
          m_requestVerb = null;
          m_requestParameter = null;
  
          final String line = m_reader.readln();
          
          int space = line.indexOf( ' ' );
          
          if( -1 == space )
          {
              m_requestVerb = line.toUpperCase();
          }
          else
          {
              m_requestVerb = line.substring( 0, space ).toUpperCase();
              m_requestParameter = line.substring( space + 1 ).trim();
  
              if( m_requestParameter.equals( "" ) )
              {
                  m_requestParameter = null;
              }
          }
      }
  
      /**
       * receive a response from server.
       *
       * @exception IOException if an error occurs
       */
      public void receiveResponse()
          throws IOException
      {
          boolean lastLine = false;
  
          m_responseCode = 0;
          m_responseText = null;
  
          while( !lastLine )
          {
              final String line = m_reader.readln();
              int responseCode = Integer.parseInt( line.substring( 0, 3 ) );
                  
              if( 0 != m_responseCode && responseCode != m_responseCode )
              {
                  throw new ProtocolException( "Badly formed response with differing codes" );
              }
                  
              m_responseCode = responseCode;
  
              lastLine = ( ' ' == line.charAt( 3 ) );
                  
              final String messagePart = line.substring( 4, line.length() );
  
              if( null == m_responseText ) m_responseText = messagePart;
              else m_responseText += '\n' + messagePart;
          }
      }
      
      /**
       * Helper method to build a response line. 
       * If message is greater than MAX_OUTGOING_LINE_LENGTH it is broken into multiple lines.
       *
       * @param responseCode the response code.
       * @param isLastLine true if this is last line in response
       * @param message the message
       * @exception IOException if an error occurs
       */
      protected void sendResponseLines( final int responseCode, 
                                        final boolean isLastLine,
                                        final String message )
          throws IOException
      {
          final int size = message.length();
          
          if( size < MAX_OUTGOING_LINE_LENGTH )
          {
              sendResponseLine( responseCode, isLastLine, message );
          }
          else
          {
              int start = 0;
              int end = MAX_OUTGOING_LINE_LENGTH;
  
              while( end < size )
              {
                  sendResponseLine( responseCode, false, message.substring( start, end ) );
                  start = end + 1;
                  end = end + MAX_OUTGOING_LINE_LENGTH;
              }
                  
              sendResponseLine( responseCode, isLastLine, message.substring( start, size ) );
          }
      }
  
      /**
       * Helper method to build a response line.
       *
       * @param responseCode the response code.
       * @param isLastLine true if this is last line in response
       * @param message the message
       * @exception IOException if an error occurs
       */
      protected void sendResponseLine( final int responseCode, 
                                       final boolean isLastLine,
                                       final String message )
          throws IOException
      {
          final char seperator = ( isLastLine ) ? ' ' : '-';
          final String responseLine = Integer.toString( responseCode ) + seperator + message;
          sendLine( responseLine );
      }
      
      /**
       * Send a raw line and terminate it with a \r\n.
       * This assumes thaat the parameters does not have \r\n 
       * sequence in it (or \n byitself).
       *
       * @param line the line
       * @exception IOException if an error occurs
       */
      public final void sendLine( final String line )
          throws IOException
      {
          m_writer.println( line );
      }
      
      /**
       * Receive a line.
       *
       * @return the line received
       * @exception IOException if an error occurs
       */
      public final String receiveLine()
          throws IOException
      {
          m_lastLine = m_reader.readln();
          return m_lastLine;
      } 
  }
  
  
  
  1.1                  jakarta-avalon/src/java/org/apache/avalon/util/internet/LineReader.java
  
  Index: LineReader.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE file.
   */
  package org.apache.avalon.util.internet;
  
  import java.io.IOException;
  import java.io.InputStream;
  import java.net.ProtocolException;
  
  /**
   * Used to write lines with appropriate line endings.
   *
   * @author <a href="mailto:donaldp@apache.org">Peter Donald</a>
   */
  public class LineReader
  {
      protected final static byte[]      LINE_TERMINATOR = { (byte)'\r', (byte)'\n' };
  
      protected InputStream        m_input;
      protected boolean            m_laxLineFormat;
  
      public LineReader( final InputStream input )
      {
          m_input = input;
      }
  
      public void setLaxLineFormat( final boolean laxLineFormat )
      {
          m_laxLineFormat = laxLineFormat;
      }
  
      public String readln()
          throws IOException
      {
          final StringBuffer sb = new StringBuffer();
          
          int data = m_input.read();
          int last = -1;
  
          while( LINE_TERMINATOR[ 1 ] != data )
          {
              if( last == LINE_TERMINATOR[ 0 ] )
              {
                  if( data == LINE_TERMINATOR[ 1 ] ) break;
                  else sb.append( (char)last );
              }
              else if( data == LINE_TERMINATOR[ 1 ] )
              {
                  break;
              }
              else
              {
                  last = data;
                  if( data != LINE_TERMINATOR[ 0 ] ) sb.append( (char)data );
              }
  
              data = m_input.read();
          }
  
          return sb.toString();
      }
  
      public void close()
          throws IOException
      {
          m_input.close();
      }
  }
  
      
  
  
  
  1.1                  jakarta-avalon/src/java/org/apache/avalon/util/internet/LineWriter.java
  
  Index: LineWriter.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE file.
   */
  package org.apache.avalon.util.internet;
  
  import java.io.IOException;
  import java.io.OutputStream;
  import java.net.ProtocolException;
  
  /**
   * Used to write lines with appropriate line endings.
   *
   * @author <a href="mailto:donaldp@apache.org">Peter Donald</a>
   */
  public class LineWriter
  {
      protected final static byte[]      LINE_TERMINATOR = { (byte)'\r', (byte)'\n' };
  
      protected OutputStream       m_output;
  
      public LineWriter( final OutputStream output )
      {
          m_output = output;
      }
  
      public void println( final String data )
              throws IOException
      {
          m_output.write( data.getBytes() );
          m_output.write( LINE_TERMINATOR );
          m_output.flush();
      }
  
      public void close()
          throws IOException
      {
          m_output.close();
      }
  }
  
      
  
  
  
  1.1                  jakarta-avalon/src/java/org/apache/avalon/util/io/ByteTerminatedInputStream.java
  
  Index: ByteTerminatedInputStream.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE file.
   */
  package org.apache.avalon.util.io;
  
  import java.io.IOException;
  import java.io.InputStream;
  
  /**
   * 
   * @author <a href="mailto:donaldp@apache.org">Peter Donald</a>
   * @author  Federico Barbieri <fe...@apache.org>
   */
  public class ByteTerminatedInputStream 
      extends InputStream
  {
      protected final boolean              m_includeTerminator;
      protected final InputStream          m_inputStream;
      protected final byte[]               m_terminator;
      protected final int                  m_matchLength;
      protected int                        m_match;
      
      public ByteTerminatedInputStream( final InputStream inputStream, 
                                        final byte[] terminator,
                                        final boolean includeTerminator ) 
      {
          m_includeTerminator = includeTerminator;
          m_matchLength = terminator.length;
          m_terminator = terminator;
          m_inputStream = inputStream;
          m_match = 0;
      }
      
      public int read()
          throws IOException
      {
          if( m_match == m_matchLength ) return -1;
  
          int next = getNext();
  
          if( !m_includeTerminator && 0 != m_match )
          {
              m_inputStream.mark( m_matchLength );
  
              int matchTest = next;
  
              while( -1 != matchTest )
              {
                  matchTest = getNext();
                  if( m_match == m_matchLength ) return -1;
                  else if( m_match == 0 ) break;
              }
              m_match = 0;
              m_inputStream.reset();
          }
  
          return next;
      }
  
      protected final int getNext()
          throws IOException
      {
          final int next = m_inputStream.read();
          
          if( next == m_terminator[ m_match ] ) m_match++;
          else if( next == m_terminator[ 0 ] ) m_match = 1;
          else m_match = 0;
  
          return next;
      }
  }
      
  
  
  
  1.1                  jakarta-avalon/src/java/org/apache/avalon/util/io/DirectoryFileFilter.java
  
  Index: DirectoryFileFilter.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE file.
   */
  package org.apache.avalon.util.io;
  
  import java.io.File;
  import java.io.FilenameFilter;
  
  /**
   * This filters files based if not a directory.
   *
   * @author <a href="mailto:donaldp@apache.org">Peter Donald</a>
   */
  public class DirectoryFileFilter 
      implements FilenameFilter
  {
      public boolean accept( final File file, final String name ) 
      {
          return file.isDirectory();
      }
  }
  
      
  
  
  
  1.1                  jakarta-avalon/src/java/org/apache/avalon/util/io/ExtensionFileFilter.java
  
  Index: ExtensionFileFilter.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE file.
   */
  package org.apache.avalon.util.io;
  
  import java.io.File;
  import java.io.FilenameFilter;
  
  /**
   * This filters files based on the extension (what the filename 
   * ends with).  This is used in retrieving all the files of a 
   * particular type.
   *
   * @author  Federico Barbieri <fe...@apache.org>
   * @author Serge Knystautas <se...@lokitech.com>
   * @author <a href="mailto:donaldp@apache.org">Peter Donald</a>
   */
  public class ExtensionFileFilter 
      implements FilenameFilter
  {
      private String[]           m_extensions;
  
      public ExtensionFileFilter( final String[] extensions ) 
      {
          m_extensions = extensions;
      }
  
      public ExtensionFileFilter( final String extension ) 
      {
          m_extensions = new String[] { extension };
      }
  
      public boolean accept( final File file, final String name ) 
      {
          for( int i = 0; i < m_extensions.length; i++ ) 
          {
              if( name.endsWith( m_extensions[ i ] ) ) return true;
          }
          return false;        
      }
  }
  
      
  
  
  
  1.1                  jakarta-avalon/src/java/org/apache/avalon/util/io/FileUtil.java
  
  Index: FileUtil.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE file.
   */
  package org.apache.avalon.util.io;
  
  import java.io.*;
  import java.net.URL;
  import org.apache.avalon.util.StringUtil;
  
  /**
   * This class provides basic facilities for manipulating files.
   *
   * @author <a href="mailto:donaldp@apache.org">Peter Donald</a>
   */
  public final class FileUtil
  {
      /**
       * Private constructor to prevent instantiation.
       *
       */
      private FileUtil()
      {
      }
  
      public static File toFile( final URL url )
      {
          if( !url.getProtocol().equals( "file" ) )
          {
              return null;
          }
          else
          {
              final String filename = url.getFile().replace( '/', File.separatorChar );
              return new File( filename );
          }        
      }
  
      /**
       * Remove extention from filename.
       * ie
       * fo.txt --> foo
       * a\b\c.jpg --> a\b\c
       * a\b\c --> a\b\c
       *
       * @param filename the filename
       * @return the filename minus extention
       */
      public static String removeExtention( final String filename )
      {
          final int index = filename.lastIndexOf( '.' );
          
          if( -1 == index ) 
          {
              return filename;
          }
          else
          {
              return filename.substring( 0, index );
          }
      }
  
      /**
       * remove path from filename.
       * ie.
       * a/b/c.txt --> c.txt
       * a.txt --> a.txt
       *
       * @param filepath the filepath
       * @return the filename minus path
       */
      public static String removePath( final String filepath )
      {
          final int index = filepath.lastIndexOf( File.separator );
  
          if( -1 == index ) 
          {
              return filepath;
          }
          else
          {
              return filepath.substring( index + 1 );
          }
      }
  
      /**
       * Copy file from source to destination.
       */
      public static void copyFileToDirectory( final String source, 
                                              final String destinationDirectory ) 
          throws IOException 
      {
          copyFileToDirectory( new File( source ), new File( destinationDirectory ) );
      }
  
      /**
       * Copy file from source to destination.
       */
      public static void copyFileToDirectory( final File source, 
                                              final File destinationDirectory ) 
          throws IOException 
      {
          if( destinationDirectory.exists() && !destinationDirectory.isDirectory() )
          {
              throw new IllegalArgumentException( "Destination is not a directory" );
          }
  
          copyFile( source, new File( destinationDirectory, source.getName() ) );
      }
  
      /**
       * Copy file from source to destination.
       */
      public static void copyFile( final File source, final File destination ) 
          throws IOException 
      {
          //check source exists
          if( !source.exists() )
          {
              throw new IOException( "File " + source + " does not exist" );
          }
  
          //does destinations directory exist ?
          if( !destination.getParentFile().exists() )
          {
              destination.mkdirs();
          }
  
          //make sure we can write to destination
          if( destination.exists() && !destination.canWrite() )
          {
              throw new IOException( "Unable to open file " + destination + " for writing." );
          }
  
          IOUtil.copy( new FileInputStream( source ), new FileOutputStream( destination ) );
  
          if( source.length() != destination.length() )
          {
              throw new IOException( "Failed to copy full contents from " + source + 
                                     " to " + destination );
          }
      } 
  
      public static void copyURLToFile( final URL source, final File destination ) 
          throws IOException 
      {
          //does destinations directory exist ?
          if( !destination.getParentFile().exists() )
          {
              destination.mkdirs();
          }
          
          //make sure we can write to destination
          if( destination.exists() && !destination.canWrite() )
          {
              throw new IOException( "Unable to open file " + destination + " for writing." );
          }
          
          IOUtil.copy( source.openStream(), new FileOutputStream( destination ) );
      } 
  
      public static String normalize( String location )
      {
          location = StringUtil.replaceSubString( location, "/./", "/" );
          
          final StringBuffer sb = new StringBuffer();
          
          int trail = 0;
          int end = location.indexOf( "/../" );
          int start = 0;
          
          while( end != -1 )
          {
              //TODO: fix when starts with /../
              trail = location.lastIndexOf( "/", end - 1 );
              sb.append( location.substring( start, trail ) );
              sb.append( '/' );
              start = end + 4;
              end = location.indexOf( "/../", start );
          }
          
          end = location.length();
          sb.append( location.substring( start, end ) );
          
          return sb.toString();
      }
  
      /** Will concatenate 2 paths, dealing with ..
       * ( /a/b/c + d = /a/b/d, /a/b/c + ../d = /a/d )
       * 
       * Thieved from Tomcat sources...
       * 
       * @return null if error occurs
       */
      public static String catPath( String lookupPath, String path )
      {
          // Cut off the last slash and everything beyond
          int index = lookupPath.lastIndexOf( "/" );
          lookupPath = lookupPath.substring( 0, index );
          
          // Deal with .. by chopping dirs off the lookup path
          while( path.startsWith( "../" ) ) 
          { 
              if( lookupPath.length() > 0 )
              {
                  index = lookupPath.lastIndexOf( "/" );
                  lookupPath = lookupPath.substring( 0, index );
              } 
              else
              {
                  // More ..'s than dirs, return null
                  return null;
              }
              
              index = path.indexOf( "../" ) + 3;
              path = path.substring( index );
          }
          
          return lookupPath + "/" + path;
      }
  
      public static File resolveFile( final File baseFile, String filename ) 
      {
          if( '/' != File.separatorChar ) 
          {
              filename = filename.replace( '/', File.separatorChar );
          }
  
          if( '\\' != File.separatorChar ) 
          {
              filename = filename.replace( '\\', File.separatorChar );
          }
  
          // deal with absolute files
          if( filename.startsWith( File.separator ) )
          {
              File file = new File( filename );
  
              try { file = file.getCanonicalFile(); } 
              catch( final IOException ioe ) {}
  
              return file;
          }
  
          final char[] chars = filename.toCharArray();
          final StringBuffer sb = new StringBuffer();
  
          //remove duplicate file seperators in succession - except 
          //on win32 as UNC filenames can be \\AComputer\AShare\myfile.txt
          int start = 0;
          if( '\\' == File.separatorChar ) 
          {
              sb.append( filename.charAt( 0 ) );
              start++;
          }
  
          for( int i = start; i < chars.length; i++ )
          {
              final boolean doubleSeperator = 
                  File.separatorChar == chars[ i ] && File.separatorChar == chars[ i - 1 ];
  
              if( !doubleSeperator ) sb.append( chars[ i ] );
          }
          
          filename = sb.toString();
  
          //must be relative
          File file = (new File( baseFile, filename )).getAbsoluteFile();
  
          try { file = file.getCanonicalFile(); }
          catch( final IOException ioe ) {}
  
          return file;
      }
  
      /**
       * Delete a file. If file is directory delete it and all sub-directories.
       */
      public static void forceDelete( final String file )
          throws IOException 
      {
          forceDelete( new File( file ) );
      }
  
      /**
       * Delete a file. If file is directory delete it and all sub-directories.
       */
      public static void forceDelete( final File file )
          throws IOException 
      {
          if( file.isDirectory() ) deleteDirectory( file );
          else
          {
              if( false == file.delete() )
              {
                  throw new IOException( "File " + file + " unable to be deleted." );
              }
          }
      }
  
      /**
       * Recursively delete a directory.
       */
      public static void deleteDirectory( final String directory )
          throws IOException 
      {
          deleteDirectory( new File( directory ) );
      }
  
      /**
       * Recursively delete a directory.
       */
      public static void deleteDirectory( final File directory )
          throws IOException 
      {
          if( !directory.exists() ) return;
  
          cleanDirectory( directory );
          if( false == directory.delete() )
          {
              throw new IOException( "Directory " + directory + " unable to be deleted." );
          }
      }  
  
      /**
       * Clean a directory without deleting it.
       */
      public static void cleanDirectory( final String directory )
          throws IOException 
      {
          cleanDirectory( new File( directory ) );
      }
      
      /**
       * Clean a directory without deleting it.
       */
      public static void cleanDirectory( final File directory )
          throws IOException 
      {
          if( !directory.exists() ) 
          {
              throw new IllegalArgumentException( directory + " does not exist" );
          }
          
          if( !directory.isDirectory() )
          {
              throw new IllegalArgumentException( directory + " is not a directory" );
          }
          
          final File[] files = directory.listFiles();
          
          for( int i = 0; i < files.length; i++ ) 
          {
              final File file = files[ i ];
              
              if( file.isFile() ) file.delete();
              else if( file.isDirectory() ) 
              {
                  cleanDirectory( file );
                  if( false == file.delete() )
                  {
                      throw new IOException( "Directory " + file + " unable to be deleted." );
                  }
              }
          }
      } 
  }
  
  
  
  1.1                  jakarta-avalon/src/java/org/apache/avalon/util/io/IOUtil.java
  
  Index: IOUtil.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE file.
   */
  package org.apache.avalon.util.io;
  
  import java.io.*;
  
  /**
   * This class provides basic facilities for manipulating io streams.
   *
   * @author <a href="mailto:donaldp@apache.org">Peter Donald</a>
   */
  public final class IOUtil
  {
      /**
       * Private constructor to prevent instantiation.
       */
      private IOUtil()
      {
      }
  
      public static void shutdownStream( final OutputStream output )
      {
          if( null == output ) return;
          
          try { output.close(); }
          catch( final IOException ioe ) {}
      }
      
      public static void shutdownStream( final InputStream input )
      {
          if( null == input ) return;
          
          try { input.close(); }
          catch( final IOException ioe ) {}
      }
  
      /**
       * Copy stream-data from source to destination.
       */
      public static void copy( final InputStream source, final OutputStream destination ) 
          throws IOException 
      {
          try
          {
              final BufferedInputStream input = new BufferedInputStream( source );
              final BufferedOutputStream output = new BufferedOutputStream( destination );
              
              final int BUFFER_SIZE = 1024 * 4;
              final byte[] buffer = new byte[ BUFFER_SIZE ];
              
              while( true )
              {
                  final int count = input.read( buffer, 0, BUFFER_SIZE );
                  if( -1 == count ) break;
                  
                  // write out those same bytes
                  output.write( buffer, 0, count );
              }
              
              //needed to flush cache
              output.flush();
          }
          finally
          {
              shutdownStream( source );
              shutdownStream( destination );
          }
      } 
  }
  
  
  
  1.1                  jakarta-avalon/src/java/org/apache/avalon/util/io/MergedInputStreams.java
  
  Index: MergedInputStreams.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE file.
   */
  package org.apache.avalon.util.io;
  
  import java.io.IOException;
  import java.io.InputStream;
  
  /**
   * Merges multiple input streams into one.
   *
   * @author <a href="mailto:donaldp@apache.org">Peter Donald</a>
   */
  public class MergedInputStreams 
      extends InputStream 
  {
      protected final InputStream[]          m_streams;
      protected int                          m_index;
  
      public MergedInputStreams( final InputStream[] inputStreams )
      {
          super();
          m_streams = inputStreams;
      }
  
      public int read() 
          throws IOException
      {
          if( m_index >= m_streams.length ) return -1;
  
          int returnVal = m_streams[ m_index ].read();
  
          if( -1 == returnVal && (++m_index) < m_streams.length )
          {
              returnVal = m_streams[ m_index ].read();
          }
          
          return returnVal;
      }
  }
  
  
  
  
  1.1                  jakarta-avalon/src/java/org/apache/avalon/util/io/ResettableFileInputStream.java
  
  Index: ResettableFileInputStream.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE file.
   */
  package org.apache.avalon.util.io;
  
  import java.io.BufferedInputStream;
  import java.io.File;
  import java.io.FileInputStream;
  import java.io.IOException;
  import java.io.InputStream;
  
  /**
   * @author  Federico Barbieri <fe...@apache.org>
   */
  public class ResettableFileInputStream 
      extends InputStream
  {
      protected static final int         DEFAULT_BUFFER_SIZE          = 1024;
  
      protected final String             m_filename;
      protected int                      m_bufferSize;
      protected InputStream              m_inputStream;
      protected long                     m_position;
      protected long                     m_mark;
      protected boolean                  m_isMarkSet;
  
      public ResettableFileInputStream( final File file )
          throws IOException 
      {
          this( file.getCanonicalPath() );
      }
      
      public ResettableFileInputStream( final String filename )
          throws IOException 
      {
          this( filename, DEFAULT_BUFFER_SIZE );
      }
      
      public ResettableFileInputStream( final String filename, final int bufferSize )
          throws IOException 
      {
          m_bufferSize = bufferSize;
          m_filename = filename;
          m_position = 0;
  
          m_inputStream = newStream();
      }
      
      public void mark( final int readLimit )
      {
          m_isMarkSet = true;
          m_mark = m_position;
          m_inputStream.mark( readLimit );
      }
      
      public boolean markSupported()
      {
          return true;
      }
      
      public void reset()
          throws IOException 
      {
          if( !m_isMarkSet )
          {
              throw new IOException( "Unmarked Stream" );
          }
          try 
          {
              m_inputStream.reset();
          } 
          catch( final IOException ioe )
          {
              try
              {
                  m_inputStream.close();
                  m_inputStream = newStream();
                  m_inputStream.skip( m_mark );
                  m_position = m_mark;
              } 
              catch( final Exception e )
              {
                  throw new IOException( "Cannot reset current Stream: " + e.getMessage() );
              }
          }
      }
  
      protected InputStream newStream()
          throws IOException
      {
          return new BufferedInputStream( new FileInputStream( m_filename ), m_bufferSize );
      }
  
      public int available()
          throws IOException
      {
          return m_inputStream.available();
      }
      
      public void close() throws IOException
      {
          m_inputStream.close();
      }
      
      public int read() throws IOException
      {
          m_position++;
          return m_inputStream.read();
      }
      
      public int read( final byte[] bytes, final int offset, final int length )
          throws IOException 
      {
          final int count = m_inputStream.read( bytes, offset, length );
          m_position += count;
          return count;
      }
      
      public long skip( final long count )
          throws IOException 
      {
          m_position += count;
          return m_inputStream.skip( count );
      }
  }
  
  
  
  1.1                  jakarta-avalon/src/java/org/apache/avalon/util/io/test/FileUtilTestlet.java
  
  Index: FileUtilTestlet.java
  ===================================================================
  /* 
   * Copyright  The Apache Software Foundation. All rights reserved. 
   * 
   * This software is published under the terms of the Apache Software License 
   * version 1.1, a copy of which has been included with this distribution in 
   * the LICENSE file. 
   */ 
  package org.apache.avalon.util.io.test;
  
  import java.io.*;
  import org.apache.avalon.util.io.FileUtil;
  import org.apache.testlet.AbstractTestlet;
  import org.apache.testlet.TestFailedException;  
  
  /** 
   * This is used to test FileUtil for correctness. 
   * 
   * @author <a href="mailto:donaldp@apache.org">Peter Donald</a> 
   */ 
  public final class FileUtilTestlet 
      extends AbstractTestlet 
  {  
      protected final int      FILE1_SIZE  = 1;
      protected final int      FILE2_SIZE  = 1024 * 4 + 1;
  
      protected final File     m_testDirectory;
      protected final File     m_testFile1;
      protected final File     m_testFile2;
  
      public FileUtilTestlet()
          throws IOException
      {
          m_testDirectory = (new File( "test/io/" )).getAbsoluteFile();
          if( !m_testDirectory.exists() )
          {
              m_testDirectory.mkdirs();
          }
  
          m_testFile1 = new File( m_testDirectory, "file1-test.txt" );
          m_testFile2 = new File( m_testDirectory, "file2-test.txt" );
          
          createFile( m_testFile1, FILE1_SIZE );
          createFile( m_testFile2, FILE2_SIZE );
      }
  
      protected void createFile( final File file, final long size )
          throws IOException
      {
          final BufferedOutputStream output = 
              new BufferedOutputStream( new FileOutputStream( file ) );
          
          for( int i = 0; i < size; i++ )
          {
              output.write( (byte)'X' );
          }
  
          output.close();
      }
  
      public void testCopyFile1() 
          throws Exception 
      {
          final File destination = new File( m_testDirectory, "copy1.txt" );
          FileUtil.copyFile( m_testFile1, destination );
          assert( "Check Exist", destination.exists() );
          assert( "Check Full copy", destination.length() == FILE1_SIZE );
      }
      
      public void testCopyFile2() 
          throws Exception 
      {
          final File destination = new File( m_testDirectory, "copy2.txt" );
          FileUtil.copyFile( m_testFile2, destination );
          assert( "Check Exist", destination.exists() );
          assert( "Check Full copy", destination.length() == FILE2_SIZE );
      }
      
      public void testForceDeleteFile1() 
          throws Exception 
      {
          final File destination = new File( m_testDirectory, "copy1.txt" );
          FileUtil.forceDelete( destination );
          assert( "Check No Exist", !destination.exists() );
      }
      
      public void testForceDeleteFile2() 
          throws Exception 
      {
          final File destination = new File( m_testDirectory, "copy2.txt" );
          FileUtil.forceDelete( destination );
          assert( "Check No Exist", !destination.exists() );
      }
      
      public void testCopyFile1ToDir() 
          throws Exception 
      {
          final File directory = new File( m_testDirectory, "subdir" );
          if( !directory.exists() ) directory.mkdirs();
          final File destination = new File( directory, "file1-test.txt" );
          FileUtil.copyFileToDirectory( m_testFile1, directory );
          assert( "Check Exist", destination.exists() );
          assert( "Check Full copy", destination.length() == FILE1_SIZE );
      }
      
      public void testCopyFile2ToDir() 
          throws Exception 
      {
          final File directory = new File( m_testDirectory, "subdir" );
          if( !directory.exists() ) directory.mkdirs();
          final File destination = new File( directory, "file2-test.txt" );
          FileUtil.copyFileToDirectory( m_testFile2, directory );
          assert( "Check Exist", destination.exists() );
          assert( "Check Full copy", destination.length() == FILE2_SIZE );
      }  
  
      public void testForceDeleteDir() 
          throws Exception 
      {
          FileUtil.forceDelete( m_testDirectory.getParentFile() );
          assert( "Check No Exist", !m_testDirectory.getParentFile().exists() );
      }
  
      public void testResolveFileDotDot()
          throws Exception
      {
          final File file = FileUtil.resolveFile( m_testDirectory, ".." );
          assertEquality( "Check .. operator", file, m_testDirectory.getParentFile() );
      }
      
      public void testResolveFileDot()
          throws Exception
      {
          final File file = FileUtil.resolveFile( m_testDirectory, "." );
          assertEquality( "Check . operator", file, m_testDirectory );
      }
  }
  
  
  
  1.1                  jakarta-avalon/src/java/org/apache/avalon/util/lang/ThreadManager.java
  
  Index: ThreadManager.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE file.
   */
  package org.apache.avalon.util.lang;
  
  import  org.apache.avalon.util.thread.ThreadContext;
  import  org.apache.avalon.util.thread.ThreadPool;
  
  /**
   * @author <a href="mailto:fede@apache.org">Federico Barbieri</a>
   */
  public final class ThreadManager
  {
      /**
       * @deprecated This will be removed in future iterations and is legacy from old time
       */
      public static ThreadPool getWorkerPool( final String name ) 
      {
          return ThreadContext.getCurrentThreadPool();
      }
  }
  
  
  
  1.1                  jakarta-avalon/src/java/org/apache/avalon/util/log/AvalonLogFormatter.java
  
  Index: AvalonLogFormatter.java
  ===================================================================
  /* 
   * Copyright (C) The Apache Software Foundation. All rights reserved. 
   * 
   * This software is published under the terms of the Apache Software License 
   * version 1.1, a copy of which has been included with this distribution in 
   * the LICENSE file. 
   */ 
  package org.apache.avalon.util.log;
  
  import java.util.Date;
  import org.apache.avalon.util.StringUtil;
  import org.apache.log.format.PatternFormatter;
  
  /**
   * Specialized formatter that knows about CascadingThrowables.
   *
   * @author <a href="mailto:donaldp@apache.org">Peter Donald</a>
   */
  public class AvalonLogFormatter 
      extends PatternFormatter
  {
      protected String getStackTrace( final Throwable throwable, final String format )
      {
          if( null == throwable ) return "";
          return StringUtil.printStackTrace( throwable, 8, true );
      }
  
      /**
       * Utility method to format time.
       *
       * @param time the time
       * @param format ancilliary format parameter - allowed to be null
       * @return the formatted string
       */
      protected String getTime( final long time, final String format )
      {
          return new Date().toString();
      }
  }
  
  
  
  1.1                  jakarta-avalon/src/java/org/apache/avalon/util/log/DefaultLogManager.java
  
  Index: DefaultLogManager.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included  with this distribution in
   * the LICENSE file.
   */
  package org.apache.avalon.util.log;
  
  import java.io.File;
  import java.io.IOException;
  import java.lang.reflect.InvocationTargetException;
  import java.lang.reflect.Method;
  import java.util.Iterator;
  import org.apache.avalon.AbstractLoggable;
  import org.apache.avalon.Component;
  import org.apache.avalon.configuration.Configurable;
  import org.apache.avalon.configuration.Configuration;
  import org.apache.avalon.configuration.ConfigurationException;
  import org.apache.avalon.Context;
  import org.apache.avalon.Contextualizable;
  import org.apache.log.Category;
  import org.apache.log.LogKit;
  import org.apache.log.LogTarget;
  import org.apache.log.output.FileOutputLogTarget;
  
  /**
   * Component responsible for managing logs.
   *
   * @author <a href="mailto:donaldp@apache.org">Peter Donald</a>
   */
  public class DefaultLogManager
      extends AbstractLoggable
      implements Component, Contextualizable, Configurable
  {
      protected String        m_baseName;
      protected File          m_baseDirectory;
  
      public void contextualize( final Context context )
      {
          m_baseName = (String)context.get( "name" );
          if( null == m_baseName ) m_baseName = "<base>";
  
          m_baseDirectory = (File)context.get( "directory" );
          if( null == m_baseDirectory ) m_baseDirectory = new File( "." );
      }
  
      public void configure( final Configuration configuration )
          throws ConfigurationException
      {
          final Configuration[] targets = configuration.getChildren( "log-target" );
          configureTargets( m_baseName, m_baseDirectory, targets );
          
          final Configuration[] categories = configuration.getChildren( "category" );
          configureCategories( m_baseName, categories );
  
          /*
            final String logPriority = configuration.getChild( "global-priority" ).getValue();
            final Priority.Enum priority = LogKit.getPriorityForName( logPriority );
            LogKit.setGlobalPriority( priority );
          */
      }
    
      protected void configureTargets( final String baseName, 
                                       final File baseDirectory, 
                                       final Configuration[] targets )
          throws ConfigurationException
      {
          for( int i = 0; i < targets.length; i++ )
          {
              final Configuration target = targets[ i ];
              final String name = baseName + '.' + target.getAttribute( "name" );
              String location = target.getAttribute( "location" ).trim();
              final String format = target.getAttribute( "format", null );
              
              if( '/' == location.charAt( 0 ) )
              {
                  location = location.substring( 1 );
              }
              
              final File file = new File( baseDirectory, location );
              
              final FileOutputLogTarget logTarget = new FileOutputLogTarget();
              final AvalonLogFormatter formatter = new AvalonLogFormatter();
              formatter.setFormat( "%{time} [%7.7{priority}] <<%{category}>> " +
                                   "(%{context}): %{message}\\n%{throwable}" );
              logTarget.setFormatter( formatter );
              
              try { logTarget.setFilename( file.getAbsolutePath() ); }
              catch( final IOException ioe )
              {
                  throw new ConfigurationException( "Error initializing log files", ioe );
              }
              
              if( null != format ) 
              {
                  logTarget.setFormat( format );
              }
              
              LogKit.addLogTarget( name, logTarget );
          }
      }
      
      protected void configureCategories( final String baseName, final Configuration[] categories )
          throws ConfigurationException
      {
          for( int i = 0; i < categories.length; i++ )
          {
              final Configuration category = categories[ i ];
              String name = category.getAttribute( "name" );
              final String target = baseName + '.' + category.getAttribute( "target" );
              final String priority = category.getAttribute( "priority" );
              
              if( name.trim().equals( "" ) )
              {
                  name = baseName;
              }
              else
              {
                  name = baseName + '.' + name;
              }
              
              final Category logCategory = 
                  LogKit.createCategory( name, LogKit.getPriorityForName( priority ) );
              final LogTarget logTarget = LogKit.getLogTarget( target );
              LogTarget logTargets[] = null;
              
              if( null != target ) logTargets = new LogTarget[] { logTarget };
              
              LogKit.createLogger( logCategory, logTargets );    
          }
      }
  }
  
  
  
  1.1                  jakarta-avalon/src/java/org/apache/avalon/util/pool/AbstractPool.java
  
  Index: AbstractPool.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE file.
   */
  package org.apache.avalon.util.pool;
  
  import org.apache.avalon.Poolable;
  import org.apache.avalon.Recyclable;
  import org.apache.avalon.Initializable;
  
  /**
   * This is an <code>Pool</code> that caches Poolable objects for reuse.
   *
   * @author <a href="mailto:bloritsch@apache.org">Berin Loritsch</a>
   * @author <a href="mailto:stefano@apache.org">Stefano Mazzocchi</a>
   * @author <a href="mailto:donaldp@apache.org">Peter Donald</a>
   */
  public class AbstractPool
      implements Pool, Initializable
  {
      protected int                     m_count;
      protected Poolable[]              m_pool;
      protected ObjectFactory           m_factory;
      protected PoolController          m_controller;
      protected int                     m_maximum;
      protected int                     m_initial;
  
      public AbstractPool( final ObjectFactory factory,
                           final PoolController controller,
                           final int initial,
                           final int maximum )
      {
          m_count = 0;
          m_factory = factory;
          m_controller = controller;
          m_maximum = maximum;
          m_initial = initial;
      }
  
      public void init() 
          throws Exception
      {
          grow( m_maximum );
          fill( m_initial );
      }
  
      /**
       * Retrieve an object from pool.
       *
       * @return an object from Pool
       */
      public Poolable get() throws Exception
      {
          if( null == m_pool && null != m_controller )
          {
              final int increase = m_controller.grow();
              if( increase > 0 ) grow( increase );
          }
  
          if( 0 == m_count )
          {
              return m_factory.newInstance();
          }
  
          m_count--;
  
          final Poolable poolable = m_pool[ m_count ];
          m_pool[ m_count ] = null;
          return poolable;
      }
  
      /**
       * Place an object in pool.
       *
       * @param poolable the object to be placed in pool
       */
      public void put( final Poolable poolable )
      {
          if( poolable instanceof Recyclable )
          {
              ((Recyclable)poolable).recycle();
          }
  
          if(  m_pool.length == (m_count + 1) && null != m_controller )
          {
              final int decrease = m_controller.shrink();
              if( decrease > 0 ) shrink( decrease );
          }
  
          if ( m_pool.length > m_count + 1 )
          {
              m_pool[ m_count++ ] = poolable;
          }
      }
  
      /**
       * Return the total number of slots in Pool
       *
       * @return the total number of slots
       */
      public final int getCapacity()
      {
          return m_pool.length;
      }
  
      /**
       * Get the number of used slots in Pool
       *
       * @return the number of used slots
       */
      public final int getSize()
      {
          return m_count;
      }
  
      /**
       * This fills the pool to the size specified in parameter.
       */
      public final void fill( final int fillSize ) throws Exception
      {
          final int size = Math.min( m_pool.length, fillSize );
  
          for( int i = m_count; i < size; i++ )
          {
              m_pool[i] = m_factory.newInstance();
          }
  
          m_count = size;
      }
  
      /**
       * This fills the pool by the size specified in parameter.
       */
      public final void grow( final int increase )
      {
          if( null == m_pool )
          {
              m_pool = new Poolable[ increase ];
              return;
          }
  
          final Poolable[] poolables = new Poolable[ increase + m_pool.length ];
          System.arraycopy( m_pool, 0, poolables, 0, m_pool.length );
          m_pool = poolables;
      }
  
      /**
       * This shrinks the pool by parameter size.
       */
      public final void shrink( final int decrease )
      {
          final Poolable[] poolables = new Poolable[ m_pool.length - decrease ];
          System.arraycopy( m_pool, 0, poolables, 0, poolables.length );
          m_pool = poolables;
      }
  }
  
  
  
  1.1                  jakarta-avalon/src/java/org/apache/avalon/util/pool/DefaultObjectFactory.java
  
  Index: DefaultObjectFactory.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE file.
   */
  package org.apache.avalon.util.pool;
  
  import java.lang.reflect.Constructor;
  import org.apache.avalon.Poolable;
  import org.apache.avalon.Recyclable;
  
  /**
   * This is the default for factory that is used to create objects for Pool.
   *
   * It creates objects via reflection and constructor.
   *
   * @author <a href="mailto:bloritsch@apache.org">Berin Loritsch</a>
   * @author <a href="mailto:stefano@apache.org">Stefano Mazzocchi</a>
   * @author <a href="mailto:donaldp@apache.org">Peter Donald</a>
   */
  public class DefaultObjectFactory
      implements ObjectFactory
  {
      protected Constructor            m_constructor;
      protected Object[]               m_arguements;
  
      public DefaultObjectFactory( final Constructor constructor, final Object[] arguements )
      {
          m_arguements = arguements;
          m_constructor = constructor;
      }
  
      public DefaultObjectFactory( final Class clazz, 
                                   final Class[] arguementClasses, 
                                   final Object[] arguements )
          throws NoSuchMethodException
      {
          this( clazz.getConstructor( arguementClasses ), arguements );
      }
  
      public DefaultObjectFactory( final Class clazz )
          throws NoSuchMethodException
      {
          this( clazz, null, null );
      }
  
      public Class getCreatedClass()
      {
          return m_constructor.getDeclaringClass();
      }
  
      public Poolable newInstance()
      {
          try
          {
              return (Poolable)m_constructor.newInstance( m_arguements );
          } 
          catch( final Exception e ) 
          {
              throw new Error( "Failed to instantiate the class " + 
                               m_constructor.getDeclaringClass().getName() + " due to " + e );
          }
      }
  }
  
  
  
  1.1                  jakarta-avalon/src/java/org/apache/avalon/util/pool/DefaultPool.java
  
  Index: DefaultPool.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE file.
   */
  package org.apache.avalon.util.pool;
  
  import org.apache.avalon.Poolable;
  import org.apache.avalon.Recyclable;
  
  /**
   * This is an <code>Pool</code> that caches Poolable objects for reuse.
   *
   * @author <a href="mailto:bloritsch@apache.org">Berin Loritsch</a>
   * @author <a href="mailto:stefano@apache.org">Stefano Mazzocchi</a>
   * @author <a href="mailto:donaldp@apache.org">Peter Donald</a>
   */
  public class DefaultPool
      extends AbstractPool
  {
      public final static int           DEFAULT_POOL_SIZE           = 8;
  
      public DefaultPool( final ObjectFactory factory, 
                          final PoolController controller ) 
          throws Exception
      {
          super( factory, controller, DEFAULT_POOL_SIZE, DEFAULT_POOL_SIZE );
      }
  
      public DefaultPool( final ObjectFactory factory ) 
          throws Exception
      {
          this( factory, null );
      }
  
      public DefaultPool( final Class clazz, final int initial, final int maximum ) 
          throws NoSuchMethodException, Exception
      {
          super( new DefaultObjectFactory( clazz ), null, initial, maximum );
      }
  
      public DefaultPool( final Class clazz, final int initial ) 
          throws NoSuchMethodException, Exception
      {
          this( clazz, initial, initial );
      }
  }
  
  
  
  1.1                  jakarta-avalon/src/java/org/apache/avalon/util/pool/ObjectFactory.java
  
  Index: ObjectFactory.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE file.
   */
  package org.apache.avalon.util.pool;
  
  import org.apache.avalon.Component;
  import org.apache.avalon.Poolable;
  
  /**
   * This is the interface for factory that is used to create objects for Pool.
   *
   * @author <a href="mailto:bloritsch@apache.org">Berin Loritsch</a>
   * @author <a href="mailto:stefano@apache.org">Stefano Mazzocchi</a>
   * @author <a href="mailto:donaldp@apache.org">Peter Donald</a>
   */
  public interface ObjectFactory 
      extends Component
  {
      Poolable newInstance() throws Exception;
      Class getCreatedClass();
  }
  
  
  
  1.1                  jakarta-avalon/src/java/org/apache/avalon/util/pool/Pool.java
  
  Index: Pool.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE file.
   */
  package org.apache.avalon.util.pool;
  
  import org.apache.avalon.Component;
  import org.apache.avalon.Poolable;
  
  /**
   * This is an <code>Pool</code> that caches Poolable objects for reuse.
   *
   * @author <a href="mailto:bloritsch@apache.org">Berin Loritsch</a>
   * @author <a href="mailto:stefano@apache.org">Stefano Mazzocchi</a>
   * @author <a href="mailto:donaldp@mad.scientist.com">Peter Donald</a>
   */
  public interface Pool 
      extends Component
  {
      Poolable get() throws Exception;
      void put( Poolable poolable );
  }
  
  
  
  1.1                  jakarta-avalon/src/java/org/apache/avalon/util/pool/PoolController.java
  
  Index: PoolController.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE file.
   */
  package org.apache.avalon.util.pool;
  
  /**
   * This is the interface you implement if you want to control how Pools capacity 
   * changes overtime.
   * 
   * It gets called everytime that a Pool tries to go below or above it's minimum or maximum.
   * 
   * @author <a href="mailto:stefano@apache.org">Stefano Mazzocchi</a>
   * @author <a href="mailto:donaldp@apache.org">Peter Donald</a>
   * @author <a href="mailto:bloritsch@apache.org">Berin Loritsch</a>
   */
  public interface PoolController
  {
      /**
       * Called when a Pool reaches it's minimum. 
       *
       * Return the number of elements to increase minimum and maximum by.
       *
       * @return the element increase
       */
      int grow();
  
      /**
       * Called when a pool reaches it's maximum.
       *
       * Returns the number of elements to decrease mi and max by.
       *
       * @return the element decrease
       */
      int shrink();
  }
  
  
  
  1.1                  jakarta-avalon/src/java/org/apache/avalon/util/pool/ThreadSafePool.java
  
  Index: ThreadSafePool.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE file.
   */
  package org.apache.avalon.util.pool;
  
  import org.apache.avalon.Poolable;
  import org.apache.avalon.Recyclable;
  import org.apache.avalon.ThreadSafe;
  
  /**
   * This is a implementation of  <code>Pool</code> that is thread safe.
   *
   * @author <a href="mailto:bloritsch@apache.org">Berin Loritsch</a>
   * @author <a href="mailto:stefano@apache.org">Stefano Mazzocchi</a>
   * @author <a href="mailto:donaldp@apache.org">Peter Donald</a>
   */
  public class ThreadSafePool
      extends AbstractPool
      implements ThreadSafe
  {
      public final static int           DEFAULT_POOL_SIZE           = 8;
  
      protected boolean                 m_blocking                  = false;
  
      public ThreadSafePool( final ObjectFactory factory, final PoolController controller )
          throws Exception 
      {
          super( factory, controller, DEFAULT_POOL_SIZE, DEFAULT_POOL_SIZE );
      }
  
      public ThreadSafePool( final ObjectFactory factory )
          throws Exception 
      {
          this( factory, null );
      }
  
      public ThreadSafePool( final ObjectFactory factory, 
                             final int initial, 
                             final int maximum  )
          throws Exception 
      {
          super( factory, null, initial, maximum );
      }
  
      public ThreadSafePool( final ObjectFactory factory, final int initial )
          throws Exception 
      {
          this( factory, initial, initial );
      }
  
      public ThreadSafePool( final Class clazz, final int initial, final int maximum ) 
          throws NoSuchMethodException, Exception
      {
          this( new DefaultObjectFactory( clazz ), initial, maximum );
      }
  
      public ThreadSafePool( final Class clazz, final int initial ) 
          throws NoSuchMethodException, Exception
      {
          this( clazz, initial, initial );
      }
  
      public final boolean isBlocking() 
      {
          return m_blocking;
      }
  
      /**
       * Set whether this pool is blocking. 
       * 
       * If this pool is blocking and empties the Pool then the thread will block until
       * an object is placed back in the pool. This has to be used with care as an errant
       * thread who never does a put will force blocked clients to wait forever.
       *
       * @param blocking a boolean indicating if it is blocking or not
       */
      public final void setBlocking( final boolean blocking ) 
      {
          m_blocking = blocking;
      }
  
      /**
       * Retrieve an object from pool.
       *
       * @return an object from Pool
       */
      public final Poolable get() throws Exception 
      {
          //Require this or else the wait later will cause 
          final Poolable[] pool = m_pool;
  
          synchronized( pool )
          {
              if( 0 == m_count )
              {
                  if( !m_blocking ) 
                  {
                      return m_factory.newInstance();
                  }
                  else
                  {
                      while( 0 == m_count )
                      {
                          try { pool.wait(); }
                          catch( final InterruptedException ie ) { }
                      }
                  }
              }
  
              m_count--;
              final Poolable poolable = m_pool[ m_count ];
              m_pool[ m_count ] = null;
              return poolable;
          }
      }
  
      /**
       * Place an object in pool.
       *
       * @param poolable the object to be placed in pool
       */
      public final void put( final Poolable poolable ) 
      {
          final Poolable[] pool = m_pool;
  
          synchronized( pool )
          {
              super.put( poolable );
  
              //if someone was waiting on the old pool then we have to notify them
              pool.notifyAll();
          }
      }
  }
  
  
  
  1.1                  jakarta-avalon/src/java/org/apache/avalon/util/pool/test/PoolProfile.java
  
  Index: PoolProfile.java
  ===================================================================
  /*
   * Copyright  The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE file.
   */
  package org.apache.avalon.util.pool.test;
  
  import org.apache.avalon.Poolable;
  import org.apache.avalon.util.pool.DefaultPool;
  import org.apache.avalon.util.pool.Pool;
  import org.apache.avalon.util.pool.ThreadSafePool;
  import org.apache.testlet.*;
  
  /**
   * This is used to profile the Pool implementation.
   *
   * @author <a href="mailto:donaldp@apache.org">Peter Donald</a>
   */
  public final class PoolProfile
      extends AbstractTestlet
  { 
      public static class A
          implements Poolable
      {
          int a;
          int b;
          int c;
          float x;
          float y;
          float z;
      }
  
      public static class B
          implements Poolable
      {
          int a;
          int b;
          int c;
          float x;
          float y;
          float z;
          Object o1;
          Object o2;
          Object o3;
  
          public void recycle()
          {
              o1 = o2 = o3 = null;
          }
      }
  
      public static class C
          implements Poolable
      {
          int a;
          int b;
          int c;
          float x;
          float y;
          float z;
          Object o1;
          Object o2;
          Object o3;
          Object o4;
          Object o5;
          Object o6;
  
          public void build()
          {
              o1 = new Object();
              o2 = new Object();
              o3 = new Object();
              o4 = new Object();
              o5 = new Object();
              o6 = new Object();
          }
  
          public void recycle()
          {
              o1 = o2 = o3 = o4 = o5 = o6 = null;
          }
      }
  
      protected static final int               TEST_SIZE          = 1000000;
  
      public void testSmallObjects()
          throws Exception
      {
          System.out.println("SMALL Sized Objects");
  
          final DefaultPool pool1 = new DefaultPool( A.class, 5, 10 );
          final long pool1Start = System.currentTimeMillis();
          final int pool1Factor = 1;
          final int pool1Loops = TEST_SIZE / pool1Factor;
          for( int i = 0; i < TEST_SIZE; i++ )
          {
              final Poolable a1 = pool1.get();
              pool1.put(a1);                
          }
          final long pool1End = System.currentTimeMillis();
          final long pool1Duration = pool1End - pool1Start;
  
          System.gc();
          System.gc();
          Thread.currentThread().sleep(2);
  
          System.out.println("FreeMem post 1: " + Runtime.getRuntime().freeMemory() );
  
          final DefaultPool pool2 = new DefaultPool( A.class, 5, 10 );
          final long pool2Start = System.currentTimeMillis();
          final int pool2Factor = 10;
          final int pool2Loops = TEST_SIZE / pool2Factor;
          for( int i = 0; i < pool2Loops; i++ )
          {
              final Poolable a1 = pool2.get();
              final Poolable a2 = pool2.get();
              final Poolable a3 = pool2.get();
              final Poolable a4 = pool2.get();
              final Poolable a5 = pool2.get();
              final Poolable a6 = pool2.get();
              final Poolable a7 = pool2.get();
              final Poolable a8 = pool2.get();
              final Poolable a9 = pool2.get();
              final Poolable a0 = pool2.get();
              pool2.put(a1);                
              pool2.put(a2);
              pool2.put(a3);
              pool2.put(a4);
              pool2.put(a5);
              pool2.put(a6);
              pool2.put(a7);
              pool2.put(a8);
              pool2.put(a9);
              pool2.put(a0);
          }
          final long pool2End = System.currentTimeMillis();
          final long pool2Duration = pool2End - pool2Start;
  
          System.gc();
          System.gc();
          Thread.currentThread().sleep(2);
  
          System.out.println("FreeMem post 2: " + Runtime.getRuntime().freeMemory() );
  
          final DefaultPool pool3 = new DefaultPool( A.class, 5, 10 );
          final long pool3Start = System.currentTimeMillis();
          final int pool3Factor = 15;
          final int pool3Loops = TEST_SIZE / pool3Factor;
          for( int i = 0; i < pool3Loops; i++ )
          {
              final Poolable a1 = pool3.get();
              final Poolable a2 = pool3.get();
              final Poolable a3 = pool3.get();
              final Poolable a4 = pool3.get();
              final Poolable a5 = pool3.get();
              final Poolable a6 = pool3.get();
              final Poolable a7 = pool3.get();
              final Poolable a8 = pool3.get();
              final Poolable a9 = pool3.get();
              final Poolable a10 = pool3.get();
              final Poolable a11 = pool3.get();
              final Poolable a12 = pool3.get();
              final Poolable a13 = pool3.get();
              final Poolable a14 = pool3.get();
              final Poolable a15 = pool3.get();
              pool3.put(a1);                
              pool3.put(a2);
              pool3.put(a3);
              pool3.put(a4);
              pool3.put(a5);
              pool3.put(a6);
              pool3.put(a7);
              pool3.put(a8);
              pool3.put(a9);
              pool3.put(a10);
              pool3.put(a11);                
              pool3.put(a12);
              pool3.put(a13);
              pool3.put(a14);
              pool3.put(a15);
          }
          final long pool3End = System.currentTimeMillis();
          final long pool3Duration = pool3End - pool3Start;
  
          System.gc();
          System.gc();
          Thread.currentThread().sleep(2);
  
          System.out.println("FreeMem post 3: " + Runtime.getRuntime().freeMemory() );
  
          final DefaultPool pool4 = new DefaultPool( A.class, 5, 10 );
          final long pool4Start = System.currentTimeMillis();
          final int pool4Factor = 20;
          final int pool4Loops = TEST_SIZE / pool4Factor;
          for( int i = 0; i < pool4Loops; i++ )
          {
              final Poolable a1 = pool4.get();
              final Poolable a2 = pool4.get();
              final Poolable a3 = pool4.get();
              final Poolable a4 = pool4.get();
              final Poolable a5 = pool4.get();
              final Poolable a6 = pool4.get();
              final Poolable a7 = pool4.get();
              final Poolable a8 = pool4.get();
              final Poolable a9 = pool4.get();
              final Poolable a10 = pool4.get();
              final Poolable a11 = pool4.get();
              final Poolable a12 = pool4.get();
              final Poolable a13 = pool4.get();
              final Poolable a14 = pool4.get();
              final Poolable a15 = pool4.get();
              final Poolable a16 = pool4.get();
              final Poolable a17 = pool4.get();
              final Poolable a18 = pool4.get();
              final Poolable a19 = pool4.get();
              final Poolable a20 = pool4.get();
              pool4.put(a1);                
              pool4.put(a2);
              pool4.put(a3);
              pool4.put(a4);
              pool4.put(a5);
              pool4.put(a6);
              pool4.put(a7);
              pool4.put(a8);
              pool4.put(a9);
              pool4.put(a10);
              pool4.put(a11);                
              pool4.put(a12);
              pool4.put(a13);
              pool4.put(a14);
              pool4.put(a15);
              pool4.put(a16);
              pool4.put(a17);                
              pool4.put(a18);
              pool4.put(a19);
              pool4.put(a20);
          }
          final long pool4End = System.currentTimeMillis();
          final long pool4Duration = pool4End - pool4Start;
  
          System.out.println("FreeMem post 4: " + Runtime.getRuntime().freeMemory() );
  
          final long createStart = System.currentTimeMillis();
          for( int i = 0; i < TEST_SIZE; i++ )
          {
              final Poolable a1 = new C();
          }
          final long createEnd = System.currentTimeMillis();
          final long createDuration = createEnd - createStart;
  
          //System.out.println("Create Duration: " + createDuration + "ms ");
          System.out.println("FreeMem post create: " + Runtime.getRuntime().freeMemory() );
  
          final double pool1Efficiancy = (double)createDuration/(double)pool1Duration * 100.0;
          final double pool2Efficiancy = (double)createDuration/(double)pool2Duration * 100.0;
          final double pool3Efficiancy = (double)createDuration/(double)pool3Duration * 100.0;
          final double pool4Efficiancy = (double)createDuration/(double)pool4Duration * 100.0;
  
          //System.out.println("Pool Duration for 100% hits: " + pool1Duration + "ms ");
          System.out.println("Pool Efficiancy for 100% hits: " + pool1Efficiancy + "ms ");
          //System.out.println("Pool Duration for 100% hits and saturated: " + pool2Duration + "ms ");
          System.out.println("Pool Efficiancy for 100% hits and saturated: " + pool2Efficiancy + "ms ");
          //System.out.println("Pool Duration for 60% hits: " + pool3Duration + "ms ");
          System.out.println("Pool Efficiancy for 60% hits: " + pool3Efficiancy + "ms ");
          //System.out.println("Pool Duration for 50% hits: " + pool4Duration + "ms ");
          System.out.println("Pool Efficiancy for 50% hits: " + pool4Efficiancy + "ms ");
      }
  
      public void testMediumObjects()
          throws Exception
      {
          System.out.println("MEDIUM Sized Objects");
  
          System.gc();
          System.gc();
          Thread.currentThread().sleep(2);
  
          final DefaultPool pool1 = new DefaultPool( B.class, 5, 10 );
          final long pool1Start = System.currentTimeMillis();
          final int pool1Factor = 1;
          final int pool1Loops = TEST_SIZE / pool1Factor;
          for( int i = 0; i < TEST_SIZE; i++ )
          {
              final Poolable a1 = pool1.get();
              pool1.put(a1);                
          }
          final long pool1End = System.currentTimeMillis();
          final long pool1Duration = pool1End - pool1Start;
  
          System.gc();
          System.gc();
          Thread.currentThread().sleep(2);
  
          System.out.println("FreeMem post 1: " + Runtime.getRuntime().freeMemory() );
  
          final DefaultPool pool2 = new DefaultPool( B.class, 5, 10 );
          final long pool2Start = System.currentTimeMillis();
          final int pool2Factor = 10;
          final int pool2Loops = TEST_SIZE / pool2Factor;
          for( int i = 0; i < pool2Loops; i++ )
          {
              final Poolable a1 = pool2.get();
              final Poolable a2 = pool2.get();
              final Poolable a3 = pool2.get();
              final Poolable a4 = pool2.get();
              final Poolable a5 = pool2.get();
              final Poolable a6 = pool2.get();
              final Poolable a7 = pool2.get();
              final Poolable a8 = pool2.get();
              final Poolable a9 = pool2.get();
              final Poolable a10 = pool2.get();
              pool2.put(a1);                
              pool2.put(a2);
              pool2.put(a3);
              pool2.put(a4);
              pool2.put(a5);
              pool2.put(a6);
              pool2.put(a7);
              pool2.put(a8);
              pool2.put(a9);
              pool2.put(a10);
          }
          final long pool2End = System.currentTimeMillis();
          final long pool2Duration = pool2End - pool2Start;
  
          System.gc();
          System.gc();
          Thread.currentThread().sleep(2);
  
          System.out.println("FreeMem post 2: " + Runtime.getRuntime().freeMemory() );
  
          final DefaultPool pool3 = new DefaultPool( B.class, 5, 10 );
          final long pool3Start = System.currentTimeMillis();
          final int pool3Factor = 15;
          final int pool3Loops = TEST_SIZE / pool3Factor;
          for( int i = 0; i < pool3Loops; i++ )
          {
              final Poolable a1 = pool3.get();
              final Poolable a2 = pool3.get();
              final Poolable a3 = pool3.get();
              final Poolable a4 = pool3.get();
              final Poolable a5 = pool3.get();
              final Poolable a6 = pool3.get();
              final Poolable a7 = pool3.get();
              final Poolable a8 = pool3.get();
              final Poolable a9 = pool3.get();
              final Poolable a10 = pool3.get();
              final Poolable a11 = pool3.get();
              final Poolable a12 = pool3.get();
              final Poolable a13 = pool3.get();
              final Poolable a14 = pool3.get();
              final Poolable a15 = pool3.get();
              pool3.put(a1);                
              pool3.put(a2);
              pool3.put(a3);
              pool3.put(a4);
              pool3.put(a5);
              pool3.put(a6);
              pool3.put(a7);
              pool3.put(a8);
              pool3.put(a9);
              pool3.put(a10);
              pool3.put(a11);                
              pool3.put(a12);
              pool3.put(a13);
              pool3.put(a14);
              pool3.put(a15);
          }
          final long pool3End = System.currentTimeMillis();
          final long pool3Duration = pool3End - pool3Start;
  
          System.gc();
          System.gc();
          Thread.currentThread().sleep(2);
  
          System.out.println("FreeMem post 3: " + Runtime.getRuntime().freeMemory() );
  
          final DefaultPool pool4 = new DefaultPool( B.class, 5, 10 );
          final long pool4Start = System.currentTimeMillis();
          final int pool4Factor = 20;
          final int pool4Loops = TEST_SIZE / pool4Factor;
          for( int i = 0; i < pool4Loops; i++ )
          {
              final Poolable a1 = pool4.get();
              final Poolable a2 = pool4.get();
              final Poolable a3 = pool4.get();
              final Poolable a4 = pool4.get();
              final Poolable a5 = pool4.get();
              final Poolable a6 = pool4.get();
              final Poolable a7 = pool4.get();
              final Poolable a8 = pool4.get();
              final Poolable a9 = pool4.get();
              final Poolable a10 = pool4.get();
              final Poolable a11 = pool4.get();
              final Poolable a12 = pool4.get();
              final Poolable a13 = pool4.get();
              final Poolable a14 = pool4.get();
              final Poolable a15 = pool4.get();
              final Poolable a16 = pool4.get();
              final Poolable a17 = pool4.get();
              final Poolable a18 = pool4.get();
              final Poolable a19 = pool4.get();
              final Poolable a20 = pool4.get();
              pool4.put(a1);                
              pool4.put(a2);
              pool4.put(a3);
              pool4.put(a4);
              pool4.put(a5);
              pool4.put(a6);
              pool4.put(a7);
              pool4.put(a8);
              pool4.put(a9);
              pool4.put(a10);
              pool4.put(a11);                
              pool4.put(a12);
              pool4.put(a13);
              pool4.put(a14);
              pool4.put(a15);
              pool4.put(a16);
              pool4.put(a17);                
              pool4.put(a18);
              pool4.put(a19);
              pool4.put(a20);
          }
          final long pool4End = System.currentTimeMillis();
          final long pool4Duration = pool4End - pool4Start;
  
          final long createStart = System.currentTimeMillis();
          for( int i = 0; i < TEST_SIZE; i++ )
          {
              final Poolable a1 = new C();
          }
          final long createEnd = System.currentTimeMillis();
          final long createDuration = createEnd - createStart;
  
          //System.out.println("Create Duration: " + createDuration + "ms ");
          System.out.println("FreeMem post create: " + Runtime.getRuntime().freeMemory() );
  
          final double pool1Efficiancy = (double)createDuration/(double)pool1Duration * 100.0;
          final double pool2Efficiancy = (double)createDuration/(double)pool2Duration * 100.0;
          final double pool3Efficiancy = (double)createDuration/(double)pool3Duration * 100.0;
          final double pool4Efficiancy = (double)createDuration/(double)pool4Duration * 100.0;
  
          //System.out.println("Pool Duration for 100% hits: " + pool1Duration + "ms ");
          System.out.println("Pool Efficiancy for 100% hits: " + pool1Efficiancy + "ms ");
          //System.out.println("Pool Duration for 100% hits and saturated: " + pool2Duration + "ms ");
          System.out.println("Pool Efficiancy for 100% hits and saturated: " + pool2Efficiancy + "ms ");
          //System.out.println("Pool Duration for 60% hits: " + pool3Duration + "ms ");
          System.out.println("Pool Efficiancy for 60% hits: " + pool3Efficiancy + "ms ");
          //System.out.println("Pool Duration for 50% hits: " + pool4Duration + "ms ");
          System.out.println("Pool Efficiancy for 50% hits: " + pool4Efficiancy + "ms ");
      }
  
      public void testLargeObjects()
          throws Exception
      {
          System.out.println("LARGE Sized Objects");
  
          System.gc();
          System.gc();
          Thread.currentThread().sleep(2);
  
          final DefaultPool pool1 = new DefaultPool( C.class, 5, 10 );
          final long pool1Start = System.currentTimeMillis();
          final int pool1Factor = 1;
          final int pool1Loops = TEST_SIZE / pool1Factor;
          for( int i = 0; i < TEST_SIZE; i++ )
          {
              final Poolable a1 = pool1.get();
              pool1.put(a1);                
          }
          final long pool1End = System.currentTimeMillis();
          final long pool1Duration = pool1End - pool1Start;
  
          System.gc();
          System.gc();
          Thread.currentThread().sleep(2);
  
          System.out.println("FreeMem post 1: " + Runtime.getRuntime().freeMemory() );
  
          final DefaultPool pool2 = new DefaultPool( C.class, 5, 10 );
          final long pool2Start = System.currentTimeMillis();
          final int pool2Factor = 10;
          final int pool2Loops = TEST_SIZE / pool2Factor;
          for( int i = 0; i < pool2Loops; i++ )
          {
              final Poolable a1 = pool2.get();
              final Poolable a2 = pool2.get();
              final Poolable a3 = pool2.get();
              final Poolable a4 = pool2.get();
              final Poolable a5 = pool2.get();
              final Poolable a6 = pool2.get();
              final Poolable a7 = pool2.get();
              final Poolable a8 = pool2.get();
              final Poolable a9 = pool2.get();
              final Poolable a10 = pool2.get();
              pool2.put(a1);                
              pool2.put(a2);
              pool2.put(a3);
              pool2.put(a4);
              pool2.put(a5);
              pool2.put(a6);
              pool2.put(a7);
              pool2.put(a8);
              pool2.put(a9);
              pool2.put(a10);
          }
          final long pool2End = System.currentTimeMillis();
          final long pool2Duration = pool2End - pool2Start;
  
          System.gc();
          System.gc();
          Thread.currentThread().sleep(2);
  
          System.out.println("FreeMem post 2: " + Runtime.getRuntime().freeMemory() );
  
          final DefaultPool pool3 = new DefaultPool( C.class, 5, 10 );
          final long pool3Start = System.currentTimeMillis();
          final int pool3Factor = 15;
          final int pool3Loops = TEST_SIZE / pool3Factor;
          for( int i = 0; i < pool3Loops; i++ )
          {
              final Poolable a1 = pool3.get();
              final Poolable a2 = pool3.get();
              final Poolable a3 = pool3.get();
              final Poolable a4 = pool3.get();
              final Poolable a5 = pool3.get();
              final Poolable a6 = pool3.get();
              final Poolable a7 = pool3.get();
              final Poolable a8 = pool3.get();
              final Poolable a9 = pool3.get();
              final Poolable a10 = pool3.get();
              final Poolable a11 = pool3.get();
              final Poolable a12 = pool3.get();
              final Poolable a13 = pool3.get();
              final Poolable a14 = pool3.get();
              final Poolable a15 = pool3.get();
              pool3.put(a1);                
              pool3.put(a2);
              pool3.put(a3);
              pool3.put(a4);
              pool3.put(a5);
              pool3.put(a6);
              pool3.put(a7);
              pool3.put(a8);
              pool3.put(a9);
              pool3.put(a10);
              pool3.put(a11);                
              pool3.put(a12);
              pool3.put(a13);
              pool3.put(a14);
              pool3.put(a15);
          }
          final long pool3End = System.currentTimeMillis();
          final long pool3Duration = pool3End - pool3Start;
  
          System.gc();
          System.gc();
          Thread.currentThread().sleep(2);
  
          System.out.println("FreeMem post 3: " + Runtime.getRuntime().freeMemory() );
  
          final DefaultPool pool4 = new DefaultPool( C.class, 5, 10 );
          final long pool4Start = System.currentTimeMillis();
          final int pool4Factor = 20;
          final int pool4Loops = TEST_SIZE / pool4Factor;
          for( int i = 0; i < pool4Loops; i++ )
          {
              final Poolable a1 = pool4.get();
              final Poolable a2 = pool4.get();
              final Poolable a3 = pool4.get();
              final Poolable a4 = pool4.get();
              final Poolable a5 = pool4.get();
              final Poolable a6 = pool4.get();
              final Poolable a7 = pool4.get();
              final Poolable a8 = pool4.get();
              final Poolable a9 = pool4.get();
              final Poolable a10 = pool4.get();
              final Poolable a11 = pool4.get();
              final Poolable a12 = pool4.get();
              final Poolable a13 = pool4.get();
              final Poolable a14 = pool4.get();
              final Poolable a15 = pool4.get();
              final Poolable a16 = pool4.get();
              final Poolable a17 = pool4.get();
              final Poolable a18 = pool4.get();
              final Poolable a19 = pool4.get();
              final Poolable a20 = pool4.get();
              pool4.put(a1);                
              pool4.put(a2);
              pool4.put(a3);
              pool4.put(a4);
              pool4.put(a5);
              pool4.put(a6);
              pool4.put(a7);
              pool4.put(a8);
              pool4.put(a9);
              pool4.put(a10);
              pool4.put(a11);                
              pool4.put(a12);
              pool4.put(a13);
              pool4.put(a14);
              pool4.put(a15);
              pool4.put(a16);
              pool4.put(a17);                
              pool4.put(a18);
              pool4.put(a19);
              pool4.put(a20);
          }
          final long pool4End = System.currentTimeMillis();
          final long pool4Duration = pool4End - pool4Start;
  
          System.out.println("FreeMem post 4: " + Runtime.getRuntime().freeMemory() );
  
          final long createStart = System.currentTimeMillis();
          for( int i = 0; i < TEST_SIZE; i++ )
          {
              final Poolable a1 = new C();
          }
          final long createEnd = System.currentTimeMillis();
          final long createDuration = createEnd - createStart;
  
          System.out.println("FreeMem post create: " + Runtime.getRuntime().freeMemory() );
  
          final double pool1Efficiancy = (double)createDuration/(double)pool1Duration * 100.0;
          final double pool2Efficiancy = (double)createDuration/(double)pool2Duration * 100.0;
          final double pool3Efficiancy = (double)createDuration/(double)pool3Duration * 100.0;
          final double pool4Efficiancy = (double)createDuration/(double)pool4Duration * 100.0;
  
          System.out.println("Pool Efficiancy for 100% hits: " + pool1Efficiancy + "ms ");
          System.out.println("Pool Efficiancy for 100% hits and saturated: " + pool2Efficiancy + "ms ");
          System.out.println("Pool Efficiancy for 60% hits: " + pool3Efficiancy + "ms ");
          System.out.println("Pool Efficiancy for 50% hits: " + pool4Efficiancy + "ms ");
      }
  
  
      public void testThreadedSmallObjects()
          throws Exception
      {
          System.out.println("SMALL Sized Objects with thread safe pools");
  
          final ThreadSafePool pool1 = new ThreadSafePool( A.class, 5, 10 );
          final long pool1Start = System.currentTimeMillis();
          final int pool1Factor = 1;
          final int pool1Loops = TEST_SIZE / pool1Factor;
          for( int i = 0; i < TEST_SIZE; i++ )
          {
              final Poolable a1 = pool1.get();
              pool1.put(a1);                
          }
          final long pool1End = System.currentTimeMillis();
          final long pool1Duration = pool1End - pool1Start;
  
          System.gc();
          System.gc();
          Thread.currentThread().sleep(2);
  
          System.out.println("FreeMem post 1: " + Runtime.getRuntime().freeMemory() );
  
          final ThreadSafePool pool2 = new ThreadSafePool( A.class, 5, 10 );
          final long pool2Start = System.currentTimeMillis();
          final int pool2Factor = 10;
          final int pool2Loops = TEST_SIZE / pool2Factor;
          for( int i = 0; i < pool2Loops; i++ )
          {
              final Poolable a1 = pool2.get();
              final Poolable a2 = pool2.get();
              final Poolable a3 = pool2.get();
              final Poolable a4 = pool2.get();
              final Poolable a5 = pool2.get();
              final Poolable a6 = pool2.get();
              final Poolable a7 = pool2.get();
              final Poolable a8 = pool2.get();
              final Poolable a9 = pool2.get();
              final Poolable a0 = pool2.get();
              pool2.put(a1);                
              pool2.put(a2);
              pool2.put(a3);
              pool2.put(a4);
              pool2.put(a5);
              pool2.put(a6);
              pool2.put(a7);
              pool2.put(a8);
              pool2.put(a9);
              pool2.put(a0);
          }
          final long pool2End = System.currentTimeMillis();
          final long pool2Duration = pool2End - pool2Start;
  
          System.gc();
          System.gc();
          Thread.currentThread().sleep(2);
  
          System.out.println("FreeMem post 2: " + Runtime.getRuntime().freeMemory() );
  
          final ThreadSafePool pool3 = new ThreadSafePool( A.class, 5, 10 );
          final long pool3Start = System.currentTimeMillis();
          final int pool3Factor = 15;
          final int pool3Loops = TEST_SIZE / pool3Factor;
          for( int i = 0; i < pool3Loops; i++ )
          {
              final Poolable a1 = pool3.get();
              final Poolable a2 = pool3.get();
              final Poolable a3 = pool3.get();
              final Poolable a4 = pool3.get();
              final Poolable a5 = pool3.get();
              final Poolable a6 = pool3.get();
              final Poolable a7 = pool3.get();
              final Poolable a8 = pool3.get();
              final Poolable a9 = pool3.get();
              final Poolable a10 = pool3.get();
              final Poolable a11 = pool3.get();
              final Poolable a12 = pool3.get();
              final Poolable a13 = pool3.get();
              final Poolable a14 = pool3.get();
              final Poolable a15 = pool3.get();
              pool3.put(a1);                
              pool3.put(a2);
              pool3.put(a3);
              pool3.put(a4);
              pool3.put(a5);
              pool3.put(a6);
              pool3.put(a7);
              pool3.put(a8);
              pool3.put(a9);
              pool3.put(a10);
              pool3.put(a11);                
              pool3.put(a12);
              pool3.put(a13);
              pool3.put(a14);
              pool3.put(a15);
          }
          final long pool3End = System.currentTimeMillis();
          final long pool3Duration = pool3End - pool3Start;
  
          System.gc();
          System.gc();
          Thread.currentThread().sleep(2);
  
          System.out.println("FreeMem post 3: " + Runtime.getRuntime().freeMemory() );
  
          final ThreadSafePool pool4 = new ThreadSafePool( A.class, 5, 10 );
          final long pool4Start = System.currentTimeMillis();
          final int pool4Factor = 20;
          final int pool4Loops = TEST_SIZE / pool4Factor;
          for( int i = 0; i < pool4Loops; i++ )
          {
              final Poolable a1 = pool4.get();
              final Poolable a2 = pool4.get();
              final Poolable a3 = pool4.get();
              final Poolable a4 = pool4.get();
              final Poolable a5 = pool4.get();
              final Poolable a6 = pool4.get();
              final Poolable a7 = pool4.get();
              final Poolable a8 = pool4.get();
              final Poolable a9 = pool4.get();
              final Poolable a10 = pool4.get();
              final Poolable a11 = pool4.get();
              final Poolable a12 = pool4.get();
              final Poolable a13 = pool4.get();
              final Poolable a14 = pool4.get();
              final Poolable a15 = pool4.get();
              final Poolable a16 = pool4.get();
              final Poolable a17 = pool4.get();
              final Poolable a18 = pool4.get();
              final Poolable a19 = pool4.get();
              final Poolable a20 = pool4.get();
              pool4.put(a1);                
              pool4.put(a2);
              pool4.put(a3);
              pool4.put(a4);
              pool4.put(a5);
              pool4.put(a6);
              pool4.put(a7);
              pool4.put(a8);
              pool4.put(a9);
              pool4.put(a10);
              pool4.put(a11);                
              pool4.put(a12);
              pool4.put(a13);
              pool4.put(a14);
              pool4.put(a15);
              pool4.put(a16);
              pool4.put(a17);                
              pool4.put(a18);
              pool4.put(a19);
              pool4.put(a20);
          }
          final long pool4End = System.currentTimeMillis();
          final long pool4Duration = pool4End - pool4Start;
  
          System.out.println("FreeMem post 4: " + Runtime.getRuntime().freeMemory() );
  
          final long createStart = System.currentTimeMillis();
          for( int i = 0; i < TEST_SIZE; i++ )
          {
              final Poolable a1 = new C();
          }
          final long createEnd = System.currentTimeMillis();
          final long createDuration = createEnd - createStart;
  
          //System.out.println("Create Duration: " + createDuration + "ms ");
          System.out.println("FreeMem post create: " + Runtime.getRuntime().freeMemory() );
  
          final double pool1Efficiancy = (double)createDuration/(double)pool1Duration * 100.0;
          final double pool2Efficiancy = (double)createDuration/(double)pool2Duration * 100.0;
          final double pool3Efficiancy = (double)createDuration/(double)pool3Duration * 100.0;
          final double pool4Efficiancy = (double)createDuration/(double)pool4Duration * 100.0;
  
          //System.out.println("Pool Duration for 100% hits: " + pool1Duration + "ms ");
          System.out.println("Pool Efficiancy for 100% hits: " + pool1Efficiancy + "ms ");
          //System.out.println("Pool Duration for 100% hits and saturated: " + pool2Duration + "ms ");
          System.out.println("Pool Efficiancy for 100% hits and saturated: " + pool2Efficiancy + "ms ");
          //System.out.println("Pool Duration for 60% hits: " + pool3Duration + "ms ");
          System.out.println("Pool Efficiancy for 60% hits: " + pool3Efficiancy + "ms ");
          //System.out.println("Pool Duration for 50% hits: " + pool4Duration + "ms ");
          System.out.println("Pool Efficiancy for 50% hits: " + pool4Efficiancy + "ms ");
      }
  
      public void testThreadedMediumObjects()
          throws Exception
      {
          System.out.println("MEDIUM Sized Objects with thread safe pools");
  
          System.gc();
          System.gc();
          Thread.currentThread().sleep(2);
  
          final ThreadSafePool pool1 = new ThreadSafePool( B.class, 5, 10 );
          final long pool1Start = System.currentTimeMillis();
          final int pool1Factor = 1;
          final int pool1Loops = TEST_SIZE / pool1Factor;
          for( int i = 0; i < TEST_SIZE; i++ )
          {
              final Poolable a1 = pool1.get();
              pool1.put(a1);                
          }
          final long pool1End = System.currentTimeMillis();
          final long pool1Duration = pool1End - pool1Start;
  
          System.gc();
          System.gc();
          Thread.currentThread().sleep(2);
  
          System.out.println("FreeMem post 1: " + Runtime.getRuntime().freeMemory() );
  
          final ThreadSafePool pool2 = new ThreadSafePool( B.class, 5, 10 );
          final long pool2Start = System.currentTimeMillis();
          final int pool2Factor = 10;
          final int pool2Loops = TEST_SIZE / pool2Factor;
          for( int i = 0; i < pool2Loops; i++ )
          {
              final Poolable a1 = pool2.get();
              final Poolable a2 = pool2.get();
              final Poolable a3 = pool2.get();
              final Poolable a4 = pool2.get();
              final Poolable a5 = pool2.get();
              final Poolable a6 = pool2.get();
              final Poolable a7 = pool2.get();
              final Poolable a8 = pool2.get();
              final Poolable a9 = pool2.get();
              final Poolable a10 = pool2.get();
              /*
                a1.build();
                a2.build();
                a3.build();
                a4.build();
                a5.build();
                a6.build();
                a7.build();
                a8.build();
                a9.build();
                a10.build();
              */
              pool2.put(a1);                
              pool2.put(a2);
              pool2.put(a3);
              pool2.put(a4);
              pool2.put(a5);
              pool2.put(a6);
              pool2.put(a7);
              pool2.put(a8);
              pool2.put(a9);
              pool2.put(a10);
          }
          final long pool2End = System.currentTimeMillis();
          final long pool2Duration = pool2End - pool2Start;
  
          System.gc();
          System.gc();
          Thread.currentThread().sleep(2);
  
          System.out.println("FreeMem post 2: " + Runtime.getRuntime().freeMemory() );
  
          final ThreadSafePool pool3 = new ThreadSafePool( B.class, 5, 10 );
          final long pool3Start = System.currentTimeMillis();
          final int pool3Factor = 15;
          final int pool3Loops = TEST_SIZE / pool3Factor;
          for( int i = 0; i < pool3Loops; i++ )
          {
              final Poolable a1 = pool3.get();
              final Poolable a2 = pool3.get();
              final Poolable a3 = pool3.get();
              final Poolable a4 = pool3.get();
              final Poolable a5 = pool3.get();
              final Poolable a6 = pool3.get();
              final Poolable a7 = pool3.get();
              final Poolable a8 = pool3.get();
              final Poolable a9 = pool3.get();
              final Poolable a10 = pool3.get();
              final Poolable a11 = pool3.get();
              final Poolable a12 = pool3.get();
              final Poolable a13 = pool3.get();
              final Poolable a14 = pool3.get();
              final Poolable a15 = pool3.get();
              /*
                a1.build();
                a2.build();
                a3.build();
                a4.build();
                a5.build();
                a6.build();
                a7.build();
                a8.build();
                a9.build();
                a10.build();
                a11.build();
                a12.build();
                a13.build();
                a14.build();
                a15.build();
              */
              pool3.put(a1);                
              pool3.put(a2);
              pool3.put(a3);
              pool3.put(a4);
              pool3.put(a5);
              pool3.put(a6);
              pool3.put(a7);
              pool3.put(a8);
              pool3.put(a9);
              pool3.put(a10);
              pool3.put(a11);                
              pool3.put(a12);
              pool3.put(a13);
              pool3.put(a14);
              pool3.put(a15);
          }
          final long pool3End = System.currentTimeMillis();
          final long pool3Duration = pool3End - pool3Start;
  
          System.gc();
          System.gc();
          Thread.currentThread().sleep(2);
  
          System.out.println("FreeMem post 3: " + Runtime.getRuntime().freeMemory() );
  
          final ThreadSafePool pool4 = new ThreadSafePool( B.class, 5, 10 );
          final long pool4Start = System.currentTimeMillis();
          final int pool4Factor = 20;
          final int pool4Loops = TEST_SIZE / pool4Factor;
          for( int i = 0; i < pool4Loops; i++ )
          {
              final Poolable a1 = pool4.get();
              final Poolable a2 = pool4.get();
              final Poolable a3 = pool4.get();
              final Poolable a4 = pool4.get();
              final Poolable a5 = pool4.get();
              final Poolable a6 = pool4.get();
              final Poolable a7 = pool4.get();
              final Poolable a8 = pool4.get();
              final Poolable a9 = pool4.get();
              final Poolable a10 = pool4.get();
              final Poolable a11 = pool4.get();
              final Poolable a12 = pool4.get();
              final Poolable a13 = pool4.get();
              final Poolable a14 = pool4.get();
              final Poolable a15 = pool4.get();
              final Poolable a16 = pool4.get();
              final Poolable a17 = pool4.get();
              final Poolable a18 = pool4.get();
              final Poolable a19 = pool4.get();
              final Poolable a20 = pool4.get();
              /*
                a1.build();
                a2.build();
                a3.build();
                a4.build();
                a5.build();
                a6.build();
                a7.build();
                a8.build();
                a9.build();
                a10.build();
                a11.build();
                a12.build();
                a13.build();
                a14.build();
                a15.build();
                a16.build();
                a17.build();
                a18.build();
                a19.build();
                a20.build();
              */
              pool4.put(a1);                
              pool4.put(a2);
              pool4.put(a3);
              pool4.put(a4);
              pool4.put(a5);
              pool4.put(a6);
              pool4.put(a7);
              pool4.put(a8);
              pool4.put(a9);
              pool4.put(a10);
              pool4.put(a11);                
              pool4.put(a12);
              pool4.put(a13);
              pool4.put(a14);
              pool4.put(a15);
              pool4.put(a16);
              pool4.put(a17);                
              pool4.put(a18);
              pool4.put(a19);
              pool4.put(a20);
          }
          final long pool4End = System.currentTimeMillis();
          final long pool4Duration = pool4End - pool4Start;
  
          final long createStart = System.currentTimeMillis();
          for( int i = 0; i < TEST_SIZE; i++ )
          {
              final Poolable a1 = new C();
          }
          final long createEnd = System.currentTimeMillis();
          final long createDuration = createEnd - createStart;
  
          //System.out.println("Create Duration: " + createDuration + "ms ");
          System.out.println("FreeMem post create: " + Runtime.getRuntime().freeMemory() );
  
          final double pool1Efficiancy = (double)createDuration/(double)pool1Duration * 100.0;
          final double pool2Efficiancy = (double)createDuration/(double)pool2Duration * 100.0;
          final double pool3Efficiancy = (double)createDuration/(double)pool3Duration * 100.0;
          final double pool4Efficiancy = (double)createDuration/(double)pool4Duration * 100.0;
  
          //System.out.println("Pool Duration for 100% hits: " + pool1Duration + "ms ");
          System.out.println("Pool Efficiancy for 100% hits: " + pool1Efficiancy + "ms ");
          //System.out.println("Pool Duration for 100% hits and saturated: " + pool2Duration + "ms ");
          System.out.println("Pool Efficiancy for 100% hits and saturated: " + pool2Efficiancy + "ms ");
          //System.out.println("Pool Duration for 60% hits: " + pool3Duration + "ms ");
          System.out.println("Pool Efficiancy for 60% hits: " + pool3Efficiancy + "ms ");
          //System.out.println("Pool Duration for 50% hits: " + pool4Duration + "ms ");
          System.out.println("Pool Efficiancy for 50% hits: " + pool4Efficiancy + "ms ");
      }
  
      public void testThreadedLargeObjects()
          throws Exception
      {
          System.out.println("LARGE Sized Objects with thread safe pools");
  
          System.gc();
          System.gc();
          Thread.currentThread().sleep(2);
  
          final ThreadSafePool pool1 = new ThreadSafePool( C.class, 5, 10 );
          final long pool1Start = System.currentTimeMillis();
          final int pool1Factor = 1;
          final int pool1Loops = TEST_SIZE / pool1Factor;
          for( int i = 0; i < TEST_SIZE; i++ )
          {
              final Poolable a1 = pool1.get();
              //a1.build();
              pool1.put(a1);                
          }
          final long pool1End = System.currentTimeMillis();
          final long pool1Duration = pool1End - pool1Start;
  
          System.gc();
          System.gc();
          Thread.currentThread().sleep(2);
  
          System.out.println("FreeMem post 1: " + Runtime.getRuntime().freeMemory() );
  
          final ThreadSafePool pool2 = new ThreadSafePool( C.class, 5, 10 );
          final long pool2Start = System.currentTimeMillis();
          final int pool2Factor = 10;
          final int pool2Loops = TEST_SIZE / pool2Factor;
          for( int i = 0; i < pool2Loops; i++ )
          {
              final Poolable a1 = pool2.get();
              final Poolable a2 = pool2.get();
              final Poolable a3 = pool2.get();
              final Poolable a4 = pool2.get();
              final Poolable a5 = pool2.get();
              final Poolable a6 = pool2.get();
              final Poolable a7 = pool2.get();
              final Poolable a8 = pool2.get();
              final Poolable a9 = pool2.get();
              final Poolable a10 = pool2.get();
              /*
                a1.build();
                a2.build();
                a3.build();
                a4.build();
                a5.build();
                a6.build();
                a7.build();
                a8.build();
                a9.build();
                a10.build();
              */
              pool2.put(a1);                
              pool2.put(a2);
              pool2.put(a3);
              pool2.put(a4);
              pool2.put(a5);
              pool2.put(a6);
              pool2.put(a7);
              pool2.put(a8);
              pool2.put(a9);
              pool2.put(a10);
          }
          final long pool2End = System.currentTimeMillis();
          final long pool2Duration = pool2End - pool2Start;
  
          System.gc();
          System.gc();
          Thread.currentThread().sleep(2);
  
          System.out.println("FreeMem post 2: " + Runtime.getRuntime().freeMemory() );
  
          final ThreadSafePool pool3 = new ThreadSafePool( C.class, 5, 10 );
          final long pool3Start = System.currentTimeMillis();
          final int pool3Factor = 15;
          final int pool3Loops = TEST_SIZE / pool3Factor;
          for( int i = 0; i < pool3Loops; i++ )
          {
              final Poolable a1 = pool3.get();
              final Poolable a2 = pool3.get();
              final Poolable a3 = pool3.get();
              final Poolable a4 = pool3.get();
              final Poolable a5 = pool3.get();
              final Poolable a6 = pool3.get();
              final Poolable a7 = pool3.get();
              final Poolable a8 = pool3.get();
              final Poolable a9 = pool3.get();
              final Poolable a10 = pool3.get();
              final Poolable a11 = pool3.get();
              final Poolable a12 = pool3.get();
              final Poolable a13 = pool3.get();
              final Poolable a14 = pool3.get();
              final Poolable a15 = pool3.get();
              /*
                a1.build();
                a2.build();
                a3.build();
                a4.build();
                a5.build();
                a6.build();
                a7.build();
                a8.build();
                a9.build();
                a10.build();
                a11.build();
                a12.build();
                a13.build();
                a14.build();
                a15.build();
              */
              pool3.put(a1);                
              pool3.put(a2);
              pool3.put(a3);
              pool3.put(a4);
              pool3.put(a5);
              pool3.put(a6);
              pool3.put(a7);
              pool3.put(a8);
              pool3.put(a9);
              pool3.put(a10);
              pool3.put(a11);                
              pool3.put(a12);
              pool3.put(a13);
              pool3.put(a14);
              pool3.put(a15);
          }
          final long pool3End = System.currentTimeMillis();
          final long pool3Duration = pool3End - pool3Start;
  
          System.gc();
          System.gc();
          Thread.currentThread().sleep(2);
  
          System.out.println("FreeMem post 3: " + Runtime.getRuntime().freeMemory() );
  
          final ThreadSafePool pool4 = new ThreadSafePool( C.class, 5, 10 );
          final long pool4Start = System.currentTimeMillis();
          final int pool4Factor = 20;
          final int pool4Loops = TEST_SIZE / pool4Factor;
          for( int i = 0; i < pool4Loops; i++ )
          {
              final Poolable a1 = pool4.get();
              final Poolable a2 = pool4.get();
              final Poolable a3 = pool4.get();
              final Poolable a4 = pool4.get();
              final Poolable a5 = pool4.get();
              final Poolable a6 = pool4.get();
              final Poolable a7 = pool4.get();
              final Poolable a8 = pool4.get();
              final Poolable a9 = pool4.get();
              final Poolable a10 = pool4.get();
              final Poolable a11 = pool4.get();
              final Poolable a12 = pool4.get();
              final Poolable a13 = pool4.get();
              final Poolable a14 = pool4.get();
              final Poolable a15 = pool4.get();
              final Poolable a16 = pool4.get();
              final Poolable a17 = pool4.get();
              final Poolable a18 = pool4.get();
              final Poolable a19 = pool4.get();
              final Poolable a20 = pool4.get();
              pool4.put(a1);                
              pool4.put(a2);
              pool4.put(a3);
              pool4.put(a4);
              pool4.put(a5);
              pool4.put(a6);
              pool4.put(a7);
              pool4.put(a8);
              pool4.put(a9);
              pool4.put(a10);
              pool4.put(a11);                
              pool4.put(a12);
              pool4.put(a13);
              pool4.put(a14);
              pool4.put(a15);
              pool4.put(a16);
              pool4.put(a17);                
              pool4.put(a18);
              pool4.put(a19);
              pool4.put(a20);
          }
          final long pool4End = System.currentTimeMillis();
          final long pool4Duration = pool4End - pool4Start;
  
          System.out.println("FreeMem post 4: " + Runtime.getRuntime().freeMemory() );
  
          final long createStart = System.currentTimeMillis();
          for( int i = 0; i < TEST_SIZE; i++ )
          {
              final Poolable a1 = new C();
          }
          final long createEnd = System.currentTimeMillis();
          final long createDuration = createEnd - createStart;
  
          System.out.println("FreeMem post create: " + Runtime.getRuntime().freeMemory() );
  
          final double pool1Efficiancy = (double)createDuration/(double)pool1Duration * 100.0;
          final double pool2Efficiancy = (double)createDuration/(double)pool2Duration * 100.0;
          final double pool3Efficiancy = (double)createDuration/(double)pool3Duration * 100.0;
          final double pool4Efficiancy = (double)createDuration/(double)pool4Duration * 100.0;
  
          System.out.println("Pool Efficiancy for 100% hits: " + pool1Efficiancy + "ms ");
          System.out.println("Pool Efficiancy for 100% hits and saturated: " + pool2Efficiancy + "ms ");
          System.out.println("Pool Efficiancy for 60% hits: " + pool3Efficiancy + "ms ");
          System.out.println("Pool Efficiancy for 50% hits: " + pool4Efficiancy + "ms ");
      }
  }
  
  
  
  1.1                  jakarta-avalon/src/java/org/apache/avalon/util/security/AbstractPolicy.java
  
  Index: AbstractPolicy.java
  ===================================================================
  /* 
   * Copyright (C) The Apache Software Foundation. All rights reserved. 
   * 
   * This software is published under the terms of the Apache Software License 
   * version 1.1, a copy of which has been included with this distribution in 
   * the LICENSE file. 
   */
  package org.apache.avalon.util.security;
  
  import java.io.File;
  import java.net.MalformedURLException;
  import java.net.URL;
  import java.security.AccessController;
  import java.security.CodeSource;
  import java.security.Permission;
  import java.security.PermissionCollection;
  import java.security.Permissions;
  import java.security.Policy;
  import java.security.PrivilegedActionException;
  import java.security.PrivilegedExceptionAction;
  import java.security.cert.Certificate;
  import java.util.ArrayList;
  import java.util.Enumeration;
  import java.util.PropertyPermission;
  import org.apache.avalon.Component;
  import org.apache.avalon.Loggable;
  import org.apache.avalon.util.io.FileUtil;
  import org.apache.log.Logger;
  
  /**
   * Abstract policy extended in avalon.
   * 
   * @author <a href="mailto:donaldp@apache.org">Peter Donald</a>
   */
  public abstract class AbstractPolicy
      extends Policy
      implements Component, Loggable
  {
      protected final static boolean     DEBUG         = true;
  
      protected final ArrayList        m_entries     = new ArrayList();
      
      protected Logger                 m_logger;
  
      /**
       * Internal Policy Entry holder class.
       */
      protected final static class PolicyEntry
      {
          CodeSource                      m_codeSource;
          Permissions                     m_permissions;
      }
  
      public void setLogger( final Logger logger )
      {
          m_logger = logger;
      }
  
      /**
       * Overide so we can have a per-application security policy with 
       * no side-effects to other applications.
       *
       * @param codeSource the codeSource to get permissions for 
       * @return the PermissionCollection
       */
      public PermissionCollection getPermissions( CodeSource codeSource )
      {
          codeSource = normalize( codeSource );
  
          getLogger().debug( "getPermissions(" + codeSource.getLocation() + ");" );
          
          final Permissions permissions = new Permissions();
          final int size = m_entries.size();
          
          for( int i = 0; i < size; i++ )
          {
              final PolicyEntry entry = (PolicyEntry)m_entries.get( i );
              
              if( entry.m_codeSource.implies( codeSource ) )
              {
                  if( DEBUG )
                  {
                      getLogger().debug( entry.m_codeSource.getLocation() + " implies " +
                                         codeSource.getLocation() );
                  }
  
                  copyPermissions( permissions, entry.m_permissions );
              }
          }
          
          if( DEBUG )
          {
              getLogger().debug( codeSource.getLocation() + " permissions = " + permissions );
          }
          
          return permissions;        
      }
  
      /**
       * Refresh policy. Ignored in this implementation.
       */
      public void refresh()
      {
      }
      
      /**
       * Normalizing CodeSource involves removing relative addressing 
       * (like .. and .) for file urls.
       *
       * @param codeSource the codeSource to be normalized
       * @return the normalized codeSource
       */
      protected CodeSource normalize( final CodeSource codeSource )
      {
          final URL initialLocation = codeSource.getLocation();
          
          // This is a bit of a hack.  I don't know why CodeSource should behave like this
          // Fear not, this only seems to be a problem for home grown classloaders.
          // - Paul Hammant, Nov 2000
          if( null == initialLocation ) return codeSource;
  
          String location = null;
          
          if( !initialLocation.getProtocol().equalsIgnoreCase( "file" ) )
          {
              location = initialLocation.getFile();
              location = FileUtil.normalize( location );
          }
          else
          {
              final File file = new File( initialLocation.getFile() );
              location = file.getAbsoluteFile().toString().replace( File.separatorChar, '/' );
              location =  FileUtil.normalize( location );
          }
          
          URL finalLocation = null;
          
          try
          {
              finalLocation = new URL( initialLocation.getProtocol(),
                                       initialLocation.getHost(),
                                       initialLocation.getPort(),
                                       location );
          }
          catch( final MalformedURLException mue ) 
          {
              getLogger().warn( "Error building codeBase", mue );
          }
  
          return new CodeSource( finalLocation, codeSource.getCertificates() );
      }
  
      protected void copyPermissions( final Permissions destination, final Permissions src )
      {
          final Enumeration enum = src.elements();
          while( enum.hasMoreElements() )
          {
              destination.add( (Permission)enum.nextElement() );
          }
      }
      
      /**
       * Create a permission set for a codeBase. 
       * These are read-write permissions and can be written till until the 
       * time in which they are applied to code.
       *
       * @param location the location of codes to apply permission set to.
       * @param signers a comma seperated string of thos who signed codebase
       * @return the new permission set
       * @exception MalformedURLException if location string is malformed
       */
      protected Permissions createPermissionSetFor( final String location, 
                                                    final Certificate[] signers )
          throws MalformedURLException
      {
          final PolicyEntry entry = new PolicyEntry();
          entry.m_codeSource = new CodeSource( new URL( location ), signers );
          entry.m_codeSource = normalize( entry.m_codeSource );
          
          getLogger().debug( "createPermissionSetFor(" + 
                             entry.m_codeSource.getLocation() + ");" );
          
          entry.m_permissions = new Permissions();
          
          m_entries.add( entry );
          return entry.m_permissions;
      }   
  
      protected final Logger getLogger()
      {
          return m_logger;
      }
  }
  
  
  
  1.1                  jakarta-avalon/src/java/org/apache/avalon/util/security/DefaultPolicy.java
  
  Index: DefaultPolicy.java
  ===================================================================
  /* 
   * Copyright (C) The Apache Software Foundation. All rights reserved. 
   * 
   * This software is published under the terms of the Apache Software License 
   * version 1.1, a copy of which has been included with this distribution in 
   * the LICENSE file. 
   */
  package org.apache.avalon.util.security;
  
  import java.io.File;
  import java.io.InputStream;
  import java.lang.reflect.Constructor;
  import java.net.MalformedURLException;
  import java.net.URL;
  import java.security.KeyStore;
  import java.security.KeyStoreException;
  import java.security.Permission;
  import java.security.PermissionCollection;
  import java.security.Permissions;
  import java.security.UnresolvedPermission;
  import java.security.cert.Certificate;
  import java.util.ArrayList;
  import java.util.HashMap;
  import java.util.Hashtable;
  import java.util.Iterator;
  import java.util.PropertyPermission;
  import java.util.StringTokenizer;
  import org.apache.avalon.Component;
  import org.apache.avalon.configuration.Configurable;
  import org.apache.avalon.configuration.Configuration;
  import org.apache.avalon.configuration.ConfigurationException;
  import org.apache.avalon.Context;
  import org.apache.avalon.Contextualizable;
  import org.apache.avalon.DefaultContext;
  import org.apache.avalon.Initializable;
  import org.apache.avalon.util.PropertyException;
  import org.apache.avalon.util.PropertyUtil;
  import org.apache.avalon.util.security.AbstractPolicy;
  
  /**
   * Policy that extracts information from policy files.
   * 
   * @author <a href="mailto:donaldp@apache.org">Peter Donald</a>
   */
  public class DefaultPolicy
      extends AbstractPolicy
      implements Component, Contextualizable, Configurable, Initializable
  {
      protected DefaultContext    m_context;
  
      public void contextualize( final Context context )
      {
          m_context = new DefaultContext( System.getProperties(), context );
          m_context.put( "/", File.separator );
      }
  
      public void configure( final Configuration configuration )
          throws ConfigurationException
      {
          final Configuration[] keyStoreConfigurations = configuration.getChildren( "keystore" );
          final HashMap keyStores = configureKeyStores( keyStoreConfigurations );
  
          final Configuration[] grants = configuration.getChildren( "grant" );
          configureGrants( grants, keyStores );
      }
  
      public void init()
          throws Exception
      {
          //these properties straight out ot ${java.home}/lib/security/java.policy
          final Permissions permissions = createPermissionSetFor( "file:/-", null );
  
          permissions.add( new PropertyPermission( "os.name", "read" ) );
          permissions.add( new PropertyPermission( "os.arch", "read" ) );
          permissions.add( new PropertyPermission( "os.version", "read" ) );
          permissions.add( new PropertyPermission( "file.separator", "read" ) );
          permissions.add( new PropertyPermission( "path.separator", "read" ) );
          permissions.add( new PropertyPermission( "line.separator", "read" ) );
          
          permissions.add( new PropertyPermission( "java.version", "read" ) );
          permissions.add( new PropertyPermission( "java.vendor", "read" ) );
          permissions.add( new PropertyPermission( "java.vendor.url", "read" ) );
          
          permissions.add( new PropertyPermission( "java.class.version", "read" ) );
          permissions.add( new PropertyPermission( "java.vm.version", "read" ) );
          permissions.add( new PropertyPermission( "java.vm.vendor", "read" ) );
          permissions.add( new PropertyPermission( "java.vm.name", "read" ) );
          
          permissions.add( new PropertyPermission( "java.specification.version", "read" ) );
          permissions.add( new PropertyPermission( "java.specification.vendor", "read" ) );
          permissions.add( new PropertyPermission( "java.specification.name", "read" ) );
          permissions.add( new PropertyPermission( "java.vm.specification.version", "read" ) );
          permissions.add( new PropertyPermission( "java.vm.specification.vendor", "read" ) );
          permissions.add( new PropertyPermission( "java.vm.specification.name", "read" ) );
      }
  
      protected HashMap configureKeyStores( final Configuration[] configurations )
          throws ConfigurationException
      {
          final HashMap keyStores = new HashMap();
  
          for( int i = 0; i < configurations.length; i++ )
          {
              final Configuration configuration = configurations[ i ];
              final String type = configuration.getAttribute( "type" );
              final String location = configuration.getAttribute( "location" );
              final String name = configuration.getAttribute( "name" );
  
              try
              {
                  final KeyStore keyStore = KeyStore.getInstance( type );
                  final URL url = new URL( location );
                  final InputStream ins = url.openStream();
                  
                  keyStore.load( ins, null );
  
                  keyStores.put( name, keyStore );
              }
              catch( final Exception e )
              {
                  throw new ConfigurationException( "Error configuring keystore " + name, e );
              }
          }
  
          return keyStores;
      }
      
      protected void configureGrants( final Configuration[] configurations, 
                                      final HashMap keyStores )
          throws ConfigurationException
      {
          for( int i = 0; i < configurations.length; i++ )
          {
              configureGrant( configurations[ i ], keyStores );
          }
      }
  
      protected void configureGrant( final Configuration configuration, final HashMap keyStores )
          throws ConfigurationException
      {
          //<grant signed-by="Fred" code-base="file:${sar.home}/blocks/*" key-store="foo-keystore">
          //<permission class="java.io.FilePermission" target="/tmp/*" action="read,write" />
          //</grant>
  
          final String signedBy = configuration.getAttribute( "signed-by", null );
          final String keyStoreName = configuration.getAttribute( "key-store", null );
  
          String codeBase = configuration.getAttribute( "code-base", null );
          if( null != codeBase )
          {
              codeBase = expand( codeBase );
          }
  
          final Certificate[] signers = getSigners( signedBy, keyStoreName, keyStores );
  
          Permissions permissions = null;
  
          try { permissions = createPermissionSetFor( codeBase, signers ); }
          catch( final MalformedURLException mue )
          {
              throw new ConfigurationException( "Malformed code-base " + codeBase, mue );
          }
  
          
          configurePermissions( configuration.getChildren( "permission" ), 
                                permissions,
                                keyStores );
      }
  
      protected void configurePermissions( final Configuration[] configurations, 
                                           final Permissions permissions,
                                           final HashMap keyStores )
          throws ConfigurationException
      {
          for( int i = 0; i < configurations.length; i++ )
          {
              configurePermission( configurations[ i ], permissions, keyStores );
          }
      }
  
      protected void configurePermission( final Configuration configuration,
                                          final Permissions permissions,
                                          final HashMap keyStores )
          throws ConfigurationException
      {
          final String type = configuration.getAttribute( "class" );
          final String actions = configuration.getAttribute( "actions", null );
          final String signedBy = configuration.getAttribute( "signed-by", null );
          final String keyStoreName = configuration.getAttribute( "key-store", null );
  
          String target = configuration.getAttribute( "target", null );
          if( null != target )
          {
              target = expand( target );
          }
  
          final Certificate[] signers = getSigners( signedBy, keyStoreName, keyStores );
          final Permission permission = createPermission( type, target, actions, signers );
  
          permissions.add( permission );
      }
  
      protected String expand( final String value )
          throws ConfigurationException
      {
          try
          {
              final Object resolvedValue = PropertyUtil.resolveProperty( value, m_context, false );
              return resolvedValue.toString();
          }
          catch( final PropertyException pe )
          {
              throw new ConfigurationException( "Error resolving property " + value, pe );
          }
      }
  
      protected Permission createPermission( final String type, 
                                             final String target, 
                                             final String actions, 
                                             final Certificate[] signers )
          throws ConfigurationException
      {
          if( null != signers ) 
          {
              return createUnresolvedPermission( type, target, actions, signers );
          }
          
          try
          {
              final Class c = Class.forName( type );
              
              Class paramClasses[] = null;
              Object params[] = null;
  
              if( null == actions && null == target )
              {
                  paramClasses = new Class[ 0 ];
                  params = new Object[ 0 ];
              }
              else if( null == actions ) 
              {
                  paramClasses = new Class[1];
                  paramClasses[0] = String.class;
                  params = new Object[1];
                  params[0] = target;
              }
              else
              {
                  paramClasses = new Class[2];
                  paramClasses[0] = String.class;
                  paramClasses[1] = String.class;
                  params = new Object[2];
                  params[0] = target;
                  params[1] = actions;
              }
              
              final Constructor constructor = c.getConstructor( paramClasses );
              final Object o = constructor.newInstance( params );
              return (Permission)o;                
          }
          catch( final ClassNotFoundException cnfe )
          {
              return createUnresolvedPermission( type, target, actions, signers );
          }
          catch( final Exception e )
          {
              throw new ConfigurationException( "Failed to create permission " + type + 
                                                " due to " + e, e );
          }
      }
      
      protected Permission createUnresolvedPermission( final String type, 
                                                       final String target, 
                                                       final String actions, 
                                                       final Certificate[] signers )
      {
          return new UnresolvedPermission( type, target, actions, signers );
      }
  
      protected Certificate[] getSigners( final String signedBy,
                                          String keyStoreName,
                                          final HashMap keyStores )
          throws ConfigurationException
      {
          if( null != signedBy && null == keyStoreName )
          {
              keyStoreName = "default";
          }
  
          Certificate[] signers = null;
           
          if( null != signedBy )
          {
              signers = getCertificates( signedBy, keyStoreName, keyStores );
          }
  
          return signers;
      }
  
      protected Certificate[] getCertificates( final String signedBy, 
                                               final String keyStoreName,
                                               final HashMap keyStores )
          throws ConfigurationException
      {
          final KeyStore keyStore = (KeyStore)keyStores.get( keyStoreName );
          
          if( null == keyStore )
          {
              throw new ConfigurationException( "Unable to aquire keyStore " + keyStoreName );
          }
  
          final ArrayList certificateSet = new ArrayList();
  
          final StringTokenizer tokenizer = new StringTokenizer( signedBy, "," );
          
          while( tokenizer.hasMoreTokens() ) 
          {
              final String alias = ((String)tokenizer.nextToken()).trim();
              Certificate certificate = null;
              
              try { certificate = keyStore.getCertificate( alias ); }
              catch( final KeyStoreException kse )
              {
                  throw new ConfigurationException( "Error aquiring certificate " + alias,
                                                    kse );
              }
  
              if( null == certificate )
              {
                  throw new ConfigurationException( "Unable to locate alias " + alias + 
                                                    " in keystore named " + keyStoreName );
              }
  
              if( !certificateSet.contains( certificate ) ) 
              {
                  if( DEBUG ) getLogger().debug( "Certificate " + certificate );
                  certificateSet.add( certificate );
              }
          }
          
          return (Certificate[])certificateSet.toArray( new Certificate[ 0 ] );
      }
  }
  
  
  
  1.1                  jakarta-avalon/src/java/org/apache/avalon/util/security/PolicyClassLoader.java
  
  Index: PolicyClassLoader.java
  ===================================================================
  /* 
   * Copyright (C) The Apache Software Foundation. All rights reserved. 
   * 
   * This software is published under the terms of the Apache Software License 
   * version 1.1, a copy of which has been included with this distribution in 
   * the LICENSE file. 
   */
  package org.apache.avalon.util.security;
  
  import java.net.URL;
  import java.net.URLClassLoader;
  import java.security.CodeSource;
  import java.security.PermissionCollection;
  import java.security.Permissions;
  import java.security.Policy;
  
  /**
   * Classloader that applies correct policy information.
   * 
   * @author <a href="mailto:donaldp@apache.org">Peter Donald</a>
   */
  public class PolicyClassLoader
      extends URLClassLoader
  {
      protected Policy      m_policy;
  
      public PolicyClassLoader( final URL[] urls, 
                                final ClassLoader classLoader, 
                                final Policy policy )
      {
          super( urls, classLoader );
          m_policy = policy;
      }
  
      /**
       * Overide so we can have a per-application security policy with 
       * no side-effects to other applications.
       *
       * @param codeSource the codeSource to get permissions for 
       * @return the PermissionCollection
       */
      protected PermissionCollection getPermissions( final CodeSource codeSource )
      {
          if( null == m_policy )
          {
              final Permissions permissions = new Permissions();
              permissions.add( new java.security.AllPermission() );
              return permissions;
          }
          else
          {
              return m_policy.getPermissions( codeSource );
          }
      }
  }
  
  
  
  1.1                  jakarta-avalon/src/java/org/apache/avalon/util/test/BinaryHeapTestlet.java
  
  Index: BinaryHeapTestlet.java
  ===================================================================
  /* 
   * Copyright (C) The Apache Software Foundation. All rights reserved. 
   * 
   * This software is published under the terms of the Apache Software License 
   * version 1.1, a copy of which has been included with this distribution in 
   * the LICENSE file. 
   */ 
  package org.apache.avalon.util.test;
   
  import org.apache.avalon.util.BinaryHeap; 
  import org.apache.testlet.AbstractTestlet; 
   
  /** 
   * 
   * @author <a href="mailto:donaldp@apache.org">Peter Donald</a> 
   */ 
  public final class BinaryHeapTestlet
      extends AbstractTestlet 
  {
      protected final static Integer VAL1 = new Integer( 1 );
      protected final static Integer VAL2 = new Integer( 2 );
      protected final static Integer VAL3 = new Integer( 3 );
      protected final static Integer VAL4 = new Integer( 4 );
      protected final static Integer VAL5 = new Integer( 5 );
      protected final static Integer VAL6 = new Integer( 6 );
      protected final static Integer VAL7 = new Integer( 7 );
  
      public void testSimpleOrder() 
      {
          final BinaryHeap heap = new BinaryHeap();
  
          heap.clear();
          heap.insert( VAL1 );
          heap.insert( VAL2 );
          heap.insert( VAL3 );
          heap.insert( VAL4 );
          
          assert( VAL1 == heap.peek() );
          assert( VAL1 == heap.pop() );
          assert( VAL2 == heap.pop() );
          assert( VAL3 == heap.pop() );
          assert( VAL4 == heap.pop() );
      }  
  
      public void testReverseOrder() 
      {
          final BinaryHeap heap = new BinaryHeap();
  
          heap.clear();
          heap.insert( VAL4 );
          heap.insert( VAL3 );
          heap.insert( VAL2 );
          heap.insert( VAL1 );        
  
          assert( VAL1 == heap.peek() );
          assert( VAL1 == heap.pop() );
          assert( VAL2 == heap.pop() );
          assert( VAL3 == heap.pop() );
          assert( VAL4 == heap.pop() );
      }  
  
      public void testMixedOrder() 
      {
          final BinaryHeap heap = new BinaryHeap();
  
          heap.clear();
          heap.insert( VAL4 );
          heap.insert( VAL2 );
          heap.insert( VAL1 );        
          heap.insert( VAL3 );
  
          assert( VAL1 == heap.peek() );
          assert( VAL1 == heap.pop() );
          assert( VAL2 == heap.pop() );
          assert( VAL3 == heap.pop() );
          assert( VAL4 == heap.pop() );
      }  
  
      public void testDuplicates() 
      {
          final BinaryHeap heap = new BinaryHeap();
  
          heap.clear();
          heap.insert( VAL4 );
          heap.insert( VAL2 );
          heap.insert( VAL1 );        
          heap.insert( VAL1 );        
          heap.insert( VAL1 );        
          heap.insert( VAL1 );
          heap.insert( VAL3 );
  
          assert( VAL1 == heap.peek() );
          assert( VAL1 == heap.pop() );
          assert( VAL1 == heap.pop() );
          assert( VAL1 == heap.pop() );
          assert( VAL1 == heap.pop() );
          assert( VAL2 == heap.pop() );
          assert( VAL3 == heap.pop() );
          assert( VAL4 == heap.pop() );
      }  
  
      public void testMixedInsertPopOrder() 
      {
          final BinaryHeap heap = new BinaryHeap();
  
          heap.clear();
          heap.insert( VAL1 );
          heap.insert( VAL4 );
          heap.insert( VAL2 );
          heap.insert( VAL1 );        
          heap.insert( VAL1 );        
          heap.insert( VAL1 );
          heap.insert( VAL3 );
  
          assert( VAL1 == heap.peek() );
          assert( VAL1 == heap.pop() );
          assert( VAL1 == heap.pop() );
          assert( VAL1 == heap.pop() );
          assert( VAL1 == heap.pop() );
  
          heap.insert( VAL4 );
          heap.insert( VAL2 );
          heap.insert( VAL1 );        
          heap.insert( VAL1 );        
          heap.insert( VAL1 );        
          heap.insert( VAL1 );
          heap.insert( VAL3 );
  
          assert( VAL1 == heap.peek() );
          assert( VAL1 == heap.pop() );
          assert( VAL1 == heap.pop() );
          assert( VAL1 == heap.pop() );
          assert( VAL1 == heap.pop() );
          assert( VAL2 == heap.pop() );
          assert( VAL2 == heap.pop() );
          assert( VAL3 == heap.pop() );
          assert( VAL3 == heap.pop() );
          assert( VAL4 == heap.pop() );
          assert( VAL4 == heap.pop() );
      }
  
      public void testReverseSimpleOrder() 
      {
          final BinaryHeap heap = new BinaryHeap( false );
  
          heap.clear();
          heap.insert( VAL1 );
          heap.insert( VAL2 );
          heap.insert( VAL3 );
          heap.insert( VAL4 );
  
          assert( VAL4 == heap.pop() );
          assert( VAL3 == heap.pop() );        
          assert( VAL2 == heap.pop() );
          assert( VAL1 == heap.peek() );
          assert( VAL1 == heap.pop() );
  
      }  
  
      public void testReverseReverseOrder() 
      {
          final BinaryHeap heap = new BinaryHeap( false );
  
          heap.clear();
          heap.insert( VAL4 );
          heap.insert( VAL3 );
          heap.insert( VAL2 );
          heap.insert( VAL1 );        
  
          assert( VAL4 == heap.pop() );
          assert( VAL3 == heap.pop() );
          assert( VAL2 == heap.pop() );
          assert( VAL1 == heap.peek() );
          assert( VAL1 == heap.pop() );
      }  
  
      public void testReverseMixedOrder() 
      {
          final BinaryHeap heap = new BinaryHeap( false );
  
          heap.clear();
          heap.insert( VAL4 );
          heap.insert( VAL2 );
          heap.insert( VAL1 );        
          heap.insert( VAL3 );
  
          assert( VAL4 == heap.pop() );
          assert( VAL3 == heap.pop() );
          assert( VAL2 == heap.pop() );
          assert( VAL1 == heap.peek() );
          assert( VAL1 == heap.pop() );
      }  
  
      public void testReverseDuplicates() 
      {
          final BinaryHeap heap = new BinaryHeap( false );
  
          heap.clear();
          heap.insert( VAL4 );
          heap.insert( VAL3 );
          heap.insert( VAL2 );
          heap.insert( VAL1 );        
          heap.insert( VAL1 );        
          heap.insert( VAL1 );        
          heap.insert( VAL1 );
  
          assert( VAL4 == heap.pop() );
          assert( VAL3 == heap.pop() );
          assert( VAL2 == heap.pop() );
          assert( VAL1 == heap.peek() );
          assert( VAL1 == heap.pop() );
          assert( VAL1 == heap.pop() );
          assert( VAL1 == heap.pop() );
          assert( VAL1 == heap.pop() );
      }  
  
      public void testReverseMixedInsertPopOrder() 
      {
          final BinaryHeap heap = new BinaryHeap( false );
  
          heap.clear();
          heap.insert( VAL1 );
          heap.insert( VAL4 );
          heap.insert( VAL2 );
          heap.insert( VAL1 );        
          heap.insert( VAL1 );        
          heap.insert( VAL1 );
          heap.insert( VAL3 );
  
          assert( VAL4 == heap.pop() );
          assert( VAL3 == heap.pop() );
          assert( VAL2 == heap.pop() );
  
          heap.insert( VAL4 );
          heap.insert( VAL2 );
          heap.insert( VAL1 );        
          heap.insert( VAL1 );        
          heap.insert( VAL1 );        
          heap.insert( VAL1 );
          heap.insert( VAL3 );
  
          assert( VAL4 == heap.pop() );
          assert( VAL3 == heap.pop() );
          assert( VAL2 == heap.pop() );
          assert( VAL1 == heap.peek() );
          assert( VAL1 == heap.pop() );
          assert( VAL1 == heap.peek() );
          assert( VAL1 == heap.pop() );
          assert( VAL1 == heap.pop() );
          assert( VAL1 == heap.pop() );
          assert( VAL1 == heap.pop() );
          assert( VAL1 == heap.pop() );
          assert( VAL1 == heap.pop() );
          assert( VAL1 == heap.pop() );
      }  
  }
  
  
  
  1.1                  jakarta-avalon/src/java/org/apache/avalon/util/test/DependencyGraphTestlet.java
  
  Index: DependencyGraphTestlet.java
  ===================================================================
  /* 
   * Copyright (C) The Apache Software Foundation. All rights reserved. 
   * 
   * This software is published under the terms of the Apache Software License 
   * version 1.1, a copy of which has been included with this distribution in 
   * the LICENSE file. 
   */ 
  package org.apache.avalon.util.test;
  
  import java.util.List;
  import org.apache.avalon.util.CircularDependencyException;
  import org.apache.avalon.util.DependencyGraph; 
  import org.apache.testlet.AbstractTestlet; 
   
  /** 
   * 
   * @author <a href="mailto:donaldp@apache.org">Peter Donald</a> 
   */ 
  public final class DependencyGraphTestlet
      extends AbstractTestlet 
  {
      protected final String[][]        DEPENDENCY_TREE =
      {
          { "A" }, { "B", "C", "D" },
          { "B" }, { "E" },
          { "C" }, {},
          { "D" }, { "F" },
          { "E" }, { "F" },
          { "F" }, { },
          { "G" }, { "H" },
          { "H" }, { "G" },
          { "I" }, { "I" }
      };
  
      protected DependencyGraph       m_graph;
      
      public void initialize()
      {
          m_graph = new DependencyGraph();
  
          for( int i = 0; i < DEPENDENCY_TREE.length; i += 2 )
          {
              m_graph.add( DEPENDENCY_TREE[ i ][0], DEPENDENCY_TREE[ i + 1 ] );
          }
      }
  
      protected boolean contains( final DependencyGraph.Dependency[] list, final String name )
      {
          for( int i = 0; i < list.length; i++ )
          {
              if( list[ i ].getName().equals( name ) )
              {
                  return true;
              }
          }
  
          return false;
      }
  
      public void testNoDependency() 
          throws Exception
      {
          final DependencyGraph.Dependency[] list = m_graph.getDependencyList( "F" );
          
          assertEquality( "Graph for F", list.length, 1 );
          assertEquality( "Graph for F[1]", list[ 0 ].getName(), "F" );
          assertEquality( "Graph for F[1]", list[ 0 ].getRequiredBy(), null );
      }
  
      public void test1LevelDependency() 
          throws Exception
      {
          final DependencyGraph.Dependency[] list = m_graph.getDependencyList( "E" );
          
          assertEquality( "Graph for E", list.length, 2 );
          assert( "Graph for E[1]", contains( list, "E" ) );
          assert( "Graph for E[2]", contains( list, "F" ) );
      }
  
      public void test2LevelDependency() 
          throws Exception
      {
          final DependencyGraph.Dependency[] list = m_graph.getDependencyList( "B" );
          
          assertEquality( "Graph for E", list.length, 3 );
          assert( "Graph for E[1]", contains( list, "E" ) );
          assert( "Graph for E[2]", contains( list, "F" ) );
          assert( "Graph for E[3]", contains( list, "B" ) );
      }
  
      public void testNLevelDependency() 
          throws Exception
      {
          final DependencyGraph.Dependency[] list = m_graph.getDependencyList( "A" );
  
          assertEquality( "Graph for A", list.length, 6 );
          assert( "Graph for A[1]", contains( list, "A" ) );
          assert( "Graph for A[2]", contains( list, "B" ) );
          assert( "Graph for A[3]", contains( list, "C" ) );
          assert( "Graph for A[4]", contains( list, "D" ) );
          assert( "Graph for A[5]", contains( list, "E" ) );
          assert( "Graph for A[6]", contains( list, "F" ) );
      }
  
      public void testAllowableCircularDependency() 
          throws Exception
      {
          m_graph.setAllowCircularity( true );
          final DependencyGraph.Dependency[] list = m_graph.getDependencyList( "G" );
  
          assertEquality( "Graph for G", list.length, 2 );
          assert( "Graph for G[1]", contains( list, "G" ) );
          assert( "Graph for H[2]", contains( list, "H" ) );
      }
  
      public void testUnallowableCircularDependency() 
          throws Exception
      {
          try
          {
              m_graph.setAllowCircularity( false );
              m_graph.getDependencyList( "G" );
          }
          catch( final CircularDependencyException cde )
          {
              return;
          }
  
          fail( "Expected CircularDependencyException" );
      }
  }
  
  
  
  1.1                  jakarta-avalon/src/java/org/apache/avalon/util/test/PropertyUtilTestlet.java
  
  Index: PropertyUtilTestlet.java
  ===================================================================
  /* 
   * Copyright (C) The Apache Software Foundation. All rights reserved. 
   * 
   * This software is published under the terms of the Apache Software License 
   * version 1.1, a copy of which has been included with this distribution in 
   * the LICENSE file. 
   */ 
  package org.apache.avalon.util.test;
  
  import org.apache.avalon.Context; 
  import org.apache.avalon.DefaultContext; 
  import org.apache.avalon.Resolvable; 
  import org.apache.avalon.util.PropertyException; 
  import org.apache.avalon.util.PropertyUtil; 
  import org.apache.testlet.AbstractTestlet; 
   
  /** 
   * 
   * @author <a href="mailto:donaldp@apache.org">Peter Donald</a> 
   */ 
  public final class PropertyUtilTestlet
      extends AbstractTestlet 
  {
      protected static final class ResolveTest
          implements Resolvable
      {
          protected int           m_count;
          protected int           m_current;
  
          public ResolveTest( final int count )
          {
              m_count = count;
          }
  
          public Object resolve( final Context context )
          {
              m_current++;
  
              if( m_current >= m_count ) return new Integer( m_count );
              else return this;
          }
      }
  
      protected final static Object     OBJ1         = new Object();
      protected final static Object     OBJ2         = new Object();
  
      protected DefaultContext          m_context;
      
  
      public void initialize()
      {
          m_context = new DefaultContext();
          m_context.put( "obj1", OBJ1 ); 
          m_context.put( "obj2", OBJ2 ); 
          m_context.put( "res1", new ResolveTest( 1 ) ); 
          m_context.put( "res2", new ResolveTest( 2 ) ); 
          m_context.put( "res3", new ResolveTest( 3 ) ); 
          m_context.put( "res4", new ResolveTest( 4 ) ); 
      }
  
      public void testNoResolve() 
          throws PropertyException
      {
          final Object result = 
              PropertyUtil.resolveProperty( "blah", m_context, false );
          
          assertEquality( result, "blah" );
      }
      
      public void testObjResolve() 
          throws PropertyException
      {
          final Object result = 
              PropertyUtil.resolveProperty( "${obj1}", m_context, false );
  
          assertEquality( result, OBJ1 );
      }
      
      public void testObjResolveToText() 
          throws PropertyException
      {
          final Object result = 
              PropertyUtil.resolveProperty( "${obj1} ", m_context, false );
          
          assertEquality( result, OBJ1 + " " );
      }
      
      public void testDualObjResolve() 
          throws PropertyException
      {
          final Object result = 
              PropertyUtil.resolveProperty( " ${obj1} ${obj2} ", m_context, false );
          
          assertEquality( result, " " + OBJ1 + " " + OBJ2 + " " );
      }
      
      public void testRecurseObjResolve() 
          throws PropertyException
      {
          final Object result = 
              PropertyUtil.resolveProperty( "${res1}", m_context, false );
          
          assertEquality( result, new Integer( 1 ) );
      }
      
      public void testRecurseObjResolve2() 
          throws PropertyException
      {
          final Object result = 
              PropertyUtil.resolveProperty( "${res2}", m_context, false );
          
          assertEquality( result, new Integer( 2 ) );
      }
      
      public void testNullObjResolve() 
          throws PropertyException
      {
          final Object result = 
              PropertyUtil.resolveProperty( "${blahaaa}", m_context, true );
          
          assertEquality( result, "" );
      }
      
      public void testNullObjResolveForException() 
          throws PropertyException
      {
          try
          {
              final Object result = 
                  PropertyUtil.resolveProperty( "${blahaaa}", m_context, false );
          }
          catch( final PropertyException pe )
          {
              return;
          }
          fail( "NUll resolve occured without exception" );
      }
  }
  
  
  
  1.1                  jakarta-avalon/src/java/org/apache/avalon/util/test/ProxyGeneratorTestlet.java
  
  Index: ProxyGeneratorTestlet.java
  ===================================================================
  /* 
   * Copyright  The Apache Software Foundation. All rights reserved. 
   * 
   * This software is published under the terms of the Apache Software License 
   * version 1.1, a copy of which has been included with this distribution in 
   * the LICENSE file. 
   */ 
  package org.apache.avalon.util.test;
  
  import org.apache.avalon.util.ProxyGenerator;
  import org.apache.testlet.AbstractTestlet;
  import org.apache.testlet.TestFailedException;  
   
  /** 
   * This is used to test Proxy generation for correctness. 
   * 
   * @author <a href="mailto:donaldp@apache.org">Peter Donald</a> 
   */ 
  public final class ProxyGeneratorTestlet 
      extends AbstractTestlet 
  {  
      public interface Interface1 
      { 
          void method1();
      }
  
      public interface Interface2 extends Interface1
      { 
          void method2();
      } 
  
      public interface Interface3
      { 
          void method3( int x );
      }
  
      public interface Interface4
      { 
          void method4( String x );
      }
  
      public interface Interface5
      { 
          void method3( String x );
      }
   
      public interface Interface6
      { 
          void method2();
      } 
  
      public interface Interface7
      { 
          void method3( double x );
      }
  
      public interface Interface8
      { 
          void method3( double x, double y );
      }
  
      public interface Interface9
      { 
          int method4( double x, double y );
      }
  
  
      public interface Interface10
      { 
          double method10( double x, double y );
      }
  
      public static class ClassA 
          implements Interface1, Interface3, Interface4, Interface5, Interface9, Interface10
      { 
          public void method1() {}
          public void method3( int x ) {}
          public void method3( String x ) {}
          public void method4( String x ) {}
          public int method4( double x, double y ) { return 0; }
          public double method10( double x, double y ) { return 0.0; }
      } 
  
      public static class ClassB implements Interface2, Interface6, Interface7, Interface8
      { 
          public void method1() {}
          public void method2() {}
          public void method3( double x ) {}
          public void method3( double x, double y ) {}
      } 
  
      public void testNoParamMethod() 
          throws Exception 
      { 
          final Class[] interfaces = new Class[] { Interface1.class };
          final Object object = new ClassA();
          final Object result = doTest( object, interfaces );
          ((Interface1)result).method1();
      }
  
      public void testExtendedInterfaceHidden() 
          throws Exception 
      { 
          final Class[] interfaces = new Class[] { Interface1.class };
          final Object object = new ClassB();
          final Object result = doTest( object, interfaces );
          ((Interface1)result).method1();
          assert( !(result instanceof Interface2) );
      }
  
      public void testExtendedInterface() 
          throws Exception 
      { 
          final Class[] interfaces = new Class[] { Interface1.class, Interface2.class };
          final Object object = new ClassB();
          final Object result = doTest( object, interfaces );
          ((Interface1)result).method1();
          ((Interface2)result).method1();
          ((Interface2)result).method2();
      }
  
      public void testIntParamInterface() 
          throws Exception 
      { 
          final Class[] interfaces = new Class[] { Interface3.class };
          final Object object = new ClassA();
          final Object result = doTest( object, interfaces );
          ((Interface3)result).method3(2);
      }
  
      public void testStringParamInterface() 
          throws Exception 
      { 
          final Class[] interfaces = new Class[] { Interface4.class };
          final Object object = new ClassA();
          final Object result = doTest( object, interfaces );
          ((Interface4)result).method4("Hello");
      }
  
      public void testOverloadedStringParamInterface() 
          throws Exception 
      { 
          final Class[] interfaces = new Class[] { Interface5.class };
          final Object object = new ClassA();
          final Object result = doTest( object, interfaces );
          ((Interface5)result).method3("Hello");
      }
  
      public void testDuplicateMethodInterface() 
          throws Exception 
      { 
          final Class[] interfaces = new Class[] { Interface2.class, Interface6.class };
          final Object object = new ClassB();
          final Object result = doTest( object, interfaces );
          ((Interface6)result).method2();
          ((Interface2)result).method2();
      }
  
      public void testDoubleParamInterface() 
          throws Exception 
      { 
          final Class[] interfaces = new Class[] { Interface7.class };
          final Object object = new ClassB();
          final Object result = doTest( object, interfaces );
          ((Interface7)result).method3(2.0);
      }
  
      public void test2DoubleParamInterface() 
          throws Exception 
      { 
          final Class[] interfaces = new Class[] { Interface8.class };
          final Object object = new ClassB();
          final Object result = doTest( object, interfaces );
          ((Interface8)result).method3(2.0,2.0);
      }
  
      public void testIntReturnInterface() 
          throws Exception 
      { 
          final Class[] interfaces = new Class[] { Interface9.class };
          final Object object = new ClassA();
          final Object result = doTest( object, interfaces );
          final int x = ((Interface9)result).method4(2.0,2.0);
      }
  
      public void testDoubleReturnInterface() 
          throws Exception 
      { 
          final Class[] interfaces = new Class[] { Interface10.class };
          final Object object = new ClassA();
          final Object result = doTest( object, interfaces );
          final double x = ((Interface10)result).method10(2.0,2.0);
      }
  
      protected Object doTest( final Object object, final Class[] interfaces )
          throws Exception 
      {
          final Object result =
              ProxyGenerator.generateProxy( object, interfaces );
  
          if( null == result )
          {
              throw new TestFailedException( "Proxy object failed to be created." );
          }
  
          for( int i = 0; i < interfaces.length; i++ )
          {
              if( !interfaces[ i ].isInstance( result ) )
              {
                  throw new TestFailedException( "Interface " + interfaces[ i ] +
                                                 " not implemented by proxy." );
              }
          }
          
          return result;
      }
  }
  
  
  
  
  
  
  
  1.1                  jakarta-avalon/src/java/org/apache/avalon/util/test/StringUtilTestlet.java
  
  Index: StringUtilTestlet.java
  ===================================================================
  /* 
   * Copyright (C) The Apache Software Foundation. All rights reserved. 
   * 
   * This software is published under the terms of the Apache Software License 
   * version 1.1, a copy of which has been included with this distribution in 
   * the LICENSE file. 
   */ 
  package org.apache.avalon.util.test;
   
  import org.apache.avalon.util.StringUtil; 
  import org.apache.testlet.AbstractTestlet; 
   
  /** 
   * 
   * @author <a href="mailto:donaldp@apache.org">Peter Donald</a> 
   */ 
  public final class StringUtilTestlet
      extends AbstractTestlet 
  {
      public void testNoReplace() 
      {
          final String result = 
              StringUtil.replaceSubString("blah", "not-there", "ignored" );
          
          assertEquality( result, "blah" );
      }
   
      public void testMidReplace() 
      {
          final String result = 
              StringUtil.replaceSubString("blah", "la", "le" );
          
          assertEquality( result, "bleh" );
      }
  
      
      public void testStartReplace() 
      {
          final String result = 
              StringUtil.replaceSubString("blah", "bla", "ble" );
          
          assertEquality( result, "bleh" );
      }
      
      public void testEndReplace() 
      {
          final String result = 
              StringUtil.replaceSubString("blah", "lah", "leh" );
          
          assertEquality( result, "bleh" );
      }
  
      public void testDoubleReplace() 
      {
          final String result = 
              StringUtil.replaceSubString("blahblah", "la", "le" );
          
          assertEquality( result, "blehbleh" );
      }
  }
  
  
  
  1.1                  jakarta-avalon/src/java/org/apache/avalon/util/thread/DefaultThreadManager.java
  
  Index: DefaultThreadManager.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE file.
   */
  package org.apache.avalon.util.thread;
  
  import java.util.Hashtable;
  import java.util.Iterator;
  import org.apache.avalon.AbstractLoggable;
  import org.apache.avalon.configuration.Configurable;
  import org.apache.avalon.configuration.Configuration;
  import org.apache.avalon.configuration.ConfigurationException;
  
  /**
   *
   *
   * @author <a href="mailto:fede@apache.org">Federico Barbieri</a>
   * @author <a href="mailto:donaldp@apache.org">Peter Donald</a>
   */
  public class DefaultThreadManager
      extends AbstractLoggable
      implements ThreadManager, Configurable 
  {
      protected final Hashtable       m_pools = new Hashtable();
  
      public void configure( final Configuration configuration )
          throws ConfigurationException
      {
          final Configuration[] groups = configuration.getChildren( "thread-group" );
          for( int i = 0; i < groups.length; i++ )
          {
              final Configuration group = groups[ i ];
  
              final String name = group.getChild( "name" ).getValue();            
              final int priority = group.getChild( "priority" ).getValueAsInt( 5 );
              final boolean isDaemon = group.getChild( "is-daemon" ).getValueAsBoolean( false );
  
              final int minThreads = group.getChild( "min-threads" ).getValueAsInt( 5 );
              final int maxThreads = group.getChild( "max-threads" ).getValueAsInt( 10 );
              final int minSpareThreads = group.getChild( "min-spare-threads" ).
                  getValueAsInt( maxThreads - minThreads );
  
              try
              {
                  final ThreadPool threadPool = new ThreadPool( name, maxThreads );
                  threadPool.setDaemon( isDaemon );
                  setupLogger( threadPool );
                  m_pools.put( name, threadPool );
              }
              catch( final Exception e )
              {
                  throw new ConfigurationException( "Error creating thread pool " + name,
                                                    e );
              }
          }
      }
  
      public ThreadPool getDefaultThreadPool()
      {
          return getThreadPool( "default" );
      }
  
      public ThreadPool getThreadPool( final String name ) 
      {
          final ThreadPool threadPool = (ThreadPool)m_pools.get( name );
  
          if( null == threadPool )
          {
              //Should this be a ComponentNotFoundException ????
              throw new IllegalArgumentException( "No such thread group " + name );
          }
  
          return threadPool;
      }
  }
  
  
  
  1.1                  jakarta-avalon/src/java/org/apache/avalon/util/thread/ThreadContext.java
  
  Index: ThreadContext.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE file.
   */
  package org.apache.avalon.util.thread;
  
  import org.apache.avalon.Poolable;
  import org.apache.avalon.util.pool.ObjectFactory;
  import org.apache.avalon.util.pool.ThreadSafePool;
  
  /**
   * To deal with *current* ThreadContext.
   *
   * @author <a href="mailto:donaldp@apache.org">Peter Donald</a>
   */
  public final class ThreadContext 
  {
      protected final static InheritableThreadLocal   c_context = new InheritableThreadLocal();
  
      public static ThreadPool getCurrentThreadPool()
      {
          return (ThreadPool)c_context.get();
      }
  
      public static void setCurrentThreadPool( final ThreadPool threadPool )
      {
          //TODO: protect by a permission guard
          c_context.set( threadPool );
      }
  }
  
  
  
  1.1                  jakarta-avalon/src/java/org/apache/avalon/util/thread/ThreadManager.java
  
  Index: ThreadManager.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE file.
   */
  package org.apache.avalon.util.thread;
  
  import org.apache.avalon.Component;
  
  /**
   * Interface for component that hands out thread pools.
   *
   * @author <a href="mailto:fede@apache.org">Federico Barbieri</a>
   * @author <a href="mailto:donaldp@apache.org">Peter Donald</a>
   */
  public interface ThreadManager
      extends Component
  {
      ThreadPool getThreadPool( String name );
      ThreadPool getDefaultThreadPool();
  }
  
  
  
  1.1                  jakarta-avalon/src/java/org/apache/avalon/util/thread/ThreadPool.java
  
  Index: ThreadPool.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE file.
   */
  package org.apache.avalon.util.thread;
  
  import org.apache.avalon.Loggable;
  import org.apache.avalon.Poolable;
  import org.apache.avalon.util.pool.ObjectFactory;
  import org.apache.avalon.util.pool.ThreadSafePool;
  import org.apache.log.Logger;
  
  /**
   * This class is the public frontend for the thread pool code.
   *
   * TODO: Should this be configured with min threads, max threads and min spare threads ?
   *
   * @author <a href="mailto:stefano@apache.org">Stefano Mazzocchi</a>
   * @author <a href="mailto:donaldp@apache.org">Peter Donald</a>
   */
  public class ThreadPool 
      extends ThreadGroup
      implements ObjectFactory, Loggable
  {
      protected final ThreadSafePool        m_pool;
      protected int                         m_level;
      protected Logger                      m_logger;
  
      public ThreadPool( final int capacity )
          throws Exception
      {
          this( "Worker Pool", capacity );
      }
  
      public ThreadPool( final String name, final int capacity )
          throws Exception 
      {
          super( name );
          m_pool = new ThreadSafePool( this, 0 );
          m_pool.init();
          m_pool.grow( capacity );
      }
  
      public void setLogger( final Logger logger )
      {
          m_logger = logger;
      }
  
      public Poolable newInstance()
      {
          final WorkerThread worker = 
              new WorkerThread( this, m_pool, getName() + " Worker #" + m_level++ );
          worker.setLogger( m_logger );
          worker.start();
          return worker;
      }
  
      public Class getCreatedClass()
      {
          return WorkerThread.class;
      }
          
      public void execute( final Runnable work ) 
          throws Exception
      {
          execute( work, Thread.NORM_PRIORITY );
      }
  
      public void execute( final Runnable work, final int priority ) 
          throws Exception
      {
          final WorkerThread worker = getWorker( priority );
          worker.execute( work );
      }
      
      public void executeAndWait( final Runnable work ) 
          throws Exception
      {
          executeAndWait( work, Thread.NORM_PRIORITY );
      }
  
      public void executeAndWait( final Runnable work, final int priority ) 
          throws Exception
      {
          final WorkerThread worker = getWorker( priority );
          worker.executeAndWait( work );
      }
  
      protected WorkerThread getWorker( final int priority )
          throws Exception
      {
          final WorkerThread worker = (WorkerThread)m_pool.get();
          worker.setContextClassLoader( Thread.currentThread().getContextClassLoader() );
          worker.setPriority( priority );
          return worker;
      }
  }
  
  
  
  1.1                  jakarta-avalon/src/java/org/apache/avalon/util/thread/WorkerThread.java
  
  Index: WorkerThread.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE file.
   */
  package org.apache.avalon.util.thread;
  
  import org.apache.avalon.Loggable;
  import org.apache.avalon.Poolable;
  import org.apache.avalon.util.pool.ThreadSafePool;
  import org.apache.log.Logger;
  
  /**
   * This class extends the Thread class to add recyclable functionalities.
   *
   * @author <a href="mailto:stefano@apache.org">Stefano Mazzocchi</a>
   * @author <a href="mailto:donaldp@apache.org">Peter Donald</a>
   */
  class WorkerThread 
      extends Thread 
      implements Poolable, Loggable
  {
      protected final static boolean  DEBUG          = false;
  
      protected Logger                m_logger;
      protected ThreadPool            m_threadPool;
      protected ThreadSafePool        m_pool;
  
      protected Runnable              m_work;
      protected boolean               m_alive;
  
      /**
       * Allocates a new <code>Worker</code> object.
       */
      protected WorkerThread( final ThreadPool threadPool,
                              final ThreadSafePool pool, 
                              final String name )
      {
          super( threadPool, name );
          
          m_threadPool = threadPool;
          m_pool = pool;
  
          m_work = null;
          m_alive = true;
          setDaemon( false );
      }
  
      public void setLogger( final Logger logger )
      {
          m_logger = logger;
      }
  
      /**
       * The main execution loop.
       */
      public final synchronized void run()
      {
          ThreadContext.setCurrentThreadPool( m_threadPool );
  
          if( DEBUG ) m_logger.info( getName() + ": starting." );
                  
          // Notify the pool this worker started running.
          //notifyAll();
  
          while( m_alive )
          {
              waitUntilCondition( true );
  
              if( DEBUG ) m_logger.debug( getName() + ": running." );
                  
              try 
              {
                  m_work.run();
              } 
              catch( final ThreadDeath td )
              {
                  if ( DEBUG ) m_logger.debug( getName() + ": thread has died." );
                          
                  // This is to let the thread death propagate to the runtime
                  // enviroment to let it know it must kill this worker
                  throw td;
              } 
              catch( final Throwable t )
              {
                  // Error thrown while working.
                  if( DEBUG ) m_logger.debug( getName() + ": error caught: " + t );
                  // XXX: what should we do when this happens?
              }
  
              if( DEBUG ) m_logger.debug( getName() + ": done." );
  
              m_work = null;
  
              //should this be just notify or notifyAll ??? 
              //It seems to resource intensive option to use notify()
              //notifyAll();
              notify();
  
              // recycle ourselves
              if( null != m_pool )
              {
                  m_pool.put( this );
              }
              else
              {
                  m_alive = false;
              }
          }
      }
  
      /**
       * Set the <code>Work</code> code this <code>Worker</code> must
       * execute and <i>notifies</i> its thread to do it.
       */
      protected synchronized void executeAndWait( final Runnable work )
      {
          execute( work );
          waitUntilCondition( false );
      }
  
      protected synchronized void waitUntilCondition( final boolean hasWork )
      {
          while( hasWork == (null == m_work) )
          {
              try 
              {
                  if( DEBUG ) m_logger.debug( getName() + ": waiting." );
                  wait(); 
                  if( DEBUG ) m_logger.debug( getName() + ": notified." );
              }
              catch( final InterruptedException ie ) {}
          }
      }
  
      protected synchronized void execute( final Runnable work )
      {
          if( DEBUG ) m_logger.debug( getName() + ": notifying this worker." );
          m_work = work;
          notify();
      }
  
      /**
       * Set the <code>alive</code> variable to false causing the worker to die.
       * If the worker is stalled and a timeout generated this call, this method
       * does not change the state of the worker (that must be destroyed in other
       * ways).
       */
      public void dispose() 
      {
          if( DEBUG ) m_logger.debug( getName() + ": destroying." );
          m_alive = false;
      }
  }