Hey Odi,

I just made a few minor additions.  We also have to be careful of the
NumberFormatExceptions that will be thrown by the parseInt() type calls.
Perhaps there should be a ConfigurationException?  Also I think that these
related classes should be in their own package, such as httpclient.config.

I am a little concerned about the use of the configuration object.  I would
expect calls to this to look like:

String httpVersion = config.getStringValue("http.version");

It seems a little verbose if it has to be used frequently.  At the same
time, we will have to be careful not to "cache" these values in case a user
changes the config value during runtime.  

I think that this is a pretty good start.  There are some bugs for
configuration that are already opened:
http://issues.apache.org/bugzilla/show_bug.cgi?id=10790
http://issues.apache.org/bugzilla/show_bug.cgi?id=10791
http://issues.apache.org/bugzilla/show_bug.cgi?id=10797

These bugs are targeted for HttpClient 2.1.  Question: do people want this
in the 2.0 release?



-----Original Message-----
From: Ortwin Glück [mailto:[EMAIL PROTECTED]]
Sent: Monday, September 23, 2002 2:53 PM
To: Jakarta Commons Developers List
Subject: Re: [HttpClient] Preferences Architecture Implementation Draft


Here is some code for discussion. It differs slightly from my initial 
sketch but is more flexible that way.


------ Configuration.java

package org.apache.commons.httpclient;

import java.util.*;
import java.io.*;

import org.apache.commons.logging.*;
/**
  * Holds the configuration for the httpclient package. Instances of 
this class
  * are immutable.
  *
  * @author Ortwin Glück
  *
  * @since 2.0
  */

public class Configuration {

     /**
      * The default configuration read from file.
      */
     public static final Configuration DEFAULT = new Configuration();
     public static final String SYSTEM_PROPERTY = 
"org.apache.commons.httpclient.configuration";

     private static final String PROPERTIES_FILE = "httpclient.properties";
     private static final String JAR_PATH = "META-INF/services/";
     private static final Log log = LogFactory.getLog(Configuration.class);
     private Properties props = new Properties();

     /**
      * Creates the default configuration.
      * The default values are read from the 
<tt>httpclient.properties</tt> which is
      * expected in the following locations:
      * 1. $JAVA_HOME/lib/ directory
      * 2. On the classpath
      * 3. In META-INF/services on the classpath
      *
      * For classpath lookups the following class loaders are probed in 
order:
      * 1. the context class loader of the current thread
      * 2. the class loader of this class
      * 3. the system class loader
      *
      * An alternative path and filename may be specified in the
      * <tt>org.apache.commons.httpclient.configuration</tt> System 
Property.
      */
     protected Configuration() {
         String filename = null;
         try {
             filename = System.getProperty(SYSTEM_PROPERTY);
         } catch(SecurityException e) {
         }

         if (filename == null) {
             String javahome = System.getProperty("java.home");
             filename = javahome + File.separator + "lib" + 
File.separator + PROPERTIES_FILE;
         }

         InputStream in = null;
         File file = new File(filename);
         if (file.exists()) {
             try {
                 log.debug("Trying "+filename);
                 in = new FileInputStream(file);
             } catch(Exception e) {
                 log.error("Unable to load configuration file", e);
             }
         }

         if (in == null) {
             try {
                 ClassLoader cl = getClassLoader();
                 if (cl == null) {
                     log.debug("Trying last ressort class loader");
                     in = ClassLoader.getSystemResourceAsStream(JAR_PATH 
+ PROPERTIES_FILE);
                 } else {
                     log.debug("Trying class loader "+cl.toString());
                     in = cl.getResourceAsStream(JAR_PATH + 
PROPERTIES_FILE);
                 }
             } catch(Exception e) {
                 log.error("Error while probing class loaders", e);
             }
         }

         if (in != null) {
             try {
                 props.load(in);
             } catch (IOException e) {
                 log.error("Could not load "+ PROPERTIES_FILE, e);
             }
         } else {
             log.warn(PROPERTIES_FILE +" not found. No default values 
available.");
         }
     }

     /**
      * Returns the best class loader.
      * @return
      */
     private ClassLoader getClassLoader() {
         ClassLoader cl = null;
         try {
             cl = Thread.currentThread().getContextClassLoader();
             if (cl != null) return cl;
         } catch(Exception e) {
             log.warn("ClassLoader Exception: " + e.getMessage());
         }
         try {
             cl = Configuration.class.getClassLoader();
         } catch(Exception e) {
             log.warn("ClassLoader Exception: " + e.getMessage());
         }
         return cl;
     }

     /**
      * Creates a configuration based on a configuration base that is 
modified
      * by the patch values. The <tt>base</tt> is first copied into the new
      * configuration. Afterwards all values from the <tt>patch</tt> 
Properties are
      * stored in the new configuration overwriting existing ones.
      *
      * @param base The configuration base
      * @param patch Values that are replaced in the base configuration.
      */
     public Configuration(Configuration base, Properties patch) {
         //copy
         props.putAll(base.props);
         //patch
         Enumeration keys = patch.keys();
         while (keys.hasMoreElements()) {
             String key = (String) keys.nextElement();
             String value = patch.getProperty(key, "");
             props.setProperty(key, value);
         }
     }

     /**
      * Convenience method to generate a patched configuration based on 
the current one.
      * @param patch Values that are replaced in the base configuration.
      * @return new Configuration(this, patch)
      */
     public Configuration patch(Properties patch) {
         return new Configuration(this, patch);
     }

     public String getStringValue(String key) {
         return props.getProperty(key, "").trim();
     }

     public long getLongValue(String key) {
         return Long.parseLong(getStringValue(key));
     }

     public long getLongHexValue(String key) {
         return Long.parseLong(getStringValue(key), 16);
     }

     public int getIntValue(String key) {
         return Integer.parseInt(getStringValue(key));
     }

     public int getIntHexValue(String key) {
         return Integer.parseInt(getStringValue(key), 16);
     }

     public float getFloatValue(String key) {
         return Float.parseFloat(getStringValue(key));
     }

     public double getDoubleValue(String key) {
         return Double.parseDouble(getStringValue(key));
     }

     public boolean getBooleanValue(String key) {
         return isEnabled(key);
     }
  

     /**
      * Returns true if the value is either yes, true, enabled, on or 1. 
The check
      * is not case sensitive.
      * @param key The key to check
      * @return
      */
     public boolean isEnabled(String key) {
         String val = getStringValue(key).toUpperCase();
         return (val.equals("YES") || val.equals("TRUE")
             || val.equals("ENABLED") || val.equals("ON")
             || val.equals("1"));
     }

     /**
      * Checks if a key is empty.
      * @param key
      * @return false if a key does not exist, it is the empty string or 
consits
      * solely of whitespace; true otherwise.
      */
     public boolean isEmpty(String key) {
         return getStringValue(key).equals("");
     }
}


------------ ConfigKeys.java

package org.apache.commons.httpclient;

/**
  * Holds the property keys used to configure HttpClient.
  * @see Configuration
  *
  * @author Ortwin Glück
  *
  * @since 2.0
  */

public interface ConfigKeys {

     /** The HTTP version to use.  1.0 means HTTP/1.0, 1.1 means HTTP/1.1 */
     public static final String HTTP_VERSION = "http.version";

     /** Whether to use preemtive authorization or not. Boolean. */
     public static final String PREEMPT_AUTH = "preemtive.authorization";

     /** The maximum number of Location redirects until an Exception is 
thrown. Integer. */
     public static final String MAX_REDIRECT = "redirect.maximum";

     /** The user-agent string used to identify the client against the 
web server. String. */
     public static final String USER_AGENT = "user.agent";

     /** The default port for http requests.
     public static final String HTTP_PORT = "http.default.port"

     /** The default port for secure https requests.
     public static final String HTTPS_PORT = "https.default.port"
}

--------- httpclient.properties
http.version=1.1
http.default.port=80
https.default.port=443
authorization.preemptive=true
redirect.maximum=20
user.agent=Jakarta Commons-HttpClient/2.0M1



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

Reply via email to