You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by Ortwin Glück <or...@nose.ch> on 2002/09/30 18:59:11 UTC

[HttpClient] Preferences Architecture Implementation Draft II

This is the second iteration in finding the right architecture for the 
preferences API.
_____
Notes
- Moved to a separate package: httpclient.config
- Configuration is not immutable.
- Configuration is now hierarchical and reflects changes in underlying 
Configurations immediately.
- The new ConfigManager links any object with a Configuration instance.
- If the user does nothing the default configuration is always used.

___________
Sample Code

The user can set the configuration from the outside for HttpClient, 
HttpMultiClient, HttpMethod, HttpConnection. The user should not try to 
configure other classes directly:
--user app
HttpClient client = new HttpClient();
Properties patch = new Properties();
patch.setProperty(ConfigKeys.USER_AGENT, "My HTTP Client 0.01");
Configuration clientConfig = new Configuration(Configuration.DEFAULT, 
patch);
ConfigManager.setConfiguration(client, clientConfig);

HttpClient configures HttpMethod automatically IF not yet configured. 
The same way a HttpConnection is configured:
--HttpClient
  public synchronized int executeMethod(HttpMethod method) {
    ...
    if (!ConfigManager.isConfigured(method)) {
     ConfigManager.setConfiguration(method, myConfig);
    }
    method.execute(getState(), connection);
    ...
  }


Low level objects use the configuration of a higher level object. The 
same applies to inner classes:
--ChunkedInputStream
  myConfig = ConfigManager.getConfiguration(method);
  ... myConfig.getBooleanValue(ConfigKeys.IGNORE_PROTOCOL_VIOLATION);

A static class must be configured by the caller using the meta object.
Users should never try to configure low-level classes:
--caller class
  ConfigManager.setConfiguration(NTLM.class, myConfig);

--NTLM
  Configuration myConfig = ConfigManager.getConfiguration(NTLM.class);
  String mySecurityProvider = 
Configuration.getStringValue(ConfigKeys.SECURITY_PROVIDER);


________
Problems

As you can see this approach generates a large overhead. This is mainly 
caused by one requirement: "Would there be a means to assign my own 
properties object to the HttpClient, HttpConnection and HttpMethod 
objects? So I could control the settings on a "client by client", 
"connection by connection",  or "method by method" basis?" by Mark R. 
Diggory, 2002-9-18.

Any single object (e.g. Cookie) must therefore know which Configuration 
applies to it. This means that the creator of an object must set its 
configuration in the ConfigManager. For static classes  the requirement 
can not be fulfilled at all. Not so nice, is it.

Please, if any of you has a good idea how to deal with this, drop me a note.


Odi




Re: [HttpClient] Preferences Architecture Implementation Draft II

Posted by "Mark R. Diggory" <md...@latte.harvard.edu>.

Ortwin Glück wrote:

> ___________
> Sample Code
>
> The user can set the configuration from the outside for HttpClient, 
> HttpMultiClient, HttpMethod, HttpConnection. The user should not try 
> to configure other classes directly:
> --user app
> HttpClient client = new HttpClient();
> Properties patch = new Properties();
> patch.setProperty(ConfigKeys.USER_AGENT, "My HTTP Client 0.01");
> Configuration clientConfig = new Configuration(Configuration.DEFAULT, 
> patch);
> ConfigManager.setConfiguration(client, clientConfig);

I guess I find this a little confusing. Why wouldn't you push the 
Configuration objects back behind HttpClient. HttpConnection and 
HttpMethod...

like this:

HttpClient client = new HttpClient();
Hashtable props = new Hashtable();
props.put(ConfigKeys.USER_AGENT, "My HTTP Client 0.01");
client.setConfiguration(props);

or

Hashtable props = new Hashtable();
props.put(ConfigKeys.USER_AGENT, "My HTTP Client 0.01");
HttpClient client = new HttpClient(props);

then provide some simple methods for the following:

public void client.addToConfiguration(key,value);
public void client.removeFromConfiguration(key);
public Hashtable getConfiguration();

This might lower the coding overhead.

>
> HttpClient configures HttpMethod automatically IF not yet configured. 
> The same way a HttpConnection is configured:
> --HttpClient
>  public synchronized int executeMethod(HttpMethod method) {
>    ...
>    if (!ConfigManager.isConfigured(method)) {
>     ConfigManager.setConfiguration(method, myConfig);
>    }
>    method.execute(getState(), connection);
>    ...
>  }
>
>
> Low level objects use the configuration of a higher level object. The 
> same applies to inner classes:
> --ChunkedInputStream
>  myConfig = ConfigManager.getConfiguration(method);
>  ... myConfig.getBooleanValue(ConfigKeys.IGNORE_PROTOCOL_VIOLATION);
>
> A static class must be configured by the caller using the meta object.
> Users should never try to configure low-level classes:
> --caller class
>  ConfigManager.setConfiguration(NTLM.class, myConfig);
>
> --NTLM
>  Configuration myConfig = ConfigManager.getConfiguration(NTLM.class);
>  String mySecurityProvider = 
> Configuration.getStringValue(ConfigKeys.SECURITY_PROVIDER);
>
>
> ________
> Problems
>
> As you can see this approach generates a large overhead. This is 
> mainly caused by one requirement: "Would there be a means to assign my 
> own properties object to the HttpClient, HttpConnection and HttpMethod 
> objects? So I could control the settings on a "client by client", 
> "connection by connection",  or "method by method" basis?" by Mark R. 
> Diggory, 2002-9-18.
>
> Any single object (e.g. Cookie) must therefore know which 
> Configuration applies to it. This means that the creator of an object 
> must set its configuration in the ConfigManager. For static classes  
> the requirement can not be fulfilled at all. Not so nice, is it.
>
> Please, if any of you has a good idea how to deal with this, drop me a 
> note.
>
>
> Odi

By using a "static" object to store configuration information 
(ConfigManager) , I think you've made it so that all objects need to get 
registered with it to figure out configuration information. Maybe if, 
each "Http" object simply stored its own Configuration object and was 
able to request from its parent the "parental" configuration. then the 
current configuration of any one object in a hierarchy could easily be 
resolved.

Finally,

I'm not sure how "dynamic" this really needs to be. If you update the 
configuration of a parent object, should it be the case that all 
previously generated objects get that configuration get the changes? 
This currently seems to be what happens by the use of the ConfigManager. 
Does this create alot of config tracking overhead?

I hadn't really looked upon the idea as having the ability to alter the 
config higher in the heirarchy once you had created an object below it.

Would it be more simple to only have newly constructed objects contain 
the new config information. Old objects below that point in the 
hierarchy could either get "destroyed/gc'ed" or "somehow invalidated". 
Then they would get "reinitialized" with the new configuration if this 
is really neccessary to keep them around. (ie. altering the 
configuration wipes out all current connections and when the client gets 
another call to a connection, it is instantiated through normal 
processes with the new config.)

Another note:
Now that I see this, I'm not sure how much configuration manipulation 
one would want to have below the HttpConnection level. My primary 
concern was to be able to manipulate things like proxying in such a way 
that if proxying was setup one way by default for the HttpClient. You 
could alter it for a specific HttpConnection if neccessary, so one could 
proxy 2 connections through two different proxy hosts. At the HttpMethod 
level, this sort of configuaration is Not/Applicable because you don't 
configure proxy info at that level. So is configuration really that 
important at the HttpMethod level? Maybe we should consider evaluating 
how much stuff we would want configurable at the Method level?

Hope this helps some,
-Mark

>
>
>
>
>------------------------------------------------------------------------
>
>/*
> * $Header$
> * $Revision$
> * $Date$
> * ====================================================================
> *
> * The Apache Software License, Version 1.1
> *
> * Copyright (c) 1999-2002 The Apache Software Foundation.  All rights
> * reserved.
> *
> * Redistribution and use in source and binary forms, with or without
> * modification, are permitted provided that the following conditions
> * are met:
> *
> * 1. Redistributions of source code must retain the above copyright
> *    notice, this list of conditions and the following disclaimer.
> *
> * 2. Redistributions in binary form must reproduce the above copyright
> *    notice, this list of conditions and the following disclaimer in
> *    the documentation and/or other materials provided with the
> *    distribution.
> *
> * 3. The end-user documentation included with the redistribution, if
> *    any, must include the following acknowlegement:
> *       "This product includes software developed by the
> *        Apache Software Foundation (http://www.apache.org/)."
> *    Alternately, this acknowlegement may appear in the software itself,
> *    if and wherever such third-party acknowlegements normally appear.
> *
> * 4. The names "The Jakarta Project", "HttpClient", and "Apache Software
> *    Foundation" must not be used to endorse or promote products derived
> *    from this software without prior written permission. For written
> *    permission, please contact apache@apache.org.
> *
> * 5. Products derived from this software may not be called "Apache"
> *    nor may "Apache" appear in their names without prior written
> *    permission of the Apache Group.
> *
> * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
> * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
> * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
> * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
> * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
> * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
> * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
> * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
> * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
> * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
> * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
> * SUCH DAMAGE.
> * ====================================================================
> *
> * This software consists of voluntary contributions made by many
> * individuals on behalf of the Apache Software Foundation.  For more
> * information on the Apache Software Foundation, please see
> * <http://www.apache.org/>.
> *
> * [Additional notices, if required by prior licensing conditions]
> *
> */
>
>package org.apache.commons.httpclient.config;
>
>/**
>  * 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";
>
>     /** The security provider to use for crypto alogrithm implementations. */
>     public static final String SECURITY_PROVIDER = "security.provider";
>
>     /** The maximum number of simultaneous HTTP/S sockets to be opened to the same host */
>     public static final String CONNECTIONS_PER_SERVER = "simultaneous.connections.maximum";
>}
>
>------------------------------------------------------------------------
>
>/*
> * $Header$
> * $Revision$
> * $Date$
> * ====================================================================
> *
> * The Apache Software License, Version 1.1
> *
> * Copyright (c) 1999-2002 The Apache Software Foundation.  All rights
> * reserved.
> *
> * Redistribution and use in source and binary forms, with or without
> * modification, are permitted provided that the following conditions
> * are met:
> *
> * 1. Redistributions of source code must retain the above copyright
> *    notice, this list of conditions and the following disclaimer.
> *
> * 2. Redistributions in binary form must reproduce the above copyright
> *    notice, this list of conditions and the following disclaimer in
> *    the documentation and/or other materials provided with the
> *    distribution.
> *
> * 3. The end-user documentation included with the redistribution, if
> *    any, must include the following acknowlegement:
> *       "This product includes software developed by the
> *        Apache Software Foundation (http://www.apache.org/)."
> *    Alternately, this acknowlegement may appear in the software itself,
> *    if and wherever such third-party acknowlegements normally appear.
> *
> * 4. The names "The Jakarta Project", "HttpClient", and "Apache Software
> *    Foundation" must not be used to endorse or promote products derived
> *    from this software without prior written permission. For written
> *    permission, please contact apache@apache.org.
> *
> * 5. Products derived from this software may not be called "Apache"
> *    nor may "Apache" appear in their names without prior written
> *    permission of the Apache Group.
> *
> * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
> * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
> * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
> * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
> * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
> * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
> * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
> * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
> * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
> * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
> * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
> * SUCH DAMAGE.
> * ====================================================================
> *
> * This software consists of voluntary contributions made by many
> * individuals on behalf of the Apache Software Foundation.  For more
> * information on the Apache Software Foundation, please see
> * <http://www.apache.org/>.
> *
> * [Additional notices, if required by prior licensing conditions]
> *
> */
>
>package org.apache.commons.httpclient.config;
>
>import java.io.File;
>import java.io.FileInputStream;
>import java.io.IOException;
>import java.io.InputStream;
>import java.util.Properties;
>
>import org.apache.commons.logging.Log;
>import org.apache.commons.logging.LogFactory;
>
>/**
>  * Holds a configuration for the httpclient package. A configuration can be
>  * hierarchically based on another configuration and only overwrite (patch) some
>  * of the values in the base configuration. Changes in the underlying base are
>  * immediately reflected in derived configurations.
>  *
>  * @author Ortwin Glück
>  *
>  * @since 2.0
>  */
>public class Configuration {
>    /**
>     * The default configuration read from file.
>     */
>    public static final Configuration DEFAULT = new Configuration();
>    /** Key of the System Property that is queried for the location of the properties file */
>    public static final String SYSTEM_PROPERTY = "org.apache.commons.httpclient.configuration";
>    /** Name of the properties file */
>    private static final String PROPERTIES_FILE = "httpclient.properties";
>    /** Location in a jar file where we expect a properies file */
>    private static final String JAR_PATH = "META-INF/services/";
>    /** The log */
>    private static final Log log = LogFactory.getLog(Configuration.class);
>    /** The actual configuration values */
>    private Properties props = new Properties();
>    /** The base configuration */
>    private Configuration base = null;
>
>    /**
>    * 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 derived configuration based on a configuration base that is modified
>     * by the patch values. Values in <tt>patch</tt> hide values in the <tt>base</tt>.
>     * <tt>DEFAULT</tt> holds the default configuration which
>     * is a good starting point.
>     *
>     * @param base The configuration base or <tt>null</tt>.
>     * @param patch Values that are replaced in the base configuration.
>     */
>    public Configuration(Configuration base, Properties patch) {
>        this.base = base;
>        patch(patch);
>    }
>
>    /**
>    * 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 void patch(Properties patch) {
>        props.putAll(patch);
>    }
>
>    /**
>     * Returns the value that is stored under <tt>key</tt>. If this is a derived
>     * configuration and there is no local value for <tt>key</tt> the base
>     * configuration will be queried.
>     *
>     * @param key The key to query
>     * @return The value as a String. Empty string if no value was found.
>     */
>    public String getStringValue(String key) {
>        if (base == null) {
>            return props.getProperty(key, "").trim();
>        } else {
>            return props.getProperty(key, base.getStringValue(key));
>        }
>    }
>
>    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("");
>    }
>}
>
>------------------------------------------------------------------------
>
>/*
> * $Header$
> * $Revision$
> * $Date$
> * ====================================================================
> *
> * The Apache Software License, Version 1.1
> *
> * Copyright (c) 1999-2002 The Apache Software Foundation.  All rights
> * reserved.
> *
> * Redistribution and use in source and binary forms, with or without
> * modification, are permitted provided that the following conditions
> * are met:
> *
> * 1. Redistributions of source code must retain the above copyright
> *    notice, this list of conditions and the following disclaimer.
> *
> * 2. Redistributions in binary form must reproduce the above copyright
> *    notice, this list of conditions and the following disclaimer in
> *    the documentation and/or other materials provided with the
> *    distribution.
> *
> * 3. The end-user documentation included with the redistribution, if
> *    any, must include the following acknowlegement:
> *       "This product includes software developed by the
> *        Apache Software Foundation (http://www.apache.org/)."
> *    Alternately, this acknowlegement may appear in the software itself,
> *    if and wherever such third-party acknowlegements normally appear.
> *
> * 4. The names "The Jakarta Project", "HttpClient", and "Apache Software
> *    Foundation" must not be used to endorse or promote products derived
> *    from this software without prior written permission. For written
> *    permission, please contact apache@apache.org.
> *
> * 5. Products derived from this software may not be called "Apache"
> *    nor may "Apache" appear in their names without prior written
> *    permission of the Apache Group.
> *
> * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
> * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
> * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
> * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
> * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
> * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
> * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
> * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
> * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
> * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
> * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
> * SUCH DAMAGE.
> * ====================================================================
> *
> * This software consists of voluntary contributions made by many
> * individuals on behalf of the Apache Software Foundation.  For more
> * information on the Apache Software Foundation, please see
> * <http://www.apache.org/>.
> *
> * [Additional notices, if required by prior licensing conditions]
> *
> */
>
>package org.apache.commons.httpclient.config;
>
>import java.util.Map;
>import java.util.WeakHashMap;
>
>/**
> * Links configurations with objects. This implementation uses a WeakHashMap to
> * ensure that configurations are removed automatically when the linked object
> * is not used any more.
> *
> * @author Ortwin Glück
> *
> * @since 2.0
> */
>public class ConfigManager {
>    /** The default configuration (for convenience) */
>    public static final Configuration DEFAULT = Configuration.DEFAULT;
>
>    /** The singleton instance */
>    private static ConfigManager instance = new ConfigManager();
>
>    /** Stores (object, Configuration) pairs */
>    private static Map configs = new WeakHashMap();
>
>    /**
>     * Singleton. Use static methods only.
>     */
>    protected ConfigManager() {
>    }
>
>    /**
>     * Links a configuration to an object. It is stored until the object is reclaimed
>     * by the garbage collector.
>     * @param object The object to link <tt>configuration</tt> to.
>     * @param configuration The configuration.
>     */
>    public static void setConfiguration(Object object, Configuration configuration) {
>        configs.put(object, configuration);
>    }
>
>    /**
>     * Gets the configuration that was linked to an object with the
>     * <tt>setConfiuration</tt> method. If no configuration was set, the default
>     * configuration is returned.
>     * @param object The object whose configuration to get.
>     * @return The configuration that was linked to <tt>object</tt> or the default one.
>     */
>    public static Configuration getConfiguration(Object object) {
>        Configuration config = (Configuration) configs.get(object);
>        if (config == null)  {
>            return DEFAULT;
>        } else {
>            return config;
>        }
>    }
>
>    /**
>     * Checks if there is a specific Configuration for an object.
>     * @param object The object that should be checked.
>     * @return true if a specific Configuration exists, fals if the DEFAULT
>     * is used for this object.
>     */
>    public static boolean isConfigured(Object object) {
>        return (configs.get(object) != null);
>    }
>}
>  
>
>------------------------------------------------------------------------
>
>--
>To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
>For additional commands, e-mail: <ma...@jakarta.apache.org>
>


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


Re: [HttpClient] Preferences Architecture Implementation Draft II

Posted by Costin Manolache <cm...@yahoo.com>.
Jeff Dever wrote:

> I'm torn about this.  I don't think that "bean style" (aka "ass load of
> setters
> and getters") is the answer.  The components in question in HttpClient are
> just
> too big for that to work.  There would be many more _configuration_
> methods in the public interface than anything else.

Then a generic setAttribute ? Or JMX ?

But in general - HttpClient should work as a bean ( or component ) as 
part of a larger program, and support configuration/tunning via API
calls.

Even if a hierarchical pull method is prefered - defining HttpClient's
own config API and/or config file is _bad_ ( and I would -1 it ). 
Either use an existing API ( jndi, properties, etc ), or propose
a top-level commons package ( as a wrapper on top of existing 
solutions ).

Commons component should be easy to integrate in other products and
apps - if they define their own config mechanisms this will be much harder.

Costin


> I think that the configuration that Odi is proposing is a reasonable
> possibility.  The comments that Mark made in a previous email also should 
be
> considered.  I wouldn't exclude a HttpClient customized solution, but if
> there are others, those should be considered too.


 
> As per Mark's email, storing the properties in the respective classes
> themselves
> seems reasonable.  The only problem is making them respect a hierachy. 
> The time that all the components come together (httpmethod, httpstate and
> httpconnection) is in the execute method.  The behavioural properties
> could be checked at the time that execute is called.
> 
> Again, I'm not sure what the right way to go is.
> 
> 
> 
> Costin Manolache wrote:
> 
>> I personally thing this is a very bad idea.
>>
>> There are already enough 'config' architectures:
>> - ant/jmx/bean style, with introspection used to call java bean
>> setters ( with or without Digester )
>> - jdk1.4 preferences/JNDI for hierarchical config and components
>> getting the info themself.
>> - simple Properties storing data with hierarchical names
>>
>> Defining another config API and impl - and doing it specifically
>> for http client is even worse - as it has implications for the
>> code that would like to use http-client and already has its
>> own config mechanisms.
>>
>> I personally think that for components like http client, java-bean
>> style of configuration is the best and in no case should they
>> define their own config files and apis.
>>
>> Except maybe using a common API modeled after jdk1.4 ( similar with
>> commons-logging ) that wraps jdk1.4 logging, jndi and other
>> hierarchical-storage configs ( for those who prefer this instead
>> of setters ).
>>
>> Costin
>>
>> Ortwin Glück wrote:
>>
>> > This is the second iteration in finding the right architecture for the
>> > preferences API.
>> > _____
>> > Notes
>> > - Moved to a separate package: httpclient.config
>> > - Configuration is not immutable.
>> > - Configuration is now hierarchical and reflects changes in underlying
>> > Configurations immediately.
>> > - The new ConfigManager links any object with a Configuration instance.
>> > - If the user does nothing the default configuration is always used.
>> >
>> > ___________
>> > Sample Code
>> >
>> > The user can set the configuration from the outside for HttpClient,
>> > HttpMultiClient, HttpMethod, HttpConnection. The user should not try to
>> > configure other classes directly:
>> > --user app
>> > HttpClient client = new HttpClient();
>> > Properties patch = new Properties();
>> > patch.setProperty(ConfigKeys.USER_AGENT, "My HTTP Client 0.01");
>> > Configuration clientConfig = new Configuration(Configuration.DEFAULT,
>> > patch);
>> > ConfigManager.setConfiguration(client, clientConfig);
>> >
>> > HttpClient configures HttpMethod automatically IF not yet configured.
>> > The same way a HttpConnection is configured:
>> > --HttpClient
>> >   public synchronized int executeMethod(HttpMethod method) {
>> >     ...
>> >     if (!ConfigManager.isConfigured(method)) {
>> >      ConfigManager.setConfiguration(method, myConfig);
>> >     }
>> >     method.execute(getState(), connection);
>> >     ...
>> >   }
>> >
>> >
>> > Low level objects use the configuration of a higher level object. The
>> > same applies to inner classes:
>> > --ChunkedInputStream
>> >   myConfig = ConfigManager.getConfiguration(method);
>> >   ... myConfig.getBooleanValue(ConfigKeys.IGNORE_PROTOCOL_VIOLATION);
>> >
>> > A static class must be configured by the caller using the meta object.
>> > Users should never try to configure low-level classes:
>> > --caller class
>> >   ConfigManager.setConfiguration(NTLM.class, myConfig);
>> >
>> > --NTLM
>> >   Configuration myConfig = ConfigManager.getConfiguration(NTLM.class);
>> >   String mySecurityProvider =
>> > Configuration.getStringValue(ConfigKeys.SECURITY_PROVIDER);
>> >
>> >
>> > ________
>> > Problems
>> >
>> > As you can see this approach generates a large overhead. This is mainly
>> > caused by one requirement: "Would there be a means to assign my own
>> > properties object to the HttpClient, HttpConnection and HttpMethod
>> > objects? So I could control the settings on a "client by client",
>> > "connection by connection",  or "method by method" basis?" by Mark R.
>> > Diggory, 2002-9-18.
>> >
>> > Any single object (e.g. Cookie) must therefore know which Configuration
>> > applies to it. This means that the creator of an object must set its
>> > configuration in the ConfigManager. For static classes  the requirement
>> > can not be fulfilled at all. Not so nice, is it.
>> >
>> > Please, if any of you has a good idea how to deal with this, drop me a
>> > note.
>> >
>> >
>> > Odi
>>
>> --
>> To unsubscribe, e-mail:  
>> <ma...@jakarta.apache.org> For additional
>> commands, e-mail: <ma...@jakarta.apache.org>

-- 
Costin



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


Re: [HttpClient] Preferences Architecture Implementation Draft II

Posted by Jeff Dever <js...@sympatico.ca>.
I'm torn about this.  I don't think that "bean style" (aka "ass load of setters
and getters") is the answer.  The components in question in HttpClient are just
too big for that to work.  There would be many more _configuration_ methods in
the public interface than anything else.

I think that the configuration that Odi is proposing is a reasonable
possibility.  The comments that Mark made in a previous email also should be
considered.  I wouldn't exclude a HttpClient customized solution, but if there
are others, those should be considered too.

As per Mark's email, storing the properties in the respective classes themselves
seems reasonable.  The only problem is making them respect a hierachy.  The time
that all the components come together (httpmethod, httpstate and
httpconnection) is in the execute method.  The behavioural properties could be
checked at the time that execute is called.

Again, I'm not sure what the right way to go is.



Costin Manolache wrote:

> I personally thing this is a very bad idea.
>
> There are already enough 'config' architectures:
> - ant/jmx/bean style, with introspection used to call java bean
> setters ( with or without Digester )
> - jdk1.4 preferences/JNDI for hierarchical config and components
> getting the info themself.
> - simple Properties storing data with hierarchical names
>
> Defining another config API and impl - and doing it specifically
> for http client is even worse - as it has implications for the
> code that would like to use http-client and already has its
> own config mechanisms.
>
> I personally think that for components like http client, java-bean
> style of configuration is the best and in no case should they
> define their own config files and apis.
>
> Except maybe using a common API modeled after jdk1.4 ( similar with
> commons-logging ) that wraps jdk1.4 logging, jndi and other
> hierarchical-storage configs ( for those who prefer this instead
> of setters ).
>
> Costin
>
> Ortwin Glück wrote:
>
> > This is the second iteration in finding the right architecture for the
> > preferences API.
> > _____
> > Notes
> > - Moved to a separate package: httpclient.config
> > - Configuration is not immutable.
> > - Configuration is now hierarchical and reflects changes in underlying
> > Configurations immediately.
> > - The new ConfigManager links any object with a Configuration instance.
> > - If the user does nothing the default configuration is always used.
> >
> > ___________
> > Sample Code
> >
> > The user can set the configuration from the outside for HttpClient,
> > HttpMultiClient, HttpMethod, HttpConnection. The user should not try to
> > configure other classes directly:
> > --user app
> > HttpClient client = new HttpClient();
> > Properties patch = new Properties();
> > patch.setProperty(ConfigKeys.USER_AGENT, "My HTTP Client 0.01");
> > Configuration clientConfig = new Configuration(Configuration.DEFAULT,
> > patch);
> > ConfigManager.setConfiguration(client, clientConfig);
> >
> > HttpClient configures HttpMethod automatically IF not yet configured.
> > The same way a HttpConnection is configured:
> > --HttpClient
> >   public synchronized int executeMethod(HttpMethod method) {
> >     ...
> >     if (!ConfigManager.isConfigured(method)) {
> >      ConfigManager.setConfiguration(method, myConfig);
> >     }
> >     method.execute(getState(), connection);
> >     ...
> >   }
> >
> >
> > Low level objects use the configuration of a higher level object. The
> > same applies to inner classes:
> > --ChunkedInputStream
> >   myConfig = ConfigManager.getConfiguration(method);
> >   ... myConfig.getBooleanValue(ConfigKeys.IGNORE_PROTOCOL_VIOLATION);
> >
> > A static class must be configured by the caller using the meta object.
> > Users should never try to configure low-level classes:
> > --caller class
> >   ConfigManager.setConfiguration(NTLM.class, myConfig);
> >
> > --NTLM
> >   Configuration myConfig = ConfigManager.getConfiguration(NTLM.class);
> >   String mySecurityProvider =
> > Configuration.getStringValue(ConfigKeys.SECURITY_PROVIDER);
> >
> >
> > ________
> > Problems
> >
> > As you can see this approach generates a large overhead. This is mainly
> > caused by one requirement: "Would there be a means to assign my own
> > properties object to the HttpClient, HttpConnection and HttpMethod
> > objects? So I could control the settings on a "client by client",
> > "connection by connection",  or "method by method" basis?" by Mark R.
> > Diggory, 2002-9-18.
> >
> > Any single object (e.g. Cookie) must therefore know which Configuration
> > applies to it. This means that the creator of an object must set its
> > configuration in the ConfigManager. For static classes  the requirement
> > can not be fulfilled at all. Not so nice, is it.
> >
> > Please, if any of you has a good idea how to deal with this, drop me a
> > note.
> >
> >
> > Odi
>
> --
> To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
> For additional commands, e-mail: <ma...@jakarta.apache.org>


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


RE: [HttpClient] Preferences Architecture Implementation Draft II

Posted by Vincent Massol <vm...@octo.com>.

> -----Original Message-----
> From: news [mailto:news@main.gmane.org] On Behalf Of Costin Manolache
> Sent: 01 October 2002 20:27
> To: commons-dev@jakarta.apache.org
> Subject: Re: [HttpClient] Preferences Architecture Implementation
Draft II
> 
> I personally thing this is a very bad idea.

I agree.

> 
> There are already enough 'config' architectures:
> - ant/jmx/bean style, with introspection used to call java bean
> setters ( with or without Digester )
> - jdk1.4 preferences/JNDI for hierarchical config and components
> getting the info themself.
> - simple Properties storing data with hierarchical names
> 
> Defining another config API and impl - and doing it specifically
> for http client is even worse - as it has implications for the
> code that would like to use http-client and already has its
> own config mechanisms.
> 
> I personally think that for components like http client, java-bean
> style of configuration is the best and in no case should they
> define their own config files and apis.

+1

> 
> Except maybe using a common API modeled after jdk1.4 ( similar with
> commons-logging ) that wraps jdk1.4 logging, jndi and other
> hierarchical-storage configs ( for those who prefer this instead
> of setters ).

Please use the javabeans approach. HttpClient should remain a framework
and not an application. Also, please use the Inversion of Control
pattern as much as possible to make the framework as flexible as
possible.

Thanks Costin.

-Vincent

[snip]



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


Re: [HttpClient] Preferences Architecture Implementation Draft II

Posted by Costin Manolache <cm...@yahoo.com>.
I personally thing this is a very bad idea.

There are already enough 'config' architectures: 
- ant/jmx/bean style, with introspection used to call java bean
setters ( with or without Digester )
- jdk1.4 preferences/JNDI for hierarchical config and components
getting the info themself.
- simple Properties storing data with hierarchical names

Defining another config API and impl - and doing it specifically 
for http client is even worse - as it has implications for the 
code that would like to use http-client and already has its
own config mechanisms. 

I personally think that for components like http client, java-bean
style of configuration is the best and in no case should they
define their own config files and apis.

Except maybe using a common API modeled after jdk1.4 ( similar with
commons-logging ) that wraps jdk1.4 logging, jndi and other 
hierarchical-storage configs ( for those who prefer this instead
of setters ).

Costin

Ortwin Glück wrote:

> This is the second iteration in finding the right architecture for the
> preferences API.
> _____
> Notes
> - Moved to a separate package: httpclient.config
> - Configuration is not immutable.
> - Configuration is now hierarchical and reflects changes in underlying
> Configurations immediately.
> - The new ConfigManager links any object with a Configuration instance.
> - If the user does nothing the default configuration is always used.
> 
> ___________
> Sample Code
> 
> The user can set the configuration from the outside for HttpClient,
> HttpMultiClient, HttpMethod, HttpConnection. The user should not try to
> configure other classes directly:
> --user app
> HttpClient client = new HttpClient();
> Properties patch = new Properties();
> patch.setProperty(ConfigKeys.USER_AGENT, "My HTTP Client 0.01");
> Configuration clientConfig = new Configuration(Configuration.DEFAULT,
> patch);
> ConfigManager.setConfiguration(client, clientConfig);
> 
> HttpClient configures HttpMethod automatically IF not yet configured.
> The same way a HttpConnection is configured:
> --HttpClient
>   public synchronized int executeMethod(HttpMethod method) {
>     ...
>     if (!ConfigManager.isConfigured(method)) {
>      ConfigManager.setConfiguration(method, myConfig);
>     }
>     method.execute(getState(), connection);
>     ...
>   }
> 
> 
> Low level objects use the configuration of a higher level object. The
> same applies to inner classes:
> --ChunkedInputStream
>   myConfig = ConfigManager.getConfiguration(method);
>   ... myConfig.getBooleanValue(ConfigKeys.IGNORE_PROTOCOL_VIOLATION);
> 
> A static class must be configured by the caller using the meta object.
> Users should never try to configure low-level classes:
> --caller class
>   ConfigManager.setConfiguration(NTLM.class, myConfig);
> 
> --NTLM
>   Configuration myConfig = ConfigManager.getConfiguration(NTLM.class);
>   String mySecurityProvider =
> Configuration.getStringValue(ConfigKeys.SECURITY_PROVIDER);
> 
> 
> ________
> Problems
> 
> As you can see this approach generates a large overhead. This is mainly
> caused by one requirement: "Would there be a means to assign my own
> properties object to the HttpClient, HttpConnection and HttpMethod
> objects? So I could control the settings on a "client by client",
> "connection by connection",  or "method by method" basis?" by Mark R.
> Diggory, 2002-9-18.
> 
> Any single object (e.g. Cookie) must therefore know which Configuration
> applies to it. This means that the creator of an object must set its
> configuration in the ConfigManager. For static classes  the requirement
> can not be fulfilled at all. Not so nice, is it.
> 
> Please, if any of you has a good idea how to deal with this, drop me a
> note.
> 
> 
> Odi




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