donaldp     01/04/03 16:35:24

  Added:       proposal/4.0/src/java/org/apache/avalon/aut Enum.java
                        StringUtil.java ValuedEnum.java Version.java
               proposal/4.0/src/java/org/apache/avalon/aut/collections
                        ArrayEnumeration.java ArrayStack.java
                        IteratorEnumeration.java ListUtils.java
               proposal/4.0/src/java/org/apache/avalon/aut/i18n
                        ResourceGroup.java XMLResourceBundle.java
                        XMLResourceBundleFactory.java XPathAPI.java
               proposal/4.0/src/java/org/apache/avalon/aut/io
                        DirectoryFileFilter.java ExtensionFileFilter.java
                        FileUtil.java IOUtil.java
               proposal/4.0/src/java/org/apache/avalon/aut/log
                        AvalonLogFormatter.java
               proposal/4.0/src/java/org/apache/avalon/aut/security
                        AbstractPolicy.java PolicyClassLoader.java
               proposal/4.0/src/java/org/apache/avalon/cli
                        AbstractParserControl.java CLArgsParser.java
                        CLOption.java CLOptionDescriptor.java CLUtil.java
                        ParserControl.java
  Removed:     proposal/4.0/src/java/org/apache/aut Enum.java
                        StringUtil.java ValuedEnum.java Version.java
               proposal/4.0/src/java/org/apache/aut/cli
                        AbstractParserControl.java CLArgsParser.java
                        CLOption.java CLOptionDescriptor.java CLUtil.java
                        ParserControl.java
               proposal/4.0/src/java/org/apache/aut/collections
                        ArrayEnumeration.java ArrayStack.java
                        IteratorEnumeration.java ListUtils.java
               proposal/4.0/src/java/org/apache/aut/i18n ResourceGroup.java
                        XMLResourceBundle.java
                        XMLResourceBundleFactory.java XPathAPI.java
               proposal/4.0/src/java/org/apache/aut/io
                        DirectoryFileFilter.java ExtensionFileFilter.java
                        FileUtil.java IOUtil.java
               proposal/4.0/src/java/org/apache/aut/security
                        AbstractPolicy.java PolicyClassLoader.java
               proposal/4.0/src/java/org/apache/log/format
                        AvalonLogFormatter.java
  Log:
  Moved org.apache.aut to org.apache.avalon.aut
  
  Revision  Changes    Path
  1.1                  
jakarta-avalon/proposal/4.0/src/java/org/apache/avalon/aut/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.aut;
  
  import java.util.Map;
  
  /**
   * Basic enum class for type-safe enums. Should be used as an abstract base.
   *
   * @author <a href="mailto:[EMAIL PROTECTED]">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/proposal/4.0/src/java/org/apache/avalon/aut/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.aut;
  
  /**
   * This class provides basic facilities for manipulating strings.
   * 
   * @author <a href="mailto:[EMAIL PROTECTED]">Peter Donald</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();
      }
  }
  
  
  
  1.1                  
jakarta-avalon/proposal/4.0/src/java/org/apache/avalon/aut/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.aut;
  
  /**
   * Basic enum class for type-safe enums with values. Should be used as an abstract 
base.
   *
   * @author <a href="mailto:[EMAIL PROTECTED]">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/proposal/4.0/src/java/org/apache/avalon/aut/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.aut;
  
  /**
   * 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:[EMAIL PROTECTED]">Federico Barbieri</a>
   * @author <a href="mailto:[EMAIL PROTECTED]">Pierpaolo Fumagalli</a>
   * @author <a href="mailto:[EMAIL PROTECTED]">Stefano Mazzocchi</a>
   * @author <a href="mailto:[EMAIL PROTECTED]">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/proposal/4.0/src/java/org/apache/avalon/aut/collections/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.aut.collections;
  
  import java.util.Enumeration;
  import java.util.List;
  import java.util.NoSuchElementException;
  
  /**
   * Enumeration wrapper for array.
   *
   * @author <a href="mailto:[EMAIL PROTECTED]">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/proposal/4.0/src/java/org/apache/avalon/aut/collections/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.aut.collections;
  
  import java.util.ArrayList;
  import java.util.EmptyStackException;
  
  /**
   * Unsynchronized stakc.
   *
   * @author <a href="mailto:[EMAIL PROTECTED]">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/proposal/4.0/src/java/org/apache/avalon/aut/collections/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.aut.collections;
  
  import java.util.Enumeration;
  import java.util.Iterator;
  import java.util.NoSuchElementException;
  
  /**
   * Enumeration wrapper for iterator.
   *
   * @author <a href="mailto:[EMAIL PROTECTED]">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/proposal/4.0/src/java/org/apache/avalon/aut/collections/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.aut.collections;
  
  import java.util.ArrayList;
  import java.util.Iterator;
  import java.util.List;
  
  /**
   * Miscelaneous utilities to manipulate Lists.
   *
   * @author  <a href="mailto:[EMAIL PROTECTED]">Federico Barbieri</a>
   * @author  <a href="mailto:[EMAIL PROTECTED]">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/proposal/4.0/src/java/org/apache/avalon/aut/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.aut.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/proposal/4.0/src/java/org/apache/avalon/aut/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.aut.i18n;
  
  import java.io.IOException;
  import java.lang.ref.SoftReference;
  import java.util.Hashtable;
  import java.util.Locale;
  import java.util.MissingResourceException;
  import org.apache.xalan.xpath.XObject;
  import org.apache.xalan.xpath.XPath;
  import org.apache.xalan.xpath.XPathProcessorImpl;
  import org.apache.xalan.xpath.XPathSupport;
  import org.apache.xalan.xpath.xml.PrefixResolverDefault;
  import org.apache.xalan.xpath.xml.XMLParserLiaisonDefault;
  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;
  
  /**
   * @author <a href="mailto:[EMAIL PROTECTED]">Mike Engelhart</a>
   * @author <a href="mailto:[EMAIL PROTECTED]">Neeme Praks</a>
   * @author <a href="mailto:[EMAIL PROTECTED]">Oleg Podolsky</a>
   * @version $Id: XMLResourceBundle.java,v 1.1 2001/04/03 23:35:22 donaldp Exp $
   */
  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/proposal/4.0/src/java/org/apache/avalon/aut/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.aut.i18n;
  
  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;
  
  /**
   * @author <a href="mailto:[EMAIL PROTECTED]">Mike Engelhart</a>
   * @author <a href="mailto:[EMAIL PROTECTED]">Neeme Praks</a>
   * @author <a href="mailto:[EMAIL PROTECTED]">Oleg Podolsky</a>
   * @version $Id: XMLResourceBundleFactory.java,v 1.1 2001/04/03 23:35:22 donaldp Exp 
$
    */
  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/proposal/4.0/src/java/org/apache/avalon/aut/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.aut.i18n;
  
  import org.apache.xalan.xpath.XObject;
  import org.apache.xalan.xpath.XPath;
  import org.apache.xalan.xpath.XPathProcessorImpl;
  import org.apache.xalan.xpath.XPathSupport;
  import org.apache.xalan.xpath.xml.PrefixResolverDefault;
  import org.apache.xalan.xpath.xml.XMLParserLiaisonDefault;
  import org.w3c.dom.Document;
  import org.w3c.dom.Node;
  import org.w3c.dom.NodeList;
  import org.xml.sax.SAXException;
  
  /**
   * 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:[EMAIL PROTECTED]">Mike Engelhart</a>
   * @see http://www.w3.org/TR/xpath
   * @version $Id: XPathAPI.java,v 1.1 2001/04/03 23:35:22 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/proposal/4.0/src/java/org/apache/avalon/aut/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.aut.io;
  
  import java.io.File;
  import java.io.FilenameFilter;
  
  /**
   * This filters files based if not a directory.
   *
   * @author <a href="mailto:[EMAIL PROTECTED]">Peter Donald</a>
   */
  public class DirectoryFileFilter 
      implements FilenameFilter
  {
      public boolean accept( final File file, final String name ) 
      {
          return file.isDirectory();
      }
  }
  
      
  
  
  
  1.1                  
jakarta-avalon/proposal/4.0/src/java/org/apache/avalon/aut/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.aut.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 <[EMAIL PROTECTED]>
   * @author Serge Knystautas <[EMAIL PROTECTED]>
   * @author <a href="mailto:[EMAIL PROTECTED]">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/proposal/4.0/src/java/org/apache/avalon/aut/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.aut.io;
  
  import java.io.*;
  import java.net.URL;
  import org.apache.aut.StringUtil;
  
  /**
   * This class provides basic facilities for manipulating files.
   *
   * @author <a href="mailto:[EMAIL PROTECTED]">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/proposal/4.0/src/java/org/apache/avalon/aut/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.aut.io;
  
  import java.io.*;
  
  /**
   * This class provides basic facilities for manipulating io streams.
   *
   * @author <a href="mailto:[EMAIL PROTECTED]">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/proposal/4.0/src/java/org/apache/avalon/aut/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.aut.log;
  
  import java.util.Date;
  import org.apache.framework.ExceptionUtil;
  import org.apache.log.format.PatternFormatter;
  
  /**
   * Specialized formatter that knows about CascadingThrowables.
   *
   * @author <a href="mailto:[EMAIL PROTECTED]">Peter Donald</a>
   */
  public class AvalonLogFormatter 
      extends PatternFormatter
  {
      protected String getStackTrace( final Throwable throwable, final String format )
      {
          if( null == throwable ) return "";
          return ExceptionUtil.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/proposal/4.0/src/java/org/apache/avalon/aut/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.aut.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.aut.io.FileUtil;
  import org.apache.framework.component.Component;
  import org.apache.framework.logger.Loggable;
  import org.apache.log.Logger;
  
  /**
   * Abstract policy extended in avalon.
   * 
   * @author <a href="mailto:[EMAIL PROTECTED]">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/proposal/4.0/src/java/org/apache/avalon/aut/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.aut.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:[EMAIL PROTECTED]">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/proposal/4.0/src/java/org/apache/avalon/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.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:[EMAIL PROTECTED]">Peter Donald</a>
   */
  public class AbstractParserControl 
      implements ParserControl
  {
      public boolean isFinished( int lastOptionCode )
      {
          return false;
      }
  }
  
  
  
  1.1                  
jakarta-avalon/proposal/4.0/src/java/org/apache/avalon/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.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:[EMAIL PROTECTED]">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/proposal/4.0/src/java/org/apache/avalon/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.cli;
  
  import java.util.Arrays;
  
  /**
   * Basic class describing an instance of option.
   *
   * @author <a href="mailto:[EMAIL PROTECTED]">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/proposal/4.0/src/java/org/apache/avalon/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.cli;
  
  /**
   * Basic class describing an type of option.
   *
   * @author <a href="mailto:[EMAIL PROTECTED]">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/proposal/4.0/src/java/org/apache/avalon/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.cli;
  
  /**
   * CLUtil offers basic utility operations for use both internal and external to 
package.
   *
   * @author <a href="mailto:[EMAIL PROTECTED]">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/proposal/4.0/src/java/org/apache/avalon/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.cli;
  
  /**
   * ParserControl is used to control particular behaviour of the parser.
   *
   * @author <a href="mailto:[EMAIL PROTECTED]">Peter Donald</a>
   */
  public interface ParserControl
  {
      boolean isFinished( int lastOptionCode );
  }
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to