You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@avalon.apache.org by cz...@apache.org on 2002/04/19 11:05:38 UTC

cvs commit: jakarta-avalon-excalibur/all/src/scratchpad/org/apache/avalon/excalibur/source/validity AggregatedValidity.java NOPValidity.java TimeStampValidity.java

cziegeler    02/04/19 02:05:38

  Added:       all/src/java/org/apache/avalon/excalibur/monitor
                        Monitorable.java SourceResource.java
               all/src/java/org/apache/excalibur/source Source.java
                        SourceFactory.java SourceParameters.java
                        SourceResolver.java SourceUtil.java
                        SourceValidity.java
               all/src/java/org/apache/excalibur/source/impl
                        ResourceSource.java ResourceSourceFactory.java
                        SourceResolverImpl.java URLSource.java
               all/src/java/org/apache/excalibur/source/impl/validity
                        AggregatedValidity.java NOPValidity.java
                        TimeStampValidity.java
  Removed:     all/src/scratchpad/org/apache/avalon/excalibur/monitor
                        Monitorable.java SourceResource.java
               all/src/scratchpad/org/apache/avalon/excalibur/source
                        ResourceSource.java ResourceSourceFactory.java
                        Source.java SourceFactory.java
                        SourceParameters.java SourceResolver.java
                        SourceResolverImpl.java SourceUtil.java
                        SourceValidity.java URLSource.java
               all/src/scratchpad/org/apache/avalon/excalibur/source/validity
                        AggregatedValidity.java NOPValidity.java
                        TimeStampValidity.java
  Log:
  Moving things from scratchpad
  
  Revision  Changes    Path
  1.1                  jakarta-avalon-excalibur/all/src/java/org/apache/avalon/excalibur/monitor/Monitorable.java
  
  Index: Monitorable.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.txt file.
   */
  package org.apache.avalon.excalibur.monitor;
  
  /**
   * Describes an object which can be monitored.
   *
   * @author <a href="mailto:cziegeler@apache.org">Carsten Ziegeler</a>
   */
  public interface Monitorable
  {
  
      /**
       *  Get the corresponding Resource object for monitoring.
       */
      Resource getResource()
          throws Exception;
  }
  
  
  
  1.1                  jakarta-avalon-excalibur/all/src/java/org/apache/avalon/excalibur/monitor/SourceResource.java
  
  Index: SourceResource.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.txt file.
   */
  package org.apache.avalon.excalibur.monitor;
  
  import java.io.IOException;
  import java.io.InputStream;
  import java.io.InputStreamReader;
  import java.io.OutputStream;
  import java.io.Reader;
  import java.io.Writer;
  import org.apache.excalibur.source.Source;
  import org.apache.excalibur.source.SourceValidity;
  
  /**
   *
   * @author <a href="mailto:cziegeler@apache.org">Carsten Ziegeler</a>
   * @version $Id: SourceResource.java,v 1.1 2002/04/19 09:05:37 cziegeler Exp $
   */
  public final class SourceResource extends StreamResource
  {
      /** The wrapped source object */
      private final Source source;
  
      /** The last validity object */
      private SourceValidity validity;
  
      /**
       * Instantiate the SourceResource
       */
      public SourceResource( Source source )
          throws Exception
      {
          super( source.getSystemId() );
  
          this.source = source;
          m_previousModified = System.currentTimeMillis();
          this.validity = source.getValidity();
      }
  
      /**
       * Determines the last time this resource was modified
       */
      public long lastModified()
      {
          if( this.validity == null )
          {
              return System.currentTimeMillis();
          }
          else
          {
              SourceValidity newVal = this.source.getValidity();
              if( newVal != null && this.validity.isValid( newVal ) == true )
              {
                  return m_previousModified;
              }
              else
              {
                  this.validity = newVal;
                  return System.currentTimeMillis();
              }
          }
      }
  
      /**
       * Sets the resource value with an OutputStream
       */
      public InputStream getResourceAsStream() throws IOException
      {
          return this.source.getInputStream();
      }
  
      /**
       * Sets the resource value with a Writer
       */
      public Reader getResourceAsReader() throws IOException
      {
          return new InputStreamReader( this.getResourceAsStream() );
      }
  
      /**
       * Sets the resource value with an OutputStream
       */
      public OutputStream setResourceAsStream() throws IOException
      {
          throw new IOException( "setResourceAsStream() not supported for URLResource" );
      }
  
      /**
       * Sets the resource value with a Writer
       */
      public Writer setResourceAsWriter() throws IOException
      {
          throw new IOException( "setResourceAsWriter() not supported for URLResource" );
      }
  }
  
  
  
  1.1                  jakarta-avalon-excalibur/all/src/java/org/apache/excalibur/source/Source.java
  
  Index: Source.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.txt file.
   */
  package org.apache.excalibur.source;
  
  import java.io.IOException;
  import java.io.InputStream;
  
  /**
   * Description of a source. This interface provides a simple interface
   * for accessing a source of data.
   *
   * When the <code>Source</code> object is no longer needed
   * it must be released using the resolver. This is very similar like
   * looking up components from a <code>ComponentManager</code>.
   * In fact a source object can implement most lifecycle interfaces
   * like Composable, Initializable, Disposable etc.
   *
   * Thee data content can be constant or change over time.
   * Using the getInputStream() method you get always the upto-date content.
   * When you're done with using the source object, you have to release it.
   * If you want to track changes of the source object, this interface
   * offers you some support for it by providing a SourceValidity object.
   *
   * How does the caching work?
   * The first time you get a Source object, you simply ask
   * it for it's content via getInputStream() and then get the validity
   * object by invoking getValidity. (Further calls to getValidity always
   * return the same object! This is not updated!)
   * The caching algorithm can now store this validity object together
   * with the system identifier of the source.
   * The next time, the caching algorithm wants to check if the cached
   * content is still valid. It has a validity object already to check
   * against.
   *
   * If it is still the same Source than the first time, you
   * have to call discardValidity() in order to discard the stored validity
   * in the Source object. If it is a new Source object,
   * calling discardValidity() should do no harm.
   * After that an upto-date validity object can retrieved by calling
   * getValidity(). This can be used to test if the content is still valid
   * as discribed in the source validity documentation.
   * If the content is still valid, the cache knows what to do, if not,
   * the new content can be get using getInputStream().
   * So either after a call to getValidity() or the getInputStream the
   * validity object must be the same until discardValidity is called!
   *
   * @author <a href="mailto:cziegeler@apache.org">Carsten Ziegeler</a>
   * @version CVS $Revision: 1.1 $ $Date: 2002/04/19 09:05:37 $
   */
  public interface Source {
  
      /**
       * Return an <code>InputStream</code> object to read from the source.
       * This is the data at the point of invocation of this method,
       * so if this is an {@link ModifiableSource} object, you might get
       * different content from two invocations.
       */
      InputStream getInputStream()
          throws IOException;
  
      /**
       * Return the unique identifer for this source
       */
      String getSystemId();
  
      /**
       *  Get the Validity object. This can either wrap the last modification
       *  date or the expires information or...
       *  If it is currently not possible to calculate such an information
       *  <code>null</code> is returned.
       */
      SourceValidity getValidity();
  
      /**
       * Refresh the content of this object after the underlying data
       * content has changed.
       */
      void discardValidity();
  
      /**
       * The mime-type of the content described by this object.
       * If the source is not able to determine the mime-type by itself
       * this can be null.
       */
       String getMimeType();
  }
  
  
  
  1.1                  jakarta-avalon-excalibur/all/src/java/org/apache/excalibur/source/SourceFactory.java
  
  Index: SourceFactory.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.txt file.
   */
  package org.apache.excalibur.source;
  
  import java.io.IOException;
  import java.net.MalformedURLException;
  import java.util.Map;
  import org.apache.avalon.framework.component.Component;
  
  /**
   * @author <a href="mailto:cziegeler@apache.org">Carsten Ziegeler</a>
   * @version $Id: SourceFactory.java,v 1.1 2002/04/19 09:05:37 cziegeler Exp $
   */
  public interface SourceFactory
      extends Component
  {
  
      String ROLE = SourceFactory.class.getName();
  
      /**
       * Get a <code>Source</code> object.
       * @param parameters This is optional.
       */
      Source getSource( String location, Map parameters )
          throws MalformedURLException, IOException;
  
  }
  
  
  
  1.1                  jakarta-avalon-excalibur/all/src/java/org/apache/excalibur/source/SourceParameters.java
  
  Index: SourceParameters.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.txt file.
   */
  package org.apache.excalibur.source;
  
  import java.io.Serializable;
  import java.util.ArrayList;
  import java.util.HashMap;
  import java.util.Iterator;
  import java.util.Map;
  import java.util.StringTokenizer;
  import org.apache.avalon.framework.configuration.Configuration;
  import org.apache.avalon.framework.configuration.ConfigurationException;
  import org.apache.avalon.framework.parameters.Parameters;
  
  /**
   * This class holds parameters for a <code>Source</code> object.
   * It differs from the usual Parameters object because it can hold
   * more than one value for a parameter.
   *
   * @author <a href="mailto:cziegeler@apache.org">Carsten Ziegeler</a>
   * @version $Id: SourceParameters.java,v 1.1 2002/04/19 09:05:37 cziegeler Exp $
   */
  public final class SourceParameters
      implements Serializable, Cloneable
  {
  
      /** The parameter names are the keys and the value is a List object */
      private Map names = new HashMap( 5 );
  
      /**
       * Decode the string
       */
      private String parseName( String s )
      {
          StringBuffer sb = new StringBuffer();
          for( int i = 0; i < s.length(); i++ )
          {
              char c = s.charAt( i );
              switch( c )
              {
                  case '+':
                      sb.append( ' ' );
                      break;
                  case '%':
                      try
                      {
                          sb.append( (char)Integer.parseInt( s.substring( i + 1, i + 3 ),
                                                             16 ) );
                          i += 2;
                      }
                      catch( NumberFormatException e )
                      {
                          throw new IllegalArgumentException();
                      }
                      catch( StringIndexOutOfBoundsException e )
                      {
                          String rest = s.substring( i );
                          sb.append( rest );
                          if( rest.length() == 2 )
                              i++;
                      }
  
                      break;
                  default:
                      sb.append( c );
                      break;
              }
          }
          return sb.toString();
      }
  
      /**
       * Create a new parameters object from the
       * children of the configuration.
       * If no children are available <code>null</code>
       * is returned.
       */
      public static SourceParameters create( Configuration conf )
      {
          Configuration[] children = conf.getChildren();
          if( children != null && children.length > 0 )
          {
              SourceParameters pars = new SourceParameters();
              String name;
              String value;
              for( int i = 0; i < children.length; i++ )
              {
                  name = children[ i ].getName();
                  try
                  {
                      value = children[ i ].getValue();
                  }
                  catch( ConfigurationException local )
                  {
                      value = ""; // ignore exception
                  }
                  pars.setParameter( name, value );
              }
              return pars;
          }
          return null;
      }
  
      /**
       * Standard Constructor creating an empty parameters object
       */
      public SourceParameters()
      {
      }
  
      /**
       * Construct a new object from a queryString
       */
      public SourceParameters( String queryString )
      {
          if( queryString != null )
          {
              StringTokenizer st = new StringTokenizer( queryString, "&" );
              while( st.hasMoreTokens() )
              {
                  String pair = (String)st.nextToken();
                  int pos = pair.indexOf( '=' );
                  if( pos != -1 )
                  {
                      this.setParameter( this.parseName( pair.substring( 0, pos ) ),
                                         this.parseName( pair.substring( pos + 1, pair.length() ) ) );
                  }
              }
          }
      }
  
      /**
       * Add a parameter.
       * The parameter is added with the given value.
       * @param name   The name of the parameter.
       * @param value  The value of the parameter.
       */
      public void setParameter( String name, String value )
      {
          ArrayList list;
          if( names.containsKey( name ) == true )
          {
              list = (ArrayList)names.get( name );
          }
          else
          {
              list = new ArrayList( 3 );
              names.put( name, list );
          }
          list.add( value );
      }
  
      /**
       * Get the value of a parameter.
       * @param name   The name of the parameter.
       * @return       The value of the first parameter with the name
       *               or <CODE>null</CODE>
       */
      public String getParameter( String name )
      {
          if( names.containsKey( name ) == true )
          {
              return (String)( (ArrayList)names.get( name ) ).get( 0 );
          }
          return null;
      }
  
      /**
       * Get the value of a parameter.
       * @param name   The name of the parameter.
       * @param defaultValue The default value if the parameter does not exist.
       * @return       The value of the first parameter with the name
       *               or <CODE>defaultValue</CODE>
       */
      public String getParameter( String name, String defaultValue )
      {
          if( names.containsKey( name ) == true )
          {
              return (String)( (ArrayList)names.get( name ) ).get( 0 );
          }
          return defaultValue;
      }
  
      /**
       * Get the integer value of a parameter.
       * @param name   The name of the parameter.
       * @param defaultValue The default value if the parameter does not exist.
       * @return       The value of the first parameter with the name
       *               or <CODE>defaultValue</CODE>
       */
      public int getParameterAsInteger( String name, int defaultValue )
      {
          if( names.containsKey( name ) == true )
          {
              return new Integer( (String)( (ArrayList)names.get( name ) ).get( 0 ) ).intValue();
          }
          return defaultValue;
      }
  
      /**
       * Get the boolean value of a parameter.
       * @param name   The name of the parameter.
       * @param defaultValue The default value if the parameter does not exist.
       * @return       The value of the first parameter with the name
       *               or <CODE>defaultValue</CODE>
       */
      public boolean getParameterAsBoolean( String name, boolean defaultValue )
      {
          if( names.containsKey( name ) == true )
          {
              return new Boolean( (String)( (ArrayList)names.get( name ) ).get( 0 ) ).booleanValue();
          }
          return defaultValue;
      }
  
      /**
       * Test if a value for this parameter exists.
       * @param name   The name of the parameter.
       * @return       <CODE>true</CODE> if a value exists, otherwise <CODE>false</CODE>
       */
      public boolean containsParameter( String name )
      {
          return names.containsKey( name );
      }
  
      /**
       * Get all values of a parameter.
       * @param name   The name of the parameter.
       * @return       Iterator for the (String) values or null if the parameter
       *               is not defined.
       */
      public Iterator getParameterValues( String name )
      {
          if( names.containsKey( name ) == true )
          {
              ArrayList list = (ArrayList)names.get( name );
              return list.iterator();
          }
          return null;
      }
  
      /**
       * Get all parameter names.
       * @return  Iterator for the (String) parameter names.
       */
      public Iterator getParameterNames()
      {
          return names.keySet().iterator();
      }
  
      /**
       * Create a Parameters object.
       * The first value of each parameter is added to the Parameters object.
       * @return An Parameters object - if no parameters are defined this is an
       *         empty object.
       */
      public Parameters getFirstParameters()
      {
          Parameters result = new Parameters();
          Iterator iter = this.getParameterNames();
          String parName;
          while( iter.hasNext() )
          {
              parName = (String)iter.next();
              result.setParameter( parName, this.getParameter( parName ) );
          }
          return result;
      }
  
      /**
       * Build a query string.
       * The query string can e.g. be used for http connections.
       * @return A query string which contains for each parameter/value pair
       *         a part, like "parameter=value" separated by "&".
       *         If no parameter is defined <CODE>null</CODE> is returned.
       */
      public String getQueryString()
      {
          StringBuffer result = new StringBuffer();
          Iterator iter = this.names.keySet().iterator();
          Iterator listIterator;
          String key;
          String value;
          boolean first = true;
          while( iter.hasNext() == true )
          {
              key = (String)iter.next();
              listIterator = ( (ArrayList)names.get( key ) ).iterator();
              while( listIterator.hasNext() == true )
              {
                  if( first == false ) result.append( '&' );
                  value = (String)listIterator.next();
                  result.append( key ).append( '=' ).append( value );
                  first = false;
              }
          }
          return ( result.length() == 0 ? null : result.toString() );
      }
  
      /**
       * Build a query string and encode each parameter value.
       * The query string can e.g. be used for http connections.
       * @return A query string which contains for each parameter/value pair
       *         a part, like "parameter=value" separated by "&".
       *         If no parameter is defined <CODE>null</CODE> is returned.
       */
      public String getEncodedQueryString()
      {
          StringBuffer result = new StringBuffer();
          Iterator iter = this.names.keySet().iterator();
          Iterator listIterator;
          String key;
          String value;
          boolean first = true;
          while( iter.hasNext() == true )
          {
              key = (String)iter.next();
              listIterator = ( (ArrayList)names.get( key ) ).iterator();
              while( listIterator.hasNext() == true )
              {
                  if( first == false ) result.append( '&' );
                  value = (String)listIterator.next();
                  result.append( key ).append( '=' ).append( SourceUtil.encode( value ) );
                  first = false;
              }
          }
          return ( result.length() == 0 ? null : result.toString() );
      }
  
      /**
       * Add all parameters from the incoming parameters object.
       */
      public void add( SourceParameters parameters )
      {
          if( null != parameters )
          {
              Iterator names = parameters.getParameterNames();
              Iterator values;
              String name;
              String value;
              while( names.hasNext() == true )
              {
                  name = (String)names.next();
                  values = parameters.getParameterValues( name );
                  while( values.hasNext() == true )
                  {
                      value = (String)values.next();
                      this.setParameter( name, value );
                  }
              }
          }
      }
  
      /**
       * Overriding toString
       */
      public String toString()
      {
          StringBuffer buffer = new StringBuffer( "SourceParameters: {" );
          Iterator names = this.getParameterNames();
          String name;
          boolean firstName = true;
          Iterator values;
          String value;
          boolean firstValue;
          while( names.hasNext() == true )
          {
              name = (String)names.next();
              if( firstName == false )
              {
                  buffer.append( ", " );
              }
              else
              {
                  firstName = false;
              }
              buffer.append( name ).append( " = (" );
              values = this.getParameterValues( name );
              firstValue = true;
              while( values.hasNext() == true )
              {
                  value = (String)values.next();
                  if( firstValue == false )
                  {
                      buffer.append( ", " );
                  }
                  else
                  {
                      firstValue = false;
                  }
                  buffer.append( value );
              }
              buffer.append( ')' );
          }
          buffer.append( '}' );
          return buffer.toString();
      }
  
      /**
       * Returns a copy of the parameters object.
       */
      public Object clone()
      {
          SourceParameters newObject = new SourceParameters();
          Iterator names = this.getParameterNames();
          Iterator values;
          String name, value;
          while( names.hasNext() )
          {
              name = (String)names.next();
              values = this.getParameterValues( name );
              while( values.hasNext() )
              {
                  value = (String)values.next();
                  newObject.setParameter( name, value );
              }
          }
          return newObject;
      }
  
      /**
       * Test if there are any parameters.
       */
      public boolean hasParameters()
      {
          return ( this.names.size() > 0 );
      }
  
      /**
       * Set the value of this parameter to the given value.
       * Remove all other values for this parameter.
       */
      public void setSingleParameterValue( String name, String value )
      {
          this.removeParameter( name );
          this.setParameter( name, value );
      }
  
      /**
       * Remove all values for this parameter
       */
      public void removeParameter( String name )
      {
          if( this.names.containsKey( name ) )
          {
              this.names.remove( name );
          }
      }
  }
  
  
  
  1.1                  jakarta-avalon-excalibur/all/src/java/org/apache/excalibur/source/SourceResolver.java
  
  Index: SourceResolver.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.txt file.
   */
  package org.apache.excalibur.source;
  
  import java.io.IOException;
  import java.net.MalformedURLException;
  import java.util.Map;
  import org.apache.avalon.framework.component.Component;
  import org.apache.avalon.framework.component.ComponentException;
  
  /**
   * Base interface for resolving a source by system identifiers.
   * Instead of using the java.net.URL classes which prevent you
   * from adding your own custom protocols in a server environment,
   * you should use this resolver for all URLs.
   *
   * The resolver creates for each source a <code>Source</code>
   * object, which could then be asked for an <code>InputStream</code>
   * etc.
   *
   * When the <code>Source</code> object is no longer needed
   * it must be released using the resolver. This is very similar like
   * looking up components from a <code>ComponentManager</code>.
   * In fact a source object can implement most lifecycle interfaces
   * like Composable, Initializable, Disposable etc.
   *
   * @author <a href="mailto:cziegeler@apache.org">Carsten Ziegeler</a>
   * @version CVS $Revision: 1.1 $ $Date: 2002/04/19 09:05:37 $
   */
  
  public interface SourceResolver
      extends Component
  {
      String ROLE = SourceResolver.class.getName();
  
      /**
       * Get a <code>Source</code> object.
       * This is a shortcut for <code>resolve(location, null, null)</code>
       */
      Source resolveURI( String location )
          throws MalformedURLException, IOException, ComponentException;
  
      /**
       * Get a <code>Source</code> object.
       * @param location - the URI to resolve. If this is relative it is either
       *                   resolved relative to the base parameter (if not null)
       *                   or relative to a base setting of the source resolver
       *                   itself.
       * @param base - a base URI for resolving relative locations. This
       *               is optional and can be <code>null</code>.
       * @param parameters - Additional parameters for the URI. The parameters
       *                     are specific to the used protocol.
       */
      Source resolveURI( String location,
                         String base,
                         Map parameters )
          throws MalformedURLException, IOException, ComponentException;
  
      /**
       * Releases a resolved resource
       */
      void release( Source source );
  }
  
  
  
  
  1.1                  jakarta-avalon-excalibur/all/src/java/org/apache/excalibur/source/SourceUtil.java
  
  Index: SourceUtil.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.txt file.
   */
  package org.apache.excalibur.source;
  
  import java.io.ByteArrayOutputStream;
  import java.io.File;
  import java.io.IOException;
  import java.io.OutputStreamWriter;
  import java.util.BitSet;
  import java.util.Iterator;
  import org.apache.avalon.framework.parameters.Parameters;
  
  /**
   *
   * Utility class for source resolving.
   *
   * @author <a href="mailto:cziegeler@apache.org">Carsten Ziegeler</a>
   * @version CVS $Revision: 1.1 $ $Date: 2002/04/19 09:05:37 $
   */
  public final class SourceUtil
  {
  
      private static final char[] alphabet = {
          'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', // 0 to 7
          'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', // 8 to 15
          'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', // 16 to 23
          'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', // 24 to 31
          'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', // 32 to 39
          'o', 'p', 'q', 'r', 's', 't', 'u', 'v', // 40 to 47
          'w', 'x', 'y', 'z', '0', '1', '2', '3', // 48 to 55
          '4', '5', '6', '7', '8', '9', '+', '/'}; // 56 to 63
  
      /**
       * Append parameters to the uri.
       * Each parameter is appended to the uri with "parameter=value",
       * the parameters are separated by "&".
       */
      public static String appendParameters( String uri,
                                             Parameters parameters )
      {
          if( parameters != null )
          {
              StringBuffer buffer = new StringBuffer( uri );
              String[] keys = parameters.getNames();
              String current;
              char separator = ( uri.indexOf( "?" ) == -1 ? '?' : '&' );
  
              if( keys != null )
              {
                  for( int i = 0; i < keys.length; i++ )
                  {
                      current = keys[ i ];
                      buffer.append( separator )
                          .append( current )
                          .append( '=' )
                          .append( SourceUtil.encode( parameters.getParameter( current, null ) ) );
                      separator = '&';
                  }
              }
              return buffer.toString();
          }
  
          return uri;
      }
  
      /**
       * Append parameters to the uri
       * Each parameter is appended to the uri with "parameter=value",
       * the parameters are separated by "&".
       */
      public static String appendParameters( String uri,
                                             SourceParameters parameters )
      {
          if( parameters != null )
          {
              StringBuffer buffer = new StringBuffer( uri );
              Iterator keys = parameters.getParameterNames();
              String current;
              char separator = ( uri.indexOf( "?" ) == -1 ? '?' : '&' );
              Iterator values;
  
              while( keys.hasNext() == true )
              {
                  current = (String)keys.next();
                  values = parameters.getParameterValues( current );
                  while( values.hasNext() == true )
                  {
                      buffer.append( separator )
                          .append( current )
                          .append( '=' )
                          .append( SourceUtil.encode( (String)values.next() ) );
                      separator = '&';
                  }
              }
              return buffer.toString();
          }
  
          return uri;
      }
  
      /**
       * BASE 64 encoding.
       * See also RFC 1421
       */
      public static String encodeBASE64( String s )
      {
          return encodeBASE64( s.getBytes() );
      }
  
      /**
       * BASE 64 encoding.
       * See also RFC 1421
       */
      public static String encodeBASE64( byte[] octetString )
      {
          int bits24;
          int bits6;
  
          char[] out = new char[ ( ( octetString.length - 1 ) / 3 + 1 ) * 4 ];
  
          int outIndex = 0;
          int i = 0;
  
          while( ( i + 3 ) <= octetString.length )
          {
              // store the octets
              bits24 = ( octetString[ i++ ] & 0xFF ) << 16;
              bits24 |= ( octetString[ i++ ] & 0xFF ) << 8;
              bits24 |= ( octetString[ i++ ] & 0xFF ) << 0;
  
              bits6 = ( bits24 & 0x00FC0000 ) >> 18;
              out[ outIndex++ ] = alphabet[ bits6 ];
              bits6 = ( bits24 & 0x0003F000 ) >> 12;
              out[ outIndex++ ] = alphabet[ bits6 ];
              bits6 = ( bits24 & 0x00000FC0 ) >> 6;
              out[ outIndex++ ] = alphabet[ bits6 ];
              bits6 = ( bits24 & 0x0000003F );
              out[ outIndex++ ] = alphabet[ bits6 ];
          }
  
          if( octetString.length - i == 2 )
          {
              // store the octets
              bits24 = ( octetString[ i ] & 0xFF ) << 16;
              bits24 |= ( octetString[ i + 1 ] & 0xFF ) << 8;
  
              bits6 = ( bits24 & 0x00FC0000 ) >> 18;
              out[ outIndex++ ] = alphabet[ bits6 ];
              bits6 = ( bits24 & 0x0003F000 ) >> 12;
              out[ outIndex++ ] = alphabet[ bits6 ];
              bits6 = ( bits24 & 0x00000FC0 ) >> 6;
              out[ outIndex++ ] = alphabet[ bits6 ];
  
              // padding
              out[ outIndex++ ] = '=';
          }
          else if( octetString.length - i == 1 )
          {
              // store the octets
              bits24 = ( octetString[ i ] & 0xFF ) << 16;
  
              bits6 = ( bits24 & 0x00FC0000 ) >> 18;
              out[ outIndex++ ] = alphabet[ bits6 ];
              bits6 = ( bits24 & 0x0003F000 ) >> 12;
              out[ outIndex++ ] = alphabet[ bits6 ];
  
              // padding
              out[ outIndex++ ] = '=';
              out[ outIndex++ ] = '=';
          }
  
          return new String( out );
      }
  
      /** A BitSet defining the characters which don't need encoding */
      static BitSet charactersDontNeedingEncoding;
      static final int characterCaseDiff = ( 'a' - 'A' );
  
      /** Initialize the BitSet */
      static
      {
          charactersDontNeedingEncoding = new BitSet( 256 );
          int i;
          for( i = 'a'; i <= 'z'; i++ )
          {
              charactersDontNeedingEncoding.set( i );
          }
          for( i = 'A'; i <= 'Z'; i++ )
          {
              charactersDontNeedingEncoding.set( i );
          }
          for( i = '0'; i <= '9'; i++ )
          {
              charactersDontNeedingEncoding.set( i );
          }
          charactersDontNeedingEncoding.set( '-' );
          charactersDontNeedingEncoding.set( '_' );
          charactersDontNeedingEncoding.set( '.' );
          charactersDontNeedingEncoding.set( '*' );
          charactersDontNeedingEncoding.set( '"' );
      }
  
      /**
       * Translates a string into <code>x-www-form-urlencoded</code> format.
       *
       * @param   s   <code>String</code> to be translated.
       * @return  the translated <code>String</code>.
       */
      public static String encode( String s )
      {
          final StringBuffer out = new StringBuffer( s.length() );
          final ByteArrayOutputStream buf = new ByteArrayOutputStream( 32 );
          final OutputStreamWriter writer = new OutputStreamWriter( buf );
          for( int i = 0; i < s.length(); i++ )
          {
              int c = (int)s.charAt( i );
              if( charactersDontNeedingEncoding.get( c ) )
              {
                  out.append( (char)c );
              }
              else
              {
                  try
                  {
                      writer.write( c );
                      writer.flush();
                  }
                  catch( IOException e )
                  {
                      buf.reset();
                      continue;
                  }
                  byte[] ba = buf.toByteArray();
                  for( int j = 0; j < ba.length; j++ )
                  {
                      out.append( '%' );
                      char ch = Character.forDigit( ( ba[ j ] >> 4 ) & 0xF, 16 );
                      // converting to use uppercase letter as part of
                      // the hex value if ch is a letter.
                      if( Character.isLetter( ch ) )
                      {
                          ch -= characterCaseDiff;
                      }
                      out.append( ch );
                      ch = Character.forDigit( ba[ j ] & 0xF, 16 );
                      if( Character.isLetter( ch ) )
                      {
                          ch -= characterCaseDiff;
                      }
                      out.append( ch );
                  }
                  buf.reset();
              }
          }
  
          return out.toString();
      }
  
      /**
       * Return a <code>File</code> object associated with the <code>Source</code> object.
       *
       * @return The corresponding <code>File</code> object or null if the
       *         <code>Source</code> object does not point to a file URI.
       */
      public static File getFile( Source source )
      {
          final String systemId = source.getSystemId();
          if( systemId.startsWith( "file:" ) )
          {
              return new File( systemId.substring( 5 ) );
          }
          return null;
      }
  
  }
  
  
  
  1.1                  jakarta-avalon-excalibur/all/src/java/org/apache/excalibur/source/SourceValidity.java
  
  Index: SourceValidity.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.txt file.
   */
  package org.apache.excalibur.source;
  
  /**
   * A Validity object contains all information to check if a Source object is
   * still valid.
   * There are two possibilities: The validity object has all information
   * to check by itself how long it is valid (e.g. given an expires date).
   * The other possibility needs another (newer) validity object to compare
   * against (e.g. to test a last modification date).
   * To avoid testing, what the actual implementation of the validity object
   * supports, the invocation order is to first call isValid() and only if
   * this results in <code>false</code>, then to call isValid(SourceValidity).
   * But remember to call the second isValid(SourceValidity) when <code>false</code>
   * is returned by the first invocation!
   *
   * @author <a href="mailto:cziegeler@apache.org">Carsten Ziegeler</a>
   * @version CVS $Revision: 1.1 $ $Date: 2002/04/19 09:05:37 $
   */
  public interface SourceValidity
      extends java.io.Serializable
  {
  
      /**
       * Check if the component is still valid.
       * If <code>false</code> is returned the isValid(SourceValidity) must be
       * called afterwards!
       */
      boolean isValid();
  
      /**
       * Check if the component is still valid.
       * This is only true, if the incoming Validity is of the same
       * type and has the same values.
       * The invocation order is that the isValid method of the
       * old Validity object is called with the new one as a parameter
       */
      boolean isValid( SourceValidity newValidity );
  }
  
  
  
  1.1                  jakarta-avalon-excalibur/all/src/java/org/apache/excalibur/source/impl/ResourceSource.java
  
  Index: ResourceSource.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.txt file.
   */
  package org.apache.excalibur.source.impl;
  
  import java.io.IOException;
  import java.io.InputStream;
  import org.apache.excalibur.source.*;
  import org.apache.excalibur.source.impl.validity.NOPValidity;
  
  /**
   * Description of a source which is described by the resource protocol
   * which gets a resource from the classloader.
   *
   * @author <a href="mailto:cziegeler@apache.org">Carsten Ziegeler</a>
   * @version CVS $Revision: 1.1 $ $Date: 2002/04/19 09:05:37 $
   */
  
  public final class ResourceSource
      implements Source
  {
      /** The system identifier */
      private String systemId;
  
      /** Location of the resource */
      private String location;
  
      /**
       * Constructor
       */
      public ResourceSource( String systemId )
      {
          this.systemId = systemId;
          final int pos = systemId.indexOf( "://" );
          this.location = systemId.substring( pos + 3 );
      }
  
      /**
       * Return an <code>InputStream</code> object to read from the source.
       */
      public InputStream getInputStream()
          throws IOException
      {
          ClassLoader loader = Thread.currentThread().getContextClassLoader();
          if( loader == null )
          {
              loader = this.getClass().getClassLoader();
          }
          return loader.getResourceAsStream( this.location );
      }
  
      /**
       * Return the unique identifer for this source
       */
      public String getSystemId()
      {
          return this.systemId;
      }
  
      /**
       *  Get the Validity object. This can either wrap the last modification
       *  date or the expires information or...
       *  If it is currently not possible to calculate such an information
       *  <code>null</code> is returned.
       */
      public SourceValidity getValidity()
      {
          // we are always valid
          return NOPValidity.SHARED_INSTANCE;
      }
  
      /**
       * Refresh this object and update the last modified date
       * and content length.
       */
      public void discardValidity()
      {
          // nothing to do
      }
  
      /**
       * The mime-type of the content described by this object.
       * If the source is not able to determine the mime-type by itself
       * this can be null.
       */
      public String getMimeType()
      {
          // FIXME
          return null;
      }
  
  }
  
  
  
  1.1                  jakarta-avalon-excalibur/all/src/java/org/apache/excalibur/source/impl/ResourceSourceFactory.java
  
  Index: ResourceSourceFactory.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.txt file.
   */
  package org.apache.excalibur.source.impl;
  
  import java.io.IOException;
  import java.net.MalformedURLException;
  import java.util.Map;
  import org.apache.avalon.framework.logger.AbstractLogEnabled;
  import org.apache.avalon.framework.thread.ThreadSafe;
  import org.apache.excalibur.source.*;
  
  /**
   * A factory for the Resource protocol
   * @author <a href="mailto:cziegeler@apache.org">Carsten Ziegeler</a>
   * @version $Id: ResourceSourceFactory.java,v 1.1 2002/04/19 09:05:37 cziegeler Exp $
   */
  public class ResourceSourceFactory
      extends AbstractLogEnabled
      implements SourceFactory, ThreadSafe
  {
  
      /**
       * Get a <code>Source</code> object.
       * @param parameters This is optional.
       */
      public Source getSource( String location, Map parameters )
          throws MalformedURLException, IOException
      {
          if( this.getLogger().isDebugEnabled() )
          {
              this.getLogger().debug( "Creating source object for " + location );
          }
          return new ResourceSource( location );
      }
  
  }
  
  
  
  1.1                  jakarta-avalon-excalibur/all/src/java/org/apache/excalibur/source/impl/SourceResolverImpl.java
  
  Index: SourceResolverImpl.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.txt file.
   */
  package org.apache.excalibur.source.impl;
  
  import java.io.File;
  import java.io.IOException;
  import java.net.MalformedURLException;
  import java.net.URL;
  import java.util.Map;
  import org.apache.avalon.excalibur.pool.Recyclable;
  
  import org.apache.avalon.framework.activity.Disposable;
  import org.apache.avalon.framework.component.ComponentException;
  import org.apache.avalon.framework.component.ComponentManager;
  import org.apache.avalon.framework.component.ComponentSelector;
  import org.apache.avalon.framework.component.Composable;
  import org.apache.avalon.framework.context.Context;
  import org.apache.avalon.framework.context.ContextException;
  import org.apache.avalon.framework.context.Contextualizable;
  import org.apache.avalon.framework.logger.AbstractLogEnabled;
  import org.apache.avalon.framework.logger.LogEnabled;
  import org.apache.avalon.framework.thread.ThreadSafe;
  import org.apache.excalibur.source.*;
  
  /**
   * Base interface for resolving a source by system identifiers.
   * Instead of using the java.net.URL classes which prevent you
   * to add your own custom protocols in a server environment,
   * you should use this resolver for all URLs.
   *
   * The resolver creates for each source a <code>Source</code>
   * object, which could then be asked for an <code>InputStream</code>
   * etc.
   *
   * When the <code>Source</code> object is no longer needed
   * it must be released using the resolver. This is very similar like
   * looking up components from a <code>ComponentManager</code>
   * and releasing them.
   *
   * It looks for the base URL in the <code>Context</code> object with
   * the "container.rootDir" entry.  If the entry does not exist, it is
   * populated with the system property "user.dir".
   *
   * @author <a href="mailto:cziegeler@apache.org">Carsten Ziegeler</a>
   * @author <a href="mailto:bloritsch@apache.org">Berin Loritsch</a>
   * @version $Id: SourceResolverImpl.java,v 1.1 2002/04/19 09:05:37 cziegeler Exp $
   */
  public class SourceResolverImpl
      extends AbstractLogEnabled
      implements Composable,
      Contextualizable,
      Disposable,
      SourceResolver,
      ThreadSafe
  {
  
      /** The component manager */
      protected ComponentManager m_manager;
  
      /** The special Source factories */
      protected ComponentSelector m_factorySelector;
  
      /** The context */
      protected Context m_context;
  
      /**
       * The base URL
       */
      protected URL m_baseURL;
  
      /**
       * Get the context
       */
      public void contextualize( Context context )
          throws ContextException
      {
          m_context = context;
  
          try
          {
              m_baseURL = ( (File)m_context.get( "context-root" ) ).toURL();
          }
          catch( ContextException ce )
          {
              // set the base URL to the current directory
              try
              {
                  m_baseURL = new File( System.getProperty( "user.dir" ) ).toURL();
                  if( this.getLogger().isDebugEnabled() )
                  {
                      this.getLogger().debug( "SourceResolver: Using base URL: " + m_baseURL );
                  }
              }
              catch( MalformedURLException mue )
              {
                  getLogger().warn( "Malformed URL for user.dir, and no container.rootDir exists", mue );
                  throw new ContextException( "Malformed URL for user.dir, and no container.rootDir exists", mue );
              }
          }
          catch( MalformedURLException mue )
          {
              getLogger().warn( "Malformed URL for container.rootDir", mue );
              throw new ContextException( "Malformed URL for container.rootDir", mue );
          }
      }
  
      /**
       * Set the current <code>ComponentManager</code> instance used by this
       * <code>Composable</code>.
       */
      public void compose( ComponentManager manager )
          throws ComponentException
      {
          m_manager = manager;
          m_factorySelector = (ComponentSelector)m_manager.lookup( SourceFactory.ROLE + "Selector" );
      }
  
      /**
       * Dispose
       */
      public void dispose()
      {
          if( m_manager != null )
          {
              m_manager.release( m_factorySelector );
              m_factorySelector = null;
          }
      }
  
      /**
       * Get a <code>Source</code> object.
       */
      public Source resolveURI( String location )
          throws MalformedURLException, IOException, ComponentException
      {
          return this.resolveURI( location, null, null );
      }
  
      /**
       * Get a <code>Source</code> object.
       */
      public Source resolveURI( String location,
                                String baseURI,
                                Map parameters )
          throws MalformedURLException, IOException, ComponentException
      {
          if( this.getLogger().isDebugEnabled() )
          {
              this.getLogger().debug( "Resolving '" + location + "' with base '" + baseURI + "' in context '" + m_baseURL + "'" );
          }
          if( location == null ) throw new MalformedURLException( "Invalid System ID" );
          if( null != baseURI && baseURI.indexOf( ':' ) == -1 )
          {
              throw new MalformedURLException( "BaseURI is not valid, it must contain a protocol: " + baseURI );
          }
  
          // first step: create systemID
          String systemID;
  
          if( baseURI == null ) baseURI = m_baseURL.toExternalForm();
  
          if( location.length() == 0 )
          {
              systemID = baseURI;
          }
          else if( location.charAt( 0 ) == '/' )
          {
              // windows: absolute paths can start with drive letter
              if( location.length() > 2 && location.charAt( 2 ) == ':' )
              {
                  systemID = new StringBuffer( "file:" ).append( location ).toString();
              }
              else
              {
                  final int protocolEnd = baseURI.indexOf( ':' );
                  systemID = new StringBuffer( baseURI.substring( protocolEnd + 1 ) )
                      .append( location ).toString();
              }
          }
          else if( location.indexOf( ":" ) > 1 )
          {
              systemID = location;
          }
          // windows: absolute paths can start with drive letter
          else if( location.length() > 1 && location.charAt( 1 ) == ':' )
          {
              systemID = new StringBuffer( "file:/" ).append( location ).toString();
          }
          else
          {
              if( baseURI.startsWith( "file:" ) == true )
              {
                  File temp = new File( baseURI.substring( "file:".length() ), location );
                  String path = temp.getAbsolutePath();
                  // windows paths starts with drive letter
                  if( path.charAt( 0 ) != File.separator.charAt( 0 ) )
                  {
                      systemID = "file:/" + path;
                  }
                  else
                  {
                      systemID = "file:" + path;
                  }
              }
              else
              {
                  final StringBuffer buffer = new StringBuffer( baseURI );
                  if( !baseURI.endsWith( "/" ) ) buffer.append( '/' );
                  buffer.append( location );
                  systemID = buffer.toString();
              }
          }
          if( this.getLogger().isDebugEnabled() )
          {
              this.getLogger().debug( "Resolved to systemID '" + systemID + "'" );
          }
  
          Source source = null;
          // search for a SourceFactory implementing the protocol
          final int protocolPos = systemID.indexOf( ':' );
          if( protocolPos != -1 )
          {
              final String protocol = systemID.substring( 0, protocolPos );
              if( m_factorySelector.hasComponent( protocol ) )
              {
                  SourceFactory factory = null;
                  try
                  {
                      factory = (SourceFactory)m_factorySelector.select( protocol );
                      source = factory.getSource( systemID, parameters );
                  }
                  finally
                  {
                      m_factorySelector.release( factory );
                  }
              }
          }
  
          if( null == source )
          {
              // no factory found, so usual url handling stuff...
              try
              {
                  if( this.getLogger().isDebugEnabled() == true )
                  {
                      getLogger().debug( "Making URL from " + systemID );
                  }
                  source = new URLSource( new URL( systemID ), parameters );
              }
              catch( MalformedURLException mue )
              {
                  if( this.getLogger().isDebugEnabled() )
                  {
                      getLogger().debug( "Making URL - MalformedURLException in getURL:", mue );
                      getLogger().debug( "Making URL a File (assuming that it is full path):" + systemID );
                  }
                  source = new URLSource( ( new File( systemID ) ).toURL(), parameters );
              }
          }
          if( source instanceof LogEnabled )
          {
              ( (LogEnabled)source ).enableLogging( getLogger() );
          }
          try
          {
              if( source instanceof Contextualizable )
              {
                  ( (Contextualizable)source ).contextualize( m_context );
              }
          }
          catch( ContextException ce )
          {
              throw new ComponentException( "ContextException occured during source resolving.", ce );
          }
  
          if( source instanceof Composable )
          {
              ( (Composable)source ).compose( m_manager );
          }
          return source;
      }
  
      /**
       * Releases a resolved resource
       */
      public void release( Source source )
      {
          if( source == null ) return;
          if( source instanceof Recyclable )
          {
              ( (Recyclable)source ).recycle();
          }
          if( source instanceof Disposable )
          {
              ( (Disposable)source ).dispose();
          }
      }
  
  }
  
  
  
  1.1                  jakarta-avalon-excalibur/all/src/java/org/apache/excalibur/source/impl/URLSource.java
  
  Index: URLSource.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.txt file.
   */
  package org.apache.excalibur.source.impl;
  
  import java.io.File;
  import java.io.FileInputStream;
  import java.io.IOException;
  import java.io.InputStream;
  import java.lang.reflect.Method;
  import java.net.HttpURLConnection;
  import java.net.URL;
  import java.net.URLConnection;
  import java.util.Iterator;
  import java.util.Map;
  import org.apache.avalon.excalibur.monitor.FileResource;
  import org.apache.avalon.excalibur.monitor.Monitorable;
  import org.apache.avalon.excalibur.monitor.Resource;
  import org.apache.avalon.excalibur.monitor.SourceResource;
  import org.apache.excalibur.source.*;
  import org.apache.excalibur.source.impl.validity.TimeStampValidity;
  
  /**
   * Description of a source which is described by an URL.
   *
   * @author <a href="mailto:cziegeler@apache.org">Carsten Ziegeler</a>
   * @version CVS $Revision: 1.1 $ $Date: 2002/04/19 09:05:37 $
   */
  
  public final class URLSource
      implements Source, Monitorable
  {
  
      /** With this parameter you can specify the method to use for a http request.
       *  Default is GET.
       */
      public final String HTTP_METHOD = "org.apache.avalon.excalibur.source.Source.http.method";
  
      /** With this parameter you can specify additional request parameters which are
       *  appended to the URI.
       */
      public final String REQUEST_PARAMETERS = "org.apache.avalon.excalibur.source.Source.request.parameters";
  
      /** Identifier for file urls */
      private final String FILE = "file:";
  
      /** The last modification date or 0 */
      private long lastModificationDate;
  
      /** The system id */
      private String systemId;
  
      /** The URL of the source */
      private URL url;
  
      /** The connection for a real URL */
      private URLConnection connection;
  
      /** Is this a file or a "real" URL */
      private boolean isFile;
  
      /** Are we initialized? */
      private boolean gotInfos;
  
      /** The <code>SourceParameters</code> used for a post*/
      private SourceParameters parameters;
  
      /** Is this a post? */
      private boolean isPost = false;
  
      /**
       * Construct a new object from a <code>URL</code>.
       * @param parameters This is optional
       */
      public URLSource( URL url,
                        Map parameters )
          throws IOException
      {
          this.systemId = url.toExternalForm();
          this.isFile = systemId.startsWith( FILE );
          this.url = url;
          this.gotInfos = false;
          this.isPost = false;
          if( null != parameters )
          {
              this.parameters = (SourceParameters)parameters.get( REQUEST_PARAMETERS );
              final String method = (String)parameters.get( HTTP_METHOD );
              if( "POST".equalsIgnoreCase( method ) )
                  this.isPost = true;
          }
          if( !isFile
              && null != this.parameters
              && this.parameters.hasParameters()
              && !this.isPost )
          {
              StringBuffer urlBuffer = new StringBuffer( this.systemId );
              String key;
              final Iterator i = this.parameters.getParameterNames();
              Iterator values;
              String value;
              boolean first = ( this.systemId.indexOf( '?' ) == -1 );
              if( first == true ) urlBuffer.append( '?' );
              while( i.hasNext() )
              {
                  key = (String)i.next();
                  values = this.parameters.getParameterValues( key );
                  while( values.hasNext() == true )
                  {
                      value = SourceUtil.encode( (String)values.next() );
                      if( first == false ) urlBuffer.append( '&' );
                      first = false;
                      urlBuffer.append( key );
                      urlBuffer.append( '=' );
                      urlBuffer.append( value );
                  }
              }
              this.url = new URL( urlBuffer.toString() );
              this.parameters = null;
          }
      }
  
      /**
       * Get the last modification date and content length of the source.
       * Any exceptions are ignored.
       */
      private void getInfos()
      {
          if( !this.gotInfos )
          {
              if( this.isFile )
              {
                  File file = new File( this.systemId.substring( FILE.length() ) );
                  this.lastModificationDate = file.lastModified();
              }
              else
              {
                  if( !this.isPost )
                  {
                      try
                      {
                          if( null == this.connection )
                          {
                              this.connection = this.url.openConnection();
                              String userInfo = this.getUserInfo();
                              if( this.url.getProtocol().startsWith( "http" ) && userInfo != null )
                              {
                                  this.connection.setRequestProperty( "Authorization", "Basic " + SourceUtil.encodeBASE64( userInfo ) );
                              }
                          }
                          this.lastModificationDate = this.connection.getLastModified();
                      }
                      catch( IOException ignore )
                      {
                          this.lastModificationDate = 0;
                      }
                  }
                  else
                  {
                      // do not open connection when using post!
                      this.lastModificationDate = 0;
                  }
              }
              this.gotInfos = true;
          }
      }
  
      /**
       * Get the last modification date of the source or 0 if it
       * is not possible to determine the date.
       */
      public long getLastModified()
      {
          this.getInfos();
          return this.lastModificationDate;
      }
  
      /**
       *  Get the corresponding Resource object for monitoring.
       */
      public Resource getResource()
          throws Exception
      {
          this.getInfos();
          if( this.isFile == true )
          {
              return new FileResource( this.systemId.substring( FILE.length() ) );
          }
          else
          {
              return new SourceResource( this );
          }
      }
  
      /**
       * Return an <code>InputStream</code> object to read from the source.
       *
       * @throws ResourceNotFoundException if file not found or
       *         HTTP location does not exist.
       * @throws IOException if I/O error occured.
       */
      public InputStream getInputStream()
          throws IOException
      {
          this.getInfos();
          InputStream input = null;
          if( this.isFile == true )
          {
              input = new FileInputStream( this.systemId.substring( FILE.length() ) );
          }
          else
          {
              if( this.connection == null )
              {
                  this.connection = this.url.openConnection();
                  /* The following requires a jdk 1.3 */
                  String userInfo = this.getUserInfo();
                  if( this.url.getProtocol().startsWith( "http" ) && userInfo != null )
                  {
                      this.connection.setRequestProperty( "Authorization", "Basic " + SourceUtil.encodeBASE64( userInfo ) );
                  }
  
                  // do a post operation
                  if( this.connection instanceof HttpURLConnection
                      && this.isPost )
                  {
                      StringBuffer buffer = new StringBuffer( 2000 );
                      String key;
                      Iterator i = this.parameters.getParameterNames();
                      Iterator values;
                      String value;
                      boolean first = true;
                      while( i.hasNext() )
                      {
                          key = (String)i.next();
                          values = this.parameters.getParameterValues( key );
                          while( values.hasNext() == true )
                          {
                              value = SourceUtil.encode( (String)values.next() );
                              if( first == false ) buffer.append( '&' );
                              first = false;
                              buffer.append( key.toString() );
                              buffer.append( '=' );
                              buffer.append( value );
                          }
                      }
                      HttpURLConnection httpCon = (HttpURLConnection)connection;
                      httpCon.setDoInput( true );
  
                      if( buffer.length() > 1 )
                      { // only post if we have parameters
                          String postString = buffer.toString();
                          httpCon.setRequestMethod( "POST" ); // this is POST
                          httpCon.setDoOutput( true );
                          httpCon.setRequestProperty( "Content-type", "application/x-www-form-urlencoded" );
  
                          // A content-length header must be contained in a POST request
                          httpCon.setRequestProperty( "Content-length", Integer.toString( postString.length() ) );
                          java.io.OutputStream out = new java.io.BufferedOutputStream( httpCon.getOutputStream() );
                          out.write( postString.getBytes() );
                          out.close();
                      }
                      input = httpCon.getInputStream();
                      this.connection = null; // make sure a new connection is created next time
                      return input;
                  }
              }
              input = this.connection.getInputStream();
              this.connection = null; // make sure a new connection is created next time
          }
          return input;
      }
  
      private static boolean checkedURLClass = false;
      private static boolean urlSupportsGetUserInfo = false;
      private static Method urlGetUserInfo = null;
      private static Object[] emptyParams = new Object[ 0 ];
  
      /**
       * Check if the <code>URL</code> class supports the getUserInfo()
       * method which is introduced in jdk 1.3
       */
      private String getUserInfo()
      {
          if( URLSource.checkedURLClass == true )
          {
              if( URLSource.urlSupportsGetUserInfo == true )
              {
                  try
                  {
                      return (String)URLSource.urlGetUserInfo.invoke( this.url, URLSource.emptyParams );
                  }
                  catch( Exception e )
                  {
                      // ignore this anyway
                  }
              }
              return null;
          }
          else
          {
              // test if the url class supports the getUserInfo method
              try
              {
                  URLSource.urlGetUserInfo = URL.class.getMethod( "getUserInfo", null );
                  String ui = (String)URLSource.urlGetUserInfo.invoke( this.url, URLSource.emptyParams );
                  URLSource.checkedURLClass = true;
                  URLSource.urlSupportsGetUserInfo = true;
                  return ui;
              }
              catch( Exception e )
              {
              }
              URLSource.checkedURLClass = true;
              URLSource.urlSupportsGetUserInfo = false;
              URLSource.urlGetUserInfo = null;
              return null;
          }
      }
  
      /**
       * Return the unique identifer for this source
       */
      public String getSystemId()
      {
          return this.systemId;
      }
  
      /**
       *  Get the Validity object. This can either wrap the last modification
       *  date or the expires information or...
       *  If it is currently not possible to calculate such an information
       *  <code>null</code> is returned.
       */
      public SourceValidity getValidity()
      {
          final long lm = this.getLastModified();
          if( lm == -1 )
          {
              return null;
          }
          else
          {
              return new TimeStampValidity( lm );
          }
      }
  
      /**
       * Refresh this object and update the last modified date
       * and content length.
       */
      public void discardValidity()
      {
          // reset connection
          this.connection = null;
          this.gotInfos = false;
      }
  
      /**
       * The mime-type of the content described by this object.
       * If the source is not able to determine the mime-type by itself
       * this can be null.
       */
      public String getMimeType()
      {
          // FIXME
          return null;
      }
  }
  
  
  
  1.1                  jakarta-avalon-excalibur/all/src/java/org/apache/excalibur/source/impl/validity/AggregatedValidity.java
  
  Index: AggregatedValidity.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.txt file.
   */
  package org.apache.excalibur.source.impl.validity;
  
  import java.util.ArrayList;
  import java.util.Iterator;
  import java.util.List;
  import org.apache.excalibur.source.SourceValidity;
  
  /**
   * A validation object using a List.
   *
   * @author <a href="mailto:dims@yahoo.com">Davanum Srinivas</a>
   * @version CVS $Revision: 1.1 $ $Date: 2002/04/19 09:05:37 $
   */
  public final class AggregatedValidity
      implements SourceValidity
  {
  
      private List a;
  
      public AggregatedValidity()
      {
          this.a = new ArrayList();
      }
  
      public void add( SourceValidity validity )
      {
          this.a.add( validity );
      }
  
      public boolean isValid()
      {
          for( Iterator i = a.iterator(); i.hasNext(); )
          {
              if( !( (SourceValidity)i.next() ).isValid() )
                  return false;
          }
          return true;
      }
  
      public boolean isValid( SourceValidity validity )
      {
          if( validity instanceof AggregatedValidity )
          {
              List b = ( (AggregatedValidity)validity ).a;
              if( a.size() != b.size() )
                  return false;
              for( Iterator i = a.iterator(), j = b.iterator(); i.hasNext(); )
              {
                  final SourceValidity srcA = (SourceValidity)i.next();
                  final SourceValidity srcB = (SourceValidity)j.next();
                  if( !srcA.isValid() && !srcA.isValid( srcB ) )
                      return false;
              }
              return true;
          }
          return false;
      }
  
      public String toString()
      {
          StringBuffer b = new StringBuffer( "SourceValidity " );
          for( Iterator i = a.iterator(); i.hasNext(); )
          {
              b.append( i.next() );
              if( i.hasNext() ) b.append( ':' );
          }
          return b.toString();
      }
  }
  
  
  
  
  1.1                  jakarta-avalon-excalibur/all/src/java/org/apache/excalibur/source/impl/validity/NOPValidity.java
  
  Index: NOPValidity.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.txt file.
   */
  package org.apache.excalibur.source.impl.validity;
  
  import org.apache.excalibur.source.SourceValidity;
  
  /**
   * A validation object which is always valid.
   *
   * @author <a href="mailto:cziegeler@apache.org">Carsten Ziegeler</a>
   * @version CVS $Revision: 1.1 $ $Date: 2002/04/19 09:05:37 $
   */
  public final class NOPValidity
      implements SourceValidity
  {
  
      public static final SourceValidity SHARED_INSTANCE = new NOPValidity();
  
      /**
       * Check if the component is still valid.
       * If <code>false</code> is returned the isValid(SourceValidity) must be
       * called afterwards!
       */
      public boolean isValid()
      {
          return true;
      }
  
      public boolean isValid( SourceValidity newValidity )
      {
          return newValidity instanceof NOPValidity;
      }
  
      public String toString()
      {
          return "NOPValidity";
      }
  
  }
  
  
  
  1.1                  jakarta-avalon-excalibur/all/src/java/org/apache/excalibur/source/impl/validity/TimeStampValidity.java
  
  Index: TimeStampValidity.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.txt file.
   */
  package org.apache.excalibur.source.impl.validity;
  
  import org.apache.excalibur.source.SourceValidity;
  
  /**
   * A validation object for time-stamps.
   *
   * @author <a href="mailto:cziegeler@apache.org">Carsten Ziegeler</a>
   * @version CVS $Revision: 1.1 $ $Date: 2002/04/19 09:05:37 $
   */
  public final class TimeStampValidity
      implements SourceValidity
  {
  
      private long timeStamp;
  
      public TimeStampValidity( long timeStamp )
      {
          this.timeStamp = timeStamp;
      }
  
      /**
       * Check if the component is still valid.
       * If <code>false</code> is returned the isValid(SourceValidity) must be
       * called afterwards!
       */
      public boolean isValid()
      {
          return false;
      }
  
      public boolean isValid( SourceValidity newValidity )
      {
          if( newValidity instanceof TimeStampValidity )
          {
              return this.timeStamp == ( (TimeStampValidity)newValidity ).getTimeStamp();
          }
          return false;
      }
  
      public long getTimeStamp()
      {
          return this.timeStamp;
      }
  
      public String toString()
      {
          return "TimeStampValidity: " + this.timeStamp;
      }
  
  }
  
  
  

--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>