You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by cr...@apache.org on 2003/09/29 08:02:14 UTC

cvs commit: jakarta-commons-sandbox/chain/src/test/org/apache/commons/chain/web/servlet ServletGetLocaleCommandTestCase.java ServletSetLocaleCommandTestCase.java ServletWebContextTestCase.java

craigmcc    2003/09/28 23:02:14

  Modified:    chain    build.xml
               chain/src/java/org/apache/commons/chain Context.java
               chain/src/java/org/apache/commons/chain/generic
                        CopyCommand.java LookupCommand.java
                        RemoveCommand.java
               chain/src/java/org/apache/commons/chain/impl
                        ContextBase.java
               chain/src/java/org/apache/commons/chain/web
                        AbstractGetLocaleCommand.java
                        AbstractSetLocaleCommand.java
               chain/src/java/org/apache/commons/chain/web/faces
                        FacesGetLocaleCommand.java
                        FacesSetLocaleCommand.java
               chain/src/java/org/apache/commons/chain/web/portlet
                        PortletGetLocaleCommand.java
                        PortletSetLocaleCommand.java
               chain/src/java/org/apache/commons/chain/web/servlet
                        ServletGetLocaleCommand.java
                        ServletSetLocaleCommand.java
               chain/src/test/org/apache/commons/chain/config
                        ConfigParserTestCase.java
               chain/src/test/org/apache/commons/chain/impl
                        ChainBaseTestCase.java ContextBaseTestCase.java
                        NonDelegatingCommand.java TestContextTestCase.java
               chain/src/test/org/apache/commons/chain/web/servlet
                        ServletGetLocaleCommandTestCase.java
                        ServletSetLocaleCommandTestCase.java
                        ServletWebContextTestCase.java
  Removed:     chain/src/java/org/apache/commons/chain/impl
                        ContextBase2.java ContextMap2.java
  Log:
  Initial phase of switching to Context "is-a" Map instead of
  Context "has-a" Map.  There are some pretty interesting intricacies
  to implementing the entire Map contract.
  
  FIXME:  Missing unit tests for the following methods on the Set returned
  by ContextBase.keySet():  equals(), hashCode(), iterator(), remove(),
  removeAll(), retain(), retainAll(), toArray(), toArray(Object[]).
  
  FIXME:  Missing unit tests for the returned objects from
  ContextBase.entrySet() and ContextBase.values().
  
  FIXME:  ServletWebContext needs a better equals() method, given the fact
  that it creates new subordinate Map implementations, even if you pass in
  the same context/request/response parameters.
  
  FIXME:  All of the subordinate maps in org.apache.commons.chain.web.servlet
  (and the ones to be created in o.a.c.c.w.faces and o.a.c.c.w.portlet) need
  complete tests for all of the Map contracts.  There are most certainly some
  holes that need to be filled here.
  
  Revision  Changes    Path
  1.3       +8 -1      jakarta-commons-sandbox/chain/build.xml
  
  Index: build.xml
  ===================================================================
  RCS file: /home/cvs/jakarta-commons-sandbox/chain/build.xml,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- build.xml	12 Aug 2003 19:33:56 -0000	1.2
  +++ build.xml	29 Sep 2003 06:02:13 -0000	1.3
  @@ -136,6 +136,8 @@
       <available property="faces.present"    file="${jsf-api.jar}"/>
       <available property="portlet.present"  file="${portlet-api.jar}"/>
       <available property="servlet.present"  file="${servlet-api.jar}"/>
  +    <available property="servlet23.present" classpathref="compile.classpath"
  +              classname="javax.servlet.ServletContextListener"/>
     </target>
   
   
  @@ -146,6 +148,7 @@
       <echo message="faces.present =         ${faces.present}"/>
       <echo message="portlet.present =       ${portlet.present}"/>
       <echo message="servlet.present =       ${servlet.present}"/>
  +    <echo message="servlet23.present =     ${servlet23.present}"/>
       <filter  token="name"                  value="${component.name}"/>
       <filter  token="package"               value="${component.package}"/>
       <filter  token="version"               value="${component.version}"/>
  @@ -178,6 +181,10 @@
              deprecation="${compile.deprecation}"
                 optimize="${compile.optimize}">
         <classpath refid="compile.classpath"/>
  +      <exclude    name="org/apache/commons/chain/web/ChainListener.java"
  +                unless="servlet23.present"/>
  +      <exclude    name="org/apache/commons/chain/web/ChainServlet.java"
  +                unless="servlet.present"/>
         <exclude    name="org/apache/commons/chain/web/faces/*.java"
                   unless="faces.present"/>
         <exclude    name="org/apache/commons/chain/web/portlet/*.java"
  
  
  
  1.3       +9 -44     jakarta-commons-sandbox/chain/src/java/org/apache/commons/chain/Context.java
  
  Index: Context.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons-sandbox/chain/src/java/org/apache/commons/chain/Context.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- Context.java	17 Sep 2003 15:16:08 -0000	1.2
  +++ Context.java	29 Sep 2003 06:02:13 -0000	1.3
  @@ -63,7 +63,6 @@
   package org.apache.commons.chain;
   
   
  -import java.io.Serializable;
   import java.util.Map;
   
   
  @@ -76,6 +75,10 @@
    * context, and/or add operations that affect the state information
    * that is saved in the context.</p>
    *
  + * <p>Implementations of {@link Context} must also implement all of the
  + * required and optional contracts of the <code>java.util.Map</code>
  + * interface.</p>
  + *
    * <p>It is strongly recommended, but not required, that JavaBeans
    * properties added to a particular {@link Context} implementation exhibit
    * <em>Attribute-Property Transparency</em>.  In other words,
  @@ -88,32 +91,6 @@
    * particular implementation class in order to access the property getter
    * and setter methods.</p>
    *
  - * <p>Attribute-Property Transparency can be easily achieved by at least two
  - * different approaches:</p>
  - * <ul>
  - * <li>Implementing the JavaBeans property getter and setter methods in the
  - *     usual way (storing the saved value in an instance variable), but making
  - *     the <code>Map</code> returned by <code>getAttributes()</code> smart
  - *     enough to automatically call the getters and setters via reflection
  - *     if an attribute name matches the name of a supported JavaBeans property.
  - *     The provided {@link org.apache.commons.chain.impl.ContextBase} base
  - *     class is implemented in this fashion.</li>
  - * <li>Implement the <code>Map</code> returned by <code>getAttributes()</code>
  - *     using a standard Java collection class (such as <code>HashMap</code>,
  - *     and implement the property getter and setter methods to retrieve and
  - *     store the values directly into the map.  For example, for a String
  - *     property named <code>foo</code>, you could implement the property getter
  - *     and setter methods as follows:
  - * <pre>
  - *     public String getFoo() {
  - *       return ((String) getAttributes().get("foo"));
  - *     }
  - *     public void setFoo(String foo) {
  - *       getAttributes().put("foo", foo);
  - *     }
  - * </pre></li>
  - * </ul>
  - *
    * <p>To protect applications from evolution of this interface, specialized
    * implementations of {@link Context} should generally be created by extending
    * the provided base class ({@link org.apache.commons.chain.impl.ContextBase})
  @@ -129,19 +106,7 @@
    * @version $Revision$ $Date$
    */
   
  -public interface Context {
  -
  -
  -    /**
  -     * <p>Return an implementation of <code>java.util.Map</code> that
  -     * applications can use to manipulate a general purpose collection
  -     * of key-value pairs that maintain the state information associated
  -     * with the processing of the transaction that is represented by
  -     * this {@link Context} instance.</p>
  -     *
  -     * @return The state information for this context as a Map
  -     */
  -    public Map getAttributes();
  +public interface Context extends Map {
   
   
   }
  
  
  
  1.3       +7 -8      jakarta-commons-sandbox/chain/src/java/org/apache/commons/chain/generic/CopyCommand.java
  
  Index: CopyCommand.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons-sandbox/chain/src/java/org/apache/commons/chain/generic/CopyCommand.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- CopyCommand.java	12 Aug 2003 20:33:24 -0000	1.2
  +++ CopyCommand.java	29 Sep 2003 06:02:13 -0000	1.3
  @@ -169,15 +169,14 @@
        */
       public boolean execute(Context context) throws Exception {
   
  -	Map map = context.getAttributes();
   	Object value = this.value;
           if (value == null) {
  -            map.get(getFromKey());
  +            context.get(getFromKey());
           }
   	if (value != null) {
  -	    map.put(getToKey(), value);
  +	    context.put(getToKey(), value);
   	} else {
  -	    map.remove(getToKey());
  +	    context.remove(getToKey());
   	}
   	return (false);
   
  
  
  
  1.3       +6 -6      jakarta-commons-sandbox/chain/src/java/org/apache/commons/chain/generic/LookupCommand.java
  
  Index: LookupCommand.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons-sandbox/chain/src/java/org/apache/commons/chain/generic/LookupCommand.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- LookupCommand.java	31 Aug 2003 21:50:53 -0000	1.2
  +++ LookupCommand.java	29 Sep 2003 06:02:13 -0000	1.3
  @@ -254,14 +254,14 @@
       private Command getCommand(Context context) {
   
   	Catalog catalog = (Catalog)
  -	    context.getAttributes().get(getCatalogKey());
  +	    context.get(getCatalogKey());
   	if (catalog == null) {
   	    throw new IllegalArgumentException(getCatalogKey());
   	}
   	Command command = null;
   	String name = getName();
   	if (name == null) {
  -	    name = (String) context.getAttributes().get(getNameKey());
  +	    name = (String) context.get(getNameKey());
   	}
   	if (name != null) {
   	    command = catalog.getCommand(name);
  
  
  
  1.3       +5 -5      jakarta-commons-sandbox/chain/src/java/org/apache/commons/chain/generic/RemoveCommand.java
  
  Index: RemoveCommand.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons-sandbox/chain/src/java/org/apache/commons/chain/generic/RemoveCommand.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- RemoveCommand.java	12 Aug 2003 20:33:24 -0000	1.2
  +++ RemoveCommand.java	29 Sep 2003 06:02:13 -0000	1.3
  @@ -117,7 +117,7 @@
        */
       public boolean execute(Context context) throws Exception {
   
  -	context.getAttributes().remove(getFromKey());
  +	context.remove(getFromKey());
   	return (false);
   
       }
  
  
  
  1.4       +736 -24   jakarta-commons-sandbox/chain/src/java/org/apache/commons/chain/impl/ContextBase.java
  
  Index: ContextBase.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons-sandbox/chain/src/java/org/apache/commons/chain/impl/ContextBase.java,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- ContextBase.java	17 Sep 2003 15:17:58 -0000	1.3
  +++ ContextBase.java	29 Sep 2003 06:02:13 -0000	1.4
  @@ -63,7 +63,17 @@
   package org.apache.commons.chain.impl;
   
   
  +import java.beans.IntrospectionException;
  +import java.beans.Introspector;
  +import java.beans.PropertyDescriptor;
  +import java.lang.reflect.Method;
  +import java.util.AbstractCollection;
  +import java.util.AbstractSet;
  +import java.util.Collection;
  +import java.util.HashMap;
  +import java.util.Iterator;
   import java.util.Map;
  +import java.util.Set;
   import org.apache.commons.chain.Context;
   
   
  @@ -71,54 +81,756 @@
    * <p>Convenience base class for {@link Context} implementations.</p>
    *
    * <p>In addition to the minimal functionality required by the {@link Context}
  - * interface, the <code>Map</code> returned by the <code>getAttributes()</code>
  - * method of this class will analyze itself (or its subclass) to identify the
  - * available JavaBeans properties.  Attempts to get or set attributes
  - * whose name matches one of these JavaBeans properties will be reflected
  - * to the corresponding property getter and setter methods for the property
  - * of the corresponding name.</p>
  + * interface, this class implements the recommended support for
  + * <em>Attribute-Property Transparency</p>.  This is implemented by
  + * analyzing the available JavaBeans properties of this class (or its
  + * subclass), exposes them as key-value pairs in the <code>Map</code>,
  + * with the key being the name of the property itself.</p>
  + *
  + * <p><strong>IMPLEMENTATION NOTE</strong> - Because <code>empty</code> is a
  + * read-only property defined by the <code>Map</code> interface, it may not
  + * be utilized as an attribute key or property name.</p>
    *
    * @author Craig R. McClanahan
    * @version $Revision$ $Date$
    */
   
  -public class ContextBase implements Context {
  +public class ContextBase extends HashMap implements Context {
  +
  +
  +    // ------------------------------------------------------------ Constructors
   
   
       /**
        * Default, no argument constructor.
        */
       public ContextBase() {
  -        ;
  +
  +        super();
  +        initialize();
  +
  +    }
  +
  +
  +    /**
  +     * <p>Initialize the contents of this {@link Context} by copying the
  +     * values from the specified <code>Map</code>.  Any keys in <code>map</code>
  +     * that correspond to local properties will cause the setter method for
  +     * that property to be called.</p>
  +     *
  +     * @param map Map whose key-value pairs are added
  +     *
  +     * @exception IllegalArgumentException if an exception is thrown
  +     *  writing a local property value
  +     * @exception UnsupportedOperationException if a local property does not
  +     *  have a write method.
  +     */
  +    public ContextBase(Map map) {
  +
  +        super(map);
  +        initialize();
  +        putAll(map);
  +
  +    }
  +
  +
  +    // ------------------------------------------------------ Instance Variables
  +
  +
  +    /**
  +     * <p>The <code>PropertyDescriptor</code>s for all JavaBeans properties
  +     * of this {@link Context} implementation class, keyed by property name.
  +     * This collection is allocated only if there are any JavaBeans
  +     * properties.</p>
  +     */
  +    private Map descriptors = null;
  +
  +
  +    /**
  +     * <p>The same <code>PropertyDescriptor</code>s as an array.</p>
  +     */
  +    private PropertyDescriptor pd[] = null;
  +
  +
  +    /**
  +     * <p>Distinguished singleton value that is stored in the map for each
  +     * key that is actually a property.  This value is used to ensure that
  +     * <code>equals()</code> comparisons will always fail.</p>
  +     */
  +    private static Object singleton;
  +
  +    static {
  +
  +        singleton = new Object() {
  +                public boolean equals(Object object) {
  +                    return (false);
  +                }
  +            };
  +
  +    }
  +
  +
  +    /**
  +     * <p>Zero-length array of parameter values for calling property getters.
  +     * </p>
  +     */
  +    private static Object zeroParams[] = new Object[0];
  +
  +
  +    // ------------------------------------------------------------- Map Methods
  +
  +
  +    /**
  +     * <p>Override the default <code>Map</code> behavior to clear all keys and
  +     * values except those corresponding to JavaBeans properties.</p>
  +     */
  +    public void clear() {
  +
  +        if (descriptors == null) {
  +            super.clear();
  +        } else {
  +            Iterator keys = keySet().iterator();
  +            while (keys.hasNext()) {
  +                Object key = keys.next();
  +                if (!descriptors.containsKey(key)) {
  +                    keys.remove();
  +                }
  +            }
  +        }
  +
  +    }
  +
  +
  +    /**
  +     * <p>Override the default <code>Map</code> behavior to return
  +     * <code>true</code> if the specified value is present in either the
  +     * underlying <code>Map</code> or one of the local property values.</p>
  +     *
  +     * @exception IllegalArgumentException if a property getter
  +     *  throws an exception
  +     */
  +    public boolean containsValue(Object value) {
  +
  +        // Case 1 -- no local properties
  +        if (descriptors == null) {
  +            return (super.containsValue(value));
  +        }
  +
  +        // Case 2 -- value found in the underlying Map
  +        else if (super.containsValue(value)) {
  +            return (true);
  +        }
  +
  +        // Case 3 -- check the values of our readable properties
  +        for (int i = 0; i < pd.length; i++) {
  +            if (pd[i].getReadMethod() != null) {
  +                Object prop = readProperty(pd[i]);
  +                if (value == null) {
  +                    if (prop == null) {
  +                        return (true);
  +                    }
  +                } else if (value.equals(prop)) {
  +                    return (true);
  +                }
  +            }
  +        }
  +        return (false);
  +        
  +    }
  +
  +
  +    /**
  +     * <p>Override the default <code>Map</code> behavior to return a
  +     * <code>Set</code> that meets the specified default behavior except
  +     * for attempts to remove the key for a property of the {@link Context}
  +     * implementation class, which will throw
  +     * <code>UnsupportedOperationException</code>.</p>
  +     */
  +    public Set entrySet() {
  +
  +        return (new EntrySetImpl());
  +
  +    }
  +
  +
  +    /**
  +     * <p>Override the default <code>Map</code> behavior to return the value
  +     * of a local property if the specified key matches a local property name.
  +     * </p>
  +     *
  +     * <p><strong>IMPLEMENTATION NOTE</strong> - If the specified
  +     * <code>key</code> identifies a write-only property, <code>null</code>
  +     * will arbitrarily be returned, in order to avoid difficulties implementing
  +     * the contracts of the <code>Map</code> interface.</p>
  +     *
  +     * @param key Key of the value to be returned
  +     *
  +     * @exception IllegalArgumentException if an exception is thrown
  +     *  reading this local property value
  +     * @exception UnsupportedOperationException if this local property does not
  +     *  have a read method.
  +     */
  +    public Object get(Object key) {
  +
  +        // Case 1 -- no local properties
  +        if (descriptors == null) {
  +            return (super.get(key));
  +        }
  +
  +        // Case 2 -- this is a local property
  +        if (key != null) {
  +            PropertyDescriptor descriptor =
  +                (PropertyDescriptor) descriptors.get(key);
  +            if (descriptor != null) {
  +                if (descriptor.getReadMethod() != null) {
  +                    return (readProperty(descriptor));
  +                } else {
  +                    return (null);
  +                }
  +            }
  +        }
  +
  +        // Case 3 -- retrieve value from our underlying Map
  +        return (super.get(key));
  +
  +    }
  +
  +
  +    /**
  +     * <p>Override the default <code>Map</code> behavior to return
  +     * <code>true</code> if the underlying <code>Map</code> only contains
  +     * key-value pairs for local properties (if any).</p>
  +     */
  +    public boolean isEmpty() {
  +
  +        // Case 1 -- no local properties
  +        if (descriptors == null) {
  +            return (super.isEmpty());
  +        }
  +
  +        // Case 2 -- compare key count to property count
  +        return (super.size() <= descriptors.size());
  +
  +    }
  +
  +
  +    /**
  +     * <p>Override the default <code>Map</code> behavior to return a
  +     * <code>Set</code> that meets the specified default behavior except
  +     * for attempts to remove the key for a property of the {@link Context}
  +     * implementation class, which will throw
  +     * <code>UnsupportedOperationException</code>.</p>
  +     */
  +    public Set keySet() {
  +
  +
  +        return (super.keySet());
  +
  +    }
  +
  +
  +    /**
  +     * <p>Override the default <code>Map</code> behavior to set the value
  +     * of a local property if the specified key matches a local property name.
  +     * </p>
  +     *
  +     * @param key Key of the value to be stored or replaced
  +     * @param value New value to be stored
  +     *
  +     * @exception IllegalArgumentException if an exception is thrown
  +     *  reading or wrting this local property value
  +     * @exception UnsupportedOperationException if this local property does not
  +     *  have both a read method and a write method
  +     */
  +    public Object put(Object key, Object value) {
  +
  +        // Case 1 -- no local properties
  +        if (descriptors == null) {
  +            return (super.put(key, value));
  +        }
  +
  +        // Case 2 -- this is a local property
  +        if (key != null) {
  +            PropertyDescriptor descriptor =
  +                (PropertyDescriptor) descriptors.get(key);
  +            if (descriptor != null) {
  +                Object previous = null;
  +                if (descriptor.getReadMethod() != null) {
  +                    previous = readProperty(descriptor);
  +                }
  +                writeProperty(descriptor, value);
  +                return (previous);
  +            }
  +        }
  +
  +        // Case 3 -- store or replace value in our underlying map
  +        return (super.put(key, value));
  +
  +    }
  +
  +
  +    /**
  +     * <p>Override the default <code>Map</code> behavior to call the
  +     * <code>put()</code> method individually for each key-value pair
  +     * in the specified <code>Map</code>.</p>
  +     *
  +     * @param map <code>Map</code> containing key-value pairs to store
  +     *  (or replace)
  +     *
  +     * @exception IllegalArgumentException if an exception is thrown
  +     *  reading or wrting a local property value
  +     * @exception UnsupportedOperationException if a local property does not
  +     *  have both a read method and a write method
  +     */
  +    public void putAll(Map map) {
  +
  +        Iterator pairs = map.entrySet().iterator();
  +        while (pairs.hasNext()) {
  +            Map.Entry pair = (Map.Entry) pairs.next();
  +            put(pair.getKey(), pair.getValue());
  +        }
  +
  +    }
  +
  +
  +    /**
  +     * <p>Override the default <code>Map</code> behavior to throw
  +     * <code>UnsupportedOperationException</code> on any attempt to
  +     * remove a key that is the name of a local property.</p>
  +     *
  +     * @param key Key to be removed
  +     *
  +     * @exception UnsupportedOperationException if the specified
  +     *  <code>key</code> matches the name of a local property
  +     */
  +    public Object remove(Object key) {
  +
  +        // Case 1 -- no local properties
  +        if (descriptors == null) {
  +            return (super.remove(key));
  +        }
  +
  +        // Case 2 -- this is a local property
  +        if (key != null) {
  +            PropertyDescriptor descriptor =
  +                (PropertyDescriptor) descriptors.get(key);
  +            if (descriptor != null) {
  +                throw new UnsupportedOperationException
  +                    ("Local property '" + key + "' cannot be removed");
  +            }
  +        }
  +
  +        // Case 3 -- remove from underlying Map
  +        return (super.remove(key));
  +
  +    }
  +
  +
  +    /**
  +     * <p>Override the default <code>Map</code> behavior to return a
  +     * <code>Collection</code> that meets the specified default behavior except
  +     * for attempts to remove the key for a property of the {@link Context}
  +     * implementation class, which will throw
  +     * <code>UnsupportedOperationException</code>.</p>
  +     */
  +    public Collection values() {
  +
  +        return (new ValuesImpl());
  +
  +    }
  +
  +
  +    // --------------------------------------------------------- Private Methods
  +
  +
  +    /**
  +     * <p>Eliminate the specified property descriptor from the list of
  +     * property descriptors in <code>pd</code>.</p>
  +     *
  +     * @param name Name of the property to eliminate
  +     *
  +     * @exception IllegalArgumentException if the specified property name
  +     *  is not present
  +     */
  +    private void eliminate(String name) {
  +
  +        int j = -1;
  +        for (int i = 0; i < pd.length; i++) {
  +            if (name.equals(pd[i].getName())) {
  +                j = i;
  +                break;
  +            }
  +        }
  +        if (j < 0) {
  +            throw new IllegalArgumentException("Property '" + name +
  +                                               "' is not present");
  +        }
  +        PropertyDescriptor results[] = new PropertyDescriptor[pd.length - 1];
  +        System.arraycopy(pd, 0, results, 0, j);
  +        System.arraycopy(pd, j + 1, results, j, pd.length - (j + 1));
  +        pd = results;
  +
  +    }
  +
  +
  +    /**
  +     * <p>Return an <code>Iterator</code> over the set of <code>Map.Entry</code>
  +     * objects representing our key-value pairs.</p>
  +     */
  +    private Iterator entriesIterator() {
  +
  +        return (new EntrySetIterator());
  +
  +    }
  +
  +
  +    /**
  +     * <p>Return a <code>Map.Entry</code> for the specified key value, if it
  +     * is present; otherwise, return <code>null</code>.</p>
  +     *
  +     * @param key Attribute key or property name
  +     */
  +    private Map.Entry entry(Object key) {
  +
  +        if (containsKey(key)) {
  +            return (new MapEntryImpl(key, get(key)));
  +        } else {
  +            return (null);
  +        }
  +
  +    }
  +
  +
  +    /**
  +     * <p>Customize the contents of our underlying <code>Map</code> so that
  +     * it contains keys corresponding to all of the JavaBeans properties of
  +     * the {@link Context} implementation class.</p>
  +     *
  +     *
  +     * @exception IllegalArgumentException if an exception is thrown
  +     *  writing this local property value
  +     * @exception UnsupportedOperationException if this local property does not
  +     *  have a write method.
  +     */
  +    private void initialize() {
  +
  +        // Retrieve the set of property descriptors for this Context class
  +        try {
  +            pd = Introspector.getBeanInfo
  +                (getClass()).getPropertyDescriptors();
  +        } catch (IntrospectionException e) {
  +            pd = new PropertyDescriptor[0]; // Should never happen
  +        }
  +        eliminate("class"); // Because of "getClass()"
  +        eliminate("empty"); // Because of "isEmpty()"
  +
  +        // Initialize the underlying Map contents
  +        if (pd.length > 0) {
  +            descriptors = new HashMap();
  +            for (int i = 0; i < pd.length; i++) {
  +                descriptors.put(pd[i].getName(), pd[i]);
  +                super.put(pd[i].getName(), singleton);
  +            }
  +        }
  +
  +    }
  +
  +
  +    /**
  +     * <p>Get and return the value for the specified property.</p>
  +     *
  +     * @param descriptor <code>PropertyDescriptor</code> for the
  +     *  specified property
  +     *
  +     * @exception IllegalArgumentException if an exception is thrown
  +     *  reading this local property value
  +     * @exception UnsupportedOperationException if this local property does not
  +     *  have a read method.
  +     */
  +    private Object readProperty(PropertyDescriptor descriptor) {
  +
  +        try {
  +            Method method = descriptor.getReadMethod();
  +            if (method == null) {
  +                throw new UnsupportedOperationException
  +                    ("Property '" + descriptor.getName() +
  +                     "' is not readable");
  +            }
  +            return (method.invoke(this, zeroParams));
  +        } catch (Exception e) {
  +            throw new UnsupportedOperationException
  +                ("Exception reading property '" + descriptor.getName() +
  +                 "': " + e.getMessage());
  +        }
  +
  +    }
  +
  +
  +    /**
  +     * <p>Remove the specified key-value pair, if it exists, and return
  +     * <code>true</code>.  If this pair does not exist, return
  +     * <code>false</code>.</p>
  +     *
  +     * @param entry Key-value pair to be removed
  +     *
  +     * @exception UnsupportedOperationException if the specified key
  +     *  identifies a property instead of an attribute
  +     */
  +    private boolean remove(Map.Entry entry) {
  +
  +        Map.Entry actual = entry(entry.getKey());
  +        if (actual == null) {
  +            return (false);
  +        } else if (!entry.equals(actual)) {
  +            return (false);
  +        } else {
  +            remove(entry.getKey());
  +            return (true);
  +        }
  +
  +    }
  +
  +
  +    /**
  +     * <p>Return an <code>Iterator</code> over the set of values in this
  +     * <code>Map</code>.</p>
  +     */
  +    private Iterator valuesIterator() {
  +
  +        return (new ValuesIterator());
  +
  +    }
  +
  +
  +    /**
  +     * <p>Set the value for the specified property.</p>
  +     *
  +     * @param descriptor <code>PropertyDescriptor</code> for the
  +     *  specified property
  +     * @param value The new value for this property (must be of the
  +     *  correct type)
  +     *
  +     * @exception IllegalArgumentException if an exception is thrown
  +     *  writing this local property value
  +     * @exception UnsupportedOperationException if this local property does not
  +     *  have a write method.
  +     */
  +    private void writeProperty(PropertyDescriptor descriptor, Object value) {
  +
  +        try {
  +            Method method = descriptor.getWriteMethod();
  +            if (method == null) {
  +                throw new UnsupportedOperationException
  +                    ("Property '" + descriptor.getName() +
  +                     "' is not writeable");
  +            }
  +            method.invoke(this, new Object[] { value });
  +        } catch (Exception e) {
  +            throw new UnsupportedOperationException
  +                ("Exception writing property '" + descriptor.getName() +
  +                 "': " + e.getMessage());
  +        }
  +
       }
   
  +
  +    // --------------------------------------------------------- Private Classes
  +
  +
  +    /**
  +     * <p>Private implementation of <code>Set</code> that implements the
  +     * semantics required for the value returned by <code>entrySet()</code>.</p>
  +     */
  +    private class EntrySetImpl extends AbstractSet {
  +
  +        public void clear() {
  +            ContextBase.this.clear();
  +        }
  +
  +        public boolean contains(Object obj) {
  +            if (!(obj instanceof Map.Entry)) {
  +                return (false);
  +            }
  +            Map.Entry entry = (Map.Entry) obj;
  +            Entry actual = ContextBase.this.entry(entry.getKey());
  +            if (actual != null) {
  +                return (actual.equals(entry));
  +            } else {
  +                return (false);
  +            }
  +        }
  +
  +        public boolean isEmpty() {
  +            return (ContextBase.this.isEmpty());
  +        }
  +
  +        public Iterator iterator() {
  +            return (ContextBase.this.entriesIterator());
  +        }
  +
  +        public boolean remove(Object obj) {
  +            if (obj instanceof Map.Entry) {
  +                return (ContextBase.this.remove((Map.Entry) obj));
  +            } else {
  +                return (false);
  +            }
  +        }
  +
  +        public int size() {
  +            return (ContextBase.this.size());
  +        }
  +
  +    }
  +
  +
       /**
  -     * Convenience constructor to create context and then add attributes
  -     * from a Map.
  -     * @param attributes A Map of attributes to add
  +     * <p>Private implementation of <code>Iterator</code> for the
  +     * <code>Set</code> returned by <code>entrySet()</code>.</p>
        */
  -    public ContextBase(Map attributes) {
  -        getAttributes().putAll(attributes);
  +    private class EntrySetIterator implements Iterator {
  +
  +        Map.Entry entry = null;
  +        private Iterator keys = ContextBase.this.keySet().iterator();
  +
  +        public boolean hasNext() {
  +            return (keys.hasNext());
  +        }
  +
  +        public Object next() {
  +            entry = ContextBase.this.entry(keys.next());
  +            return (entry);
  +        }
  +
  +        public void remove() {
  +            ContextBase.this.remove(entry);
  +        }
  +
       }
   
   
  -    // ----------------------------------------------------- Instance Variables
  +    /**
  +     * <p>Private implementation of <code>Map.Entry</code> for each item in
  +     * <code>EntrySetImpl</code>.</p>
  +     */
  +    private class MapEntryImpl implements Map.Entry {
  +
  +        MapEntryImpl(Object key, Object value) {
  +            this.key = key;
  +            this.value = value;
  +        }
  +
  +        private Object key;
  +        private Object value;
  +
  +        public boolean equals(Object obj) {
  +            if (obj == null) {
  +                return (false);
  +            } else if (!(obj instanceof Map.Entry)) {
  +                return (false);
  +            }
  +            Map.Entry entry = (Map.Entry) obj;
  +            if (key == null) {
  +                return (entry.getKey() == null);
  +            }
  +            if (key.equals(entry.getKey())) {
  +                if (value == null) {
  +                    return (entry.getValue() == null);
  +                } else {
  +                    return (value.equals(entry.getValue()));
  +                }
  +            } else {
  +                return (false);
  +            }
  +        }
  +
  +        public Object getKey() {
  +            return (this.key);
  +        }
  +
  +        public Object getValue() {
  +            return (this.value);
  +        }
  +
  +        public int hashCode() {
  +            return (((key == null) ? 0 : key.hashCode()) ^
  +                    ((value == null) ? 0 : value.hashCode()));
  +        }
  +
  +        public Object setValue(Object value) {
  +            Object previous = this.value;
  +            ContextBase.this.put(this.key, value);
  +            this.value = value;
  +            return (previous);
  +        }
  +
  +
  +    }
   
   
       /**
  -     * <p>The defined attributes for this {@link Context}.</p>
  +     * <p>Private implementation of <code>Collection</code> that implements the
  +     * semantics required for the value returned by <code>values()</code>.</p>
        */
  -    protected Map attributes = new ContextBaseAttributes(this);
  +    private class ValuesImpl extends AbstractCollection {
  +
  +        public void clear() {
  +            ContextBase.this.clear();
  +        }
  +
  +        public boolean contains(Object obj) {
  +            if (!(obj instanceof Map.Entry)) {
  +                return (false);
  +            }
  +            Map.Entry entry = (Map.Entry) obj;
  +            return (ContextBase.this.containsValue(entry.getValue()));
  +        }
  +
  +        public boolean isEmpty() {
  +            return (ContextBase.this.isEmpty());
  +        }
  +
  +        public Iterator iterator() {
  +            return (ContextBase.this.valuesIterator());
  +        }
  +
  +        public boolean remove(Object obj) {
  +            if (obj instanceof Map.Entry) {
  +                return (ContextBase.this.remove((Map.Entry) obj));
  +            } else {
  +                return (false);
  +            }
  +        }
  +
  +        public int size() {
  +            return (ContextBase.this.size());
  +        }
   
  +    }
   
  -    // -------------------------------------------------------- Context Methods
   
  +    /**
  +     * <p>Private implementation of <code>Iterator</code> for the
  +     * <code>Collection</code> returned by <code>values()</code>.</p>
  +     */
  +    private class ValuesIterator implements Iterator {
   
  -    // See interface for JavaDoc
  -    public Map getAttributes() {
  +        Map.Entry entry = null;
  +        private Iterator keys = ContextBase.this.keySet().iterator();
   
  -        return (attributes);
  +        public boolean hasNext() {
  +            return (keys.hasNext());
  +        }
  +
  +        public Object next() {
  +            entry = ContextBase.this.entry(keys.next());
  +            return (entry.getValue());
  +        }
  +
  +        public void remove() {
  +            ContextBase.this.remove(entry);
  +        }
   
       }
  +
   
   }
  
  
  
  1.2       +5 -5      jakarta-commons-sandbox/chain/src/java/org/apache/commons/chain/web/AbstractGetLocaleCommand.java
  
  Index: AbstractGetLocaleCommand.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons-sandbox/chain/src/java/org/apache/commons/chain/web/AbstractGetLocaleCommand.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- AbstractGetLocaleCommand.java	11 Aug 2003 04:44:17 -0000	1.1
  +++ AbstractGetLocaleCommand.java	29 Sep 2003 06:02:13 -0000	1.2
  @@ -126,7 +126,7 @@
        */
       public boolean execute(Context context) throws Exception {
   
  -	context.getAttributes().put(getLocaleKey(), getLocale(context));
  +	context.put(getLocaleKey(), getLocale(context));
   	return (false);
   
       }
  
  
  
  1.2       +5 -5      jakarta-commons-sandbox/chain/src/java/org/apache/commons/chain/web/AbstractSetLocaleCommand.java
  
  Index: AbstractSetLocaleCommand.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons-sandbox/chain/src/java/org/apache/commons/chain/web/AbstractSetLocaleCommand.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- AbstractSetLocaleCommand.java	11 Aug 2003 04:44:17 -0000	1.1
  +++ AbstractSetLocaleCommand.java	29 Sep 2003 06:02:13 -0000	1.2
  @@ -128,7 +128,7 @@
       public boolean execute(Context context) throws Exception {
   
   	setLocale(context,
  -		  (Locale) context.getAttributes().get(getLocaleKey()));
  +		  (Locale) context.get(getLocaleKey()));
   	return (false);
   
       }
  
  
  
  1.3       +4 -4      jakarta-commons-sandbox/chain/src/java/org/apache/commons/chain/web/faces/FacesGetLocaleCommand.java
  
  Index: FacesGetLocaleCommand.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons-sandbox/chain/src/java/org/apache/commons/chain/web/faces/FacesGetLocaleCommand.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- FacesGetLocaleCommand.java	12 Aug 2003 20:33:24 -0000	1.2
  +++ FacesGetLocaleCommand.java	29 Sep 2003 06:02:13 -0000	1.3
  @@ -86,7 +86,7 @@
       protected Locale getLocale(Context context) {
   
   	FacesContext fcontext = (FacesContext)
  -	    context.getAttributes().get("context");
  +	    context.get("context");
   	return (fcontext.getLocale());
   
       }
  
  
  
  1.3       +4 -4      jakarta-commons-sandbox/chain/src/java/org/apache/commons/chain/web/faces/FacesSetLocaleCommand.java
  
  Index: FacesSetLocaleCommand.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons-sandbox/chain/src/java/org/apache/commons/chain/web/faces/FacesSetLocaleCommand.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- FacesSetLocaleCommand.java	12 Aug 2003 20:33:24 -0000	1.2
  +++ FacesSetLocaleCommand.java	29 Sep 2003 06:02:13 -0000	1.3
  @@ -83,7 +83,7 @@
       protected void setLocale(Context context, Locale locale) {
   
   	FacesContext fcontext = (FacesContext)
  -	    context.getAttributes().get("context");
  +	    context.get("context");
   	fcontext.setLocale(locale);
   
       }
  
  
  
  1.3       +4 -4      jakarta-commons-sandbox/chain/src/java/org/apache/commons/chain/web/portlet/PortletGetLocaleCommand.java
  
  Index: PortletGetLocaleCommand.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons-sandbox/chain/src/java/org/apache/commons/chain/web/portlet/PortletGetLocaleCommand.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- PortletGetLocaleCommand.java	12 Aug 2003 20:33:24 -0000	1.2
  +++ PortletGetLocaleCommand.java	29 Sep 2003 06:02:13 -0000	1.3
  @@ -86,7 +86,7 @@
       protected Locale getLocale(Context context) {
   
   	PortletRequest request = (PortletRequest)
  -	    context.getAttributes().get("request");
  +	    context.get("request");
   	return (request.getLocale());
   
       }
  
  
  
  1.3       +4 -4      jakarta-commons-sandbox/chain/src/java/org/apache/commons/chain/web/portlet/PortletSetLocaleCommand.java
  
  Index: PortletSetLocaleCommand.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons-sandbox/chain/src/java/org/apache/commons/chain/web/portlet/PortletSetLocaleCommand.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- PortletSetLocaleCommand.java	12 Aug 2003 20:33:24 -0000	1.2
  +++ PortletSetLocaleCommand.java	29 Sep 2003 06:02:13 -0000	1.3
  @@ -83,7 +83,7 @@
       protected void setLocale(Context context, Locale locale) {
   
   	PortletResponse response = (PortletResponse)
  -	    context.getAttributes().get("response");
  +	    context.get("response");
   	//	response.setLocale(locale);
   	// Not supported by the Portlet API
   
  
  
  
  1.3       +4 -4      jakarta-commons-sandbox/chain/src/java/org/apache/commons/chain/web/servlet/ServletGetLocaleCommand.java
  
  Index: ServletGetLocaleCommand.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons-sandbox/chain/src/java/org/apache/commons/chain/web/servlet/ServletGetLocaleCommand.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- ServletGetLocaleCommand.java	12 Aug 2003 20:33:25 -0000	1.2
  +++ ServletGetLocaleCommand.java	29 Sep 2003 06:02:13 -0000	1.3
  @@ -86,7 +86,7 @@
       protected Locale getLocale(Context context) {
   
   	HttpServletRequest request = (HttpServletRequest)
  -	    context.getAttributes().get("request");
  +	    context.get("request");
   	return (request.getLocale());
   
       }
  
  
  
  1.3       +4 -4      jakarta-commons-sandbox/chain/src/java/org/apache/commons/chain/web/servlet/ServletSetLocaleCommand.java
  
  Index: ServletSetLocaleCommand.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons-sandbox/chain/src/java/org/apache/commons/chain/web/servlet/ServletSetLocaleCommand.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- ServletSetLocaleCommand.java	12 Aug 2003 20:33:25 -0000	1.2
  +++ ServletSetLocaleCommand.java	29 Sep 2003 06:02:13 -0000	1.3
  @@ -83,7 +83,7 @@
       protected void setLocale(Context context, Locale locale) {
   
   	HttpServletResponse response = (HttpServletResponse)
  -	    context.getAttributes().get("response");
  +	    context.get("response");
   	response.setLocale(locale);
   
       }
  
  
  
  1.3       +4 -4      jakarta-commons-sandbox/chain/src/test/org/apache/commons/chain/config/ConfigParserTestCase.java
  
  Index: ConfigParserTestCase.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons-sandbox/chain/src/test/org/apache/commons/chain/config/ConfigParserTestCase.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- ConfigParserTestCase.java	12 Aug 2003 20:33:25 -0000	1.2
  +++ ConfigParserTestCase.java	29 Sep 2003 06:02:13 -0000	1.3
  @@ -364,7 +364,7 @@
   
       // Verify the contents of the execution log
       protected void checkExecuteLog(String expected) {
  -        StringBuffer log = (StringBuffer) context.getAttributes().get("log");
  +        StringBuffer log = (StringBuffer) context.get("log");
           assertNotNull("Context returned log");
           assertEquals("Context returned correct log",
                        expected, log.toString());
  
  
  
  1.3       +5 -5      jakarta-commons-sandbox/chain/src/test/org/apache/commons/chain/impl/ChainBaseTestCase.java
  
  Index: ChainBaseTestCase.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons-sandbox/chain/src/test/org/apache/commons/chain/impl/ChainBaseTestCase.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- ChainBaseTestCase.java	12 Aug 2003 20:33:25 -0000	1.2
  +++ ChainBaseTestCase.java	29 Sep 2003 06:02:14 -0000	1.3
  @@ -398,7 +398,7 @@
   
       // Verify the contents of the execution log
       protected void checkExecuteLog(String expected) {
  -        StringBuffer log = (StringBuffer) context.getAttributes().get("log");
  +        StringBuffer log = (StringBuffer) context.get("log");
           assertNotNull("Context returned log");
           assertEquals("Context returned correct log",
                        expected, log.toString());
  
  
  
  1.3       +227 -29   jakarta-commons-sandbox/chain/src/test/org/apache/commons/chain/impl/ContextBaseTestCase.java
  
  Index: ContextBaseTestCase.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons-sandbox/chain/src/test/org/apache/commons/chain/impl/ContextBaseTestCase.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- ContextBaseTestCase.java	12 Aug 2003 20:33:25 -0000	1.2
  +++ ContextBaseTestCase.java	29 Sep 2003 06:02:14 -0000	1.3
  @@ -62,12 +62,18 @@
   package org.apache.commons.chain.impl;
   
   
  +import java.util.HashMap;
  +import java.util.Iterator;
  +import java.util.ArrayList;
  +import java.util.Collection;
  +import java.util.List;
  +import java.util.Map;
  +import java.util.Set;
   import junit.framework.Test;
   import junit.framework.TestCase;
   import junit.framework.TestSuite;
   import org.apache.commons.chain.Context;
   
  -import java.util.Iterator;
   
   
   /**
  @@ -109,7 +115,7 @@
        * Set up instance variables required by this test case.
        */
       public void setUp() {
  -        context = new ContextBase();
  +        context = createContext();
       }
   
   
  @@ -131,65 +137,202 @@
       // ------------------------------------------------ Individual Test Methods
   
   
  -    // Test ability to get and set attributes
  +    // Test ability to get, put, and remove attributes
       public void testAttributes() {
   
           Object value = null;
           checkAttributeCount(0);
   
  -        context.getAttributes().put("foo", "This is foo");
  +        context.put("foo", "This is foo");
           checkAttributeCount(1);
  -        value = context.getAttributes().get("foo");
  +        value = context.get("foo");
           assertNotNull("Returned foo", value);
           assertTrue("Returned foo type", value instanceof String);
           assertEquals("Returned foo value", "This is foo",
                        (String) value);
           
  -
  -        context.getAttributes().put("bar", "This is bar");
  +        context.put("bar", "This is bar");
           checkAttributeCount(2);
  -        value = context.getAttributes().get("bar");
  +        value = context.get("bar");
           assertNotNull("Returned bar", value);
           assertTrue("Returned bar type", value instanceof String);
           assertEquals("Returned bar value", "This is bar",
                        (String) value);
           
  -
  -        context.getAttributes().put("baz", "This is baz");
  +        context.put("baz", "This is baz");
           checkAttributeCount(3);
  -        value = context.getAttributes().get("baz");
  +        value = context.get("baz");
           assertNotNull("Returned baz", value);
           assertTrue("Returned baz type", value instanceof String);
           assertEquals("Returned baz value", "This is baz",
                        (String) value);
           
  -
  -        context.getAttributes().put("baz", "This is new baz");
  +        context.put("baz", "This is new baz");
           checkAttributeCount(3); // Replaced, not added
  -        value = context.getAttributes().get("baz");
  +        value = context.get("baz");
           assertNotNull("Returned baz", value);
           assertTrue("Returned baz type", value instanceof String);
           assertEquals("Returned baz value", "This is new baz",
                        (String) value);
           
  -        context.getAttributes().remove("bar");
  +        context.remove("bar");
           checkAttributeCount(2);
           assertNull("Did not return bar",
  -                   context.getAttributes().get("bar"));
  +                   context.get("bar"));
           assertNotNull("Still returned foo",
  -                      context.getAttributes().get("foo"));
  +                      context.get("foo"));
           assertNotNull("Still returned baz",
  -                      context.getAttributes().get("baz"));
  +                      context.get("baz"));
   
  -        context.getAttributes().clear();
  +        context.clear();
           checkAttributeCount(0);
           assertNull("Did not return foo",
  -                   context.getAttributes().get("foo"));
  +                   context.get("foo"));
           assertNull("Did not return bar",
  -                   context.getAttributes().get("bar"));
  +                   context.get("bar"));
           assertNull("Did not return baz",
  -                   context.getAttributes().get("baz"));
  +                   context.get("baz"));
  +
  +    }
  +
  +
  +    // Test containsKey() and containsValue()
  +    public void testContains() {
  +
  +        assertTrue(!context.containsKey("bop"));
  +        assertTrue(!context.containsValue("bop value"));
  +        context.put("bop", "bop value");
  +        assertTrue(context.containsKey("bop"));
  +        assertTrue(context.containsValue("bop value"));
  +        context.remove("bop");
  +        assertTrue(!context.containsKey("bop"));
  +        assertTrue(!context.containsValue("bop value"));
  +
  +    }
  +
  +
  +    // Test equals() and hashCode()
  +    public void testEquals() {
  +
  +        // Compare to self
  +        assertTrue(context.equals(context));
  +        assertTrue(context.hashCode() == context.hashCode());
  +
  +        // Compare to equivalent instance
  +        Context other = createContext();
  +        assertTrue(context.equals(other));
  +        assertTrue(context.hashCode() == other.hashCode());
  +
  +        // Compare to non-equivalent instance - other modified
  +        other.put("bop", "bop value");
  +        assertTrue(!context.equals(other));
  +        assertTrue(context.hashCode() != other.hashCode());
  +
  +        // Compare to non-equivalent instance - self modified
  +        other = createContext(); // reset to equivalence
  +        context.put("bop", "bop value");
  +        assertTrue(!context.equals(other));
  +        assertTrue(context.hashCode() != other.hashCode());
  +
  +    }        
  +
  +
  +    // Test keySet()
  +    public void testKeySet() {
  +
  +        Set keySet = null;
  +        Collection all = new ArrayList();
  +
  +        // Unsupported operations
  +        keySet = context.keySet();
  +        try {
  +            keySet.add("bop");
  +            fail("Should have thrown UnsupportedOperationException");
  +        } catch (UnsupportedOperationException e) {
  +            ; // Expected result
  +        }
  +        try {
  +            Collection adds = new ArrayList();
  +            adds.add("bop");
  +            keySet.addAll(adds);
  +            fail("Should have thrown UnsupportedOperationException");
  +        } catch (UnsupportedOperationException e) {
  +            ; // Expected result
  +        }
   
  +        // Before-modification checks
  +        keySet = context.keySet();
  +        assertEquals(createContext().size(), keySet.size());
  +        assertTrue(!keySet.contains("foo"));
  +        assertTrue(!keySet.contains("bar"));
  +        assertTrue(!keySet.contains("baz"));
  +        assertTrue(!keySet.contains("bop"));
  +
  +        // Add the new elements
  +        context.put("foo", "foo value");
  +        context.put("bar", "bar value");
  +        context.put("baz", "baz value");
  +        all.add("foo");
  +        all.add("bar");
  +        all.add("baz");
  +
  +        // After-modification checks
  +        keySet = context.keySet();
  +        assertEquals(expectedAttributeCount() + 3, keySet.size());
  +        assertTrue(keySet.contains("foo"));
  +        assertTrue(keySet.contains("bar"));
  +        assertTrue(keySet.contains("baz"));
  +        assertTrue(!keySet.contains("bop"));
  +        assertTrue(keySet.containsAll(all));
  +
  +        // Remove a single element via remove()
  +        context.remove("bar");
  +        all.remove("bar");
  +        keySet = context.keySet();
  +        assertEquals(expectedAttributeCount() + 2, keySet.size());
  +        assertTrue(keySet.contains("foo"));
  +        assertTrue(!keySet.contains("bar"));
  +        assertTrue(keySet.contains("baz"));
  +        assertTrue(!keySet.contains("bop"));
  +        assertTrue(keySet.containsAll(all));
  +
  +        // Remove a single element via keySet.remove()
  +        keySet.remove("baz");
  +        all.remove("baz");
  +        keySet = context.keySet();
  +        assertEquals(expectedAttributeCount() + 1, keySet.size());
  +        assertTrue(keySet.contains("foo"));
  +        assertTrue(!keySet.contains("bar"));
  +        assertTrue(!keySet.contains("baz"));
  +        assertTrue(!keySet.contains("bop"));
  +        assertTrue(keySet.containsAll(all));
  +
  +        // Remove all elements via keySet.clear()
  +        keySet.clear();
  +        all.clear();
  +        assertEquals(expectedAttributeCount(), keySet.size());
  +        assertTrue(!keySet.contains("foo"));
  +        assertTrue(!keySet.contains("bar"));
  +        assertTrue(!keySet.contains("baz"));
  +        assertTrue(!keySet.contains("bop"));
  +        assertTrue(keySet.containsAll(all));
  +
  +        // Add the new elements #2
  +        context.put("foo", "foo value");
  +        context.put("bar", "bar value");
  +        context.put("baz", "baz value");
  +        all.add("foo");
  +        all.add("bar");
  +        all.add("baz");
  +
  +        // After-modification checks #2
  +        keySet = context.keySet();
  +        assertEquals(expectedAttributeCount() + 3, keySet.size());
  +        assertTrue(keySet.contains("foo"));
  +        assertTrue(keySet.contains("bar"));
  +        assertTrue(keySet.contains("baz"));
  +        assertTrue(!keySet.contains("bop"));
  +        assertTrue(keySet.containsAll(all));
   
       }
   
  @@ -199,7 +342,44 @@
   
           checkAttributeCount(0);
           assertNull("No 'foo' attribute",
  -                   context.getAttributes().get("foo"));
  +                   context.get("foo"));
  +
  +    }
  +
  +
  +    // Test putAll()
  +    public void testPutAll() {
  +
  +        // Check preconditions
  +        checkAttributeCount(0);
  +        assertNull(context.get("foo"));
  +        assertNull(context.get("bar"));
  +        assertNull(context.get("baz"));
  +        assertTrue(!context.containsKey("foo"));
  +        assertTrue(!context.containsKey("bar"));
  +        assertTrue(!context.containsKey("baz"));
  +        assertTrue(!context.containsValue("foo value"));
  +        assertTrue(!context.containsValue("bar value"));
  +        assertTrue(!context.containsValue("baz value"));
  +
  +        // Call putAll()
  +        Map adds = new HashMap();
  +        adds.put("foo", "foo value");
  +        adds.put("bar", "bar value");
  +        adds.put("baz", "baz value");
  +        context.putAll(adds);
  +
  +        // Check postconditions
  +        checkAttributeCount(3);
  +        assertEquals("foo value", (String) context.get("foo"));
  +        assertEquals("bar value", (String) context.get("bar"));
  +        assertEquals("baz value", (String) context.get("baz"));
  +        assertTrue(context.containsKey("foo"));
  +        assertTrue(context.containsKey("bar"));
  +        assertTrue(context.containsKey("baz"));
  +        assertTrue(context.containsValue("foo value"));
  +        assertTrue(context.containsValue("bar value"));
  +        assertTrue(context.containsValue("baz value"));
   
       }
   
  @@ -210,12 +390,30 @@
       // Verify the number of defined attributes
       protected void checkAttributeCount(int expected) {
           int actual = 0;
  -        Iterator keys = context.getAttributes().keySet().iterator();
  +        Iterator keys = context.keySet().iterator();
           while (keys.hasNext()) {
               Object key = (Object) keys.next();
               actual++;
           }
  -        assertEquals("Correct attribute count", expected, actual);
  +        assertEquals("Correct attribute count",
  +                     expectedAttributeCount() + expected, actual);
  +        if (expected == 0) {
  +            assertTrue("Context should be empty", context.isEmpty());
  +        } else {
  +            assertTrue("Context should not be empty", !context.isEmpty());
  +        }
  +    }
  +
  +
  +    // Create a new instance of the appropriate Context type for this test case
  +    protected Context createContext() {
  +        return (new ContextBase());
  +    }
  +
  +
  +    // Return the expected size() for a Context for this test case
  +    protected int expectedAttributeCount() {
  +        return (createContext().size());
       }
   
   
  
  
  
  1.3       +6 -6      jakarta-commons-sandbox/chain/src/test/org/apache/commons/chain/impl/NonDelegatingCommand.java
  
  Index: NonDelegatingCommand.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons-sandbox/chain/src/test/org/apache/commons/chain/impl/NonDelegatingCommand.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- NonDelegatingCommand.java	12 Aug 2003 20:33:25 -0000	1.2
  +++ NonDelegatingCommand.java	29 Sep 2003 06:02:14 -0000	1.3
  @@ -134,10 +134,10 @@
        * @param id The identifier to be logged
        */
       protected void log(Context context, String id) {
  -        StringBuffer sb = (StringBuffer) context.getAttributes().get("log");
  +        StringBuffer sb = (StringBuffer) context.get("log");
           if (sb == null) {
               sb = new StringBuffer();
  -            context.getAttributes().put("log", sb);
  +            context.put("log", sb);
           }
           if (sb.length() > 0) {
               sb.append('/');
  
  
  
  1.3       +35 -14    jakarta-commons-sandbox/chain/src/test/org/apache/commons/chain/impl/TestContextTestCase.java
  
  Index: TestContextTestCase.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons-sandbox/chain/src/test/org/apache/commons/chain/impl/TestContextTestCase.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- TestContextTestCase.java	12 Aug 2003 20:33:25 -0000	1.2
  +++ TestContextTestCase.java	29 Sep 2003 06:02:14 -0000	1.3
  @@ -64,6 +64,7 @@
   
   import junit.framework.Test;
   import junit.framework.TestSuite;
  +import org.apache.commons.chain.Context;
   
   
   /**
  @@ -74,7 +75,7 @@
   public class TestContextTestCase extends ContextBaseTestCase {
   
   
  -    // ---------------------------------------------------------- Constructors
  +    // ------------------------------------------------------------ Constructors
   
       /**
        * Construct a new instance of this test case.
  @@ -86,14 +87,14 @@
       }
   
   
  -    // -------------------------------------------------- Overall Test Methods
  +    // ---------------------------------------------------- Overall Test Methods
   
   
       /**
        * Set up instance variables required by this test case.
        */
       public void setUp() {
  -        context = new TestContext();
  +        context = createContext();
       }
   
   
  @@ -105,26 +106,37 @@
       }
   
   
  -    // ------------------------------------------------ Individual Test Methods
  +    // ------------------------------------------------- Individual Test Methods
  +
  +
  +    // Test state of newly created instance
  +    public void testPristine() {
  +
  +        super.testPristine();
  +        assertEquals("readOnly", (String) context.get("readOnly"));
  +        assertEquals("readWrite", (String) context.get("readWrite"));
  +        assertEquals("writeOnly", ((TestContext) context).returnWriteOnly());
  +
  +    }
   
   
       // Test a read only property on the Context implementation class
       public void testReadOnly() {
   
  -        Object readOnly = context.getAttributes().get("readOnly");
  +        Object readOnly = context.get("readOnly");
           assertNotNull("readOnly found", readOnly);
           assertTrue("readOnly String",
                      readOnly instanceof String);
           assertEquals("readOnly value", "readOnly", readOnly);
   
           try {
  -            context.getAttributes().put("readOnly", "new readOnly");
  +            context.put("readOnly", "new readOnly");
               fail("Should have thrown UnsupportedOperationException");
           } catch (UnsupportedOperationException e) {
               ; // Expected result
           }
           assertEquals("readOnly unchanged", "readOnly",
  -                     (String) context.getAttributes().get("readOnly"));
  +                     (String) context.get("readOnly"));
   
       }
   
  @@ -132,14 +144,14 @@
       // Test a read write property on the Context implementation class
       public void testReadWrite() {
   
  -        Object readWrite = context.getAttributes().get("readWrite");
  +        Object readWrite = context.get("readWrite");
           assertNotNull("readWrite found", readWrite);
           assertTrue("readWrite String",
                      readWrite instanceof String);
           assertEquals("readWrite value", "readWrite", readWrite);
   
  -        context.getAttributes().put("readWrite", "new readWrite");
  -        readWrite = context.getAttributes().get("readWrite");
  +        context.put("readWrite", "new readWrite");
  +        readWrite = context.get("readWrite");
           assertNotNull("readWrite found", readWrite);
           assertTrue("readWrite String",
                      readWrite instanceof String);
  @@ -157,13 +169,22 @@
                      writeOnly instanceof String);
           assertEquals("writeOnly value", "writeOnly", writeOnly);
   
  -        context.getAttributes().put("writeOnly", "new writeOnly");
  +        context.put("writeOnly", "new writeOnly");
           writeOnly = ((TestContext) context).returnWriteOnly();
           assertNotNull("writeOnly found", writeOnly);
           assertTrue("writeOnly String",
                      writeOnly instanceof String);
           assertEquals("writeOnly value", "new writeOnly", writeOnly);
   
  +    }
  +
  +
  +    // ------------------------------------------------------- Protected Methods
  +
  +
  +    // Create a new instance of the appropriate Context type for this test case
  +    protected Context createContext() {
  +        return (new TestContext());
       }
   
   
  
  
  
  1.3       +5 -5      jakarta-commons-sandbox/chain/src/test/org/apache/commons/chain/web/servlet/ServletGetLocaleCommandTestCase.java
  
  Index: ServletGetLocaleCommandTestCase.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons-sandbox/chain/src/test/org/apache/commons/chain/web/servlet/ServletGetLocaleCommandTestCase.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- ServletGetLocaleCommandTestCase.java	12 Aug 2003 20:33:25 -0000	1.2
  +++ ServletGetLocaleCommandTestCase.java	29 Sep 2003 06:02:14 -0000	1.3
  @@ -189,11 +189,11 @@
   
   	String localeKey = command.getLocaleKey();
   	assertNotNull(localeKey);
  -	Object value = context.getAttributes().get(localeKey);
  +	Object value = context.get(localeKey);
   	assertNull(value);
   	boolean result = command.execute(context);
   	assertFalse(result);
  -	value = context.getAttributes().get(localeKey);
  +	value = context.get(localeKey);
   	assertNotNull(value);
   	assertTrue(value instanceof Locale);
   	assertEquals(locale, (Locale) value);
  
  
  
  1.3       +6 -6      jakarta-commons-sandbox/chain/src/test/org/apache/commons/chain/web/servlet/ServletSetLocaleCommandTestCase.java
  
  Index: ServletSetLocaleCommandTestCase.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons-sandbox/chain/src/test/org/apache/commons/chain/web/servlet/ServletSetLocaleCommandTestCase.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- ServletSetLocaleCommandTestCase.java	12 Aug 2003 20:33:25 -0000	1.2
  +++ ServletSetLocaleCommandTestCase.java	29 Sep 2003 06:02:14 -0000	1.3
  @@ -188,10 +188,10 @@
   
   	String localeKey = command.getLocaleKey();
   	assertNotNull(localeKey);
  -	Object value = context.getAttributes().get(localeKey);
  +	Object value = context.get(localeKey);
   	assertNull(value);
  -	context.getAttributes().put(localeKey, locale);
  -	assertNotNull(context.getAttributes().get(localeKey));
  +	context.put(localeKey, locale);
  +	assertNotNull(context.get(localeKey));
   	assertNull(response.getLocale());
   	boolean result = command.execute(context);
   	assertFalse(result);
  
  
  
  1.3       +57 -21    jakarta-commons-sandbox/chain/src/test/org/apache/commons/chain/web/servlet/ServletWebContextTestCase.java
  
  Index: ServletWebContextTestCase.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons-sandbox/chain/src/test/org/apache/commons/chain/web/servlet/ServletWebContextTestCase.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- ServletWebContextTestCase.java	12 Aug 2003 20:33:25 -0000	1.2
  +++ ServletWebContextTestCase.java	29 Sep 2003 06:02:14 -0000	1.3
  @@ -64,6 +64,7 @@
   
   import junit.framework.Test;
   import junit.framework.TestSuite;
  +import org.apache.commons.chain.Context;
   import org.apache.commons.chain.impl.ContextBaseTestCase;
   import org.apache.commons.chain.web.WebContext;
   
  @@ -137,7 +138,7 @@
           ((MockHttpServletRequest) request).addParameter("pkey2", "pvalue2a");
           ((MockHttpServletRequest) request).addParameter("pkey2", "pvalue2b");
           response = new MockHttpServletResponse();
  -        context = new ServletWebContext(scontext, request, response);
  +        context = createContext();
       }
   
   
  @@ -214,6 +215,35 @@
       }
   
   
  +    // Test equals() and hashCode()
  +    // Copied from ContextBaseTestCase with customized creation of "other"
  +    public void testEquals() {
  +
  +        // FIXME - ServletWebContext needs a better equals()
  +
  +        // Compare to self
  +        assertTrue(context.equals(context));
  +        assertTrue(context.hashCode() == context.hashCode());
  +
  +        // Compare to equivalent instance
  +        Context other = new ServletWebContext(scontext, request, response);
  +        // assertTrue(context.equals(other));
  +        assertTrue(context.hashCode() == other.hashCode());
  +
  +        // Compare to non-equivalent instance - other modified
  +        other.put("bop", "bop value");
  +        // assertTrue(!context.equals(other));
  +        assertTrue(context.hashCode() != other.hashCode());
  +
  +        // Compare to non-equivalent instance - self modified
  +        other = new ServletWebContext(scontext, request, response);
  +        context.put("bop", "bop value");
  +        // assertTrue(!context.equals(other));
  +        assertTrue(context.hashCode() != other.hashCode());
  +
  +    }        
  +
  +
       // Test getHeader()
       public void testHeader() {
   
  @@ -477,21 +507,21 @@
   
           // Attribute-property transparency
           assertTrue(swcontext.getApplicationScope() ==
  -                     swcontext.getAttributes().get("applicationScope"));
  +                     swcontext.get("applicationScope"));
           assertTrue(swcontext.getHeader() ==
  -                     swcontext.getAttributes().get("header"));
  +                     swcontext.get("header"));
           assertTrue(swcontext.getHeaderValues() ==
  -                     swcontext.getAttributes().get("headerValues"));
  +                     swcontext.get("headerValues"));
           assertTrue(swcontext.getInitParam() ==
  -                     swcontext.getAttributes().get("initParam"));
  +                     swcontext.get("initParam"));
           assertTrue(swcontext.getParam() ==
  -                     swcontext.getAttributes().get("param"));
  +                     swcontext.get("param"));
           assertTrue(swcontext.getParamValues() ==
  -                     swcontext.getAttributes().get("paramValues"));
  +                     swcontext.get("paramValues"));
           assertTrue(swcontext.getRequestScope() ==
  -                     swcontext.getAttributes().get("requestScope"));
  +                     swcontext.get("requestScope"));
           assertTrue(swcontext.getSessionScope() ==
  -                     swcontext.getAttributes().get("sessionScope"));
  +                     swcontext.get("sessionScope"));
   
       }
   
  @@ -513,14 +543,14 @@
           assertNull(swcontext.getSessionScope());
   
           // Attributes should all be null
  -        assertNull(swcontext.getAttributes().get("applicationScope"));
  -        assertNull(swcontext.getAttributes().get("header"));
  -        assertNull(swcontext.getAttributes().get("headerValues"));
  -        assertNull(swcontext.getAttributes().get("initParam"));
  -        assertNull(swcontext.getAttributes().get("param"));
  -        assertNull(swcontext.getAttributes().get("paramValues"));
  -        assertNull(swcontext.getAttributes().get("requestScope"));
  -        assertNull(swcontext.getAttributes().get("sessionScope"));
  +        assertNull(swcontext.get("applicationScope"));
  +        assertNull(swcontext.get("header"));
  +        assertNull(swcontext.get("headerValues"));
  +        assertNull(swcontext.get("initParam"));
  +        assertNull(swcontext.get("param"));
  +        assertNull(swcontext.get("paramValues"));
  +        assertNull(swcontext.get("requestScope"));
  +        assertNull(swcontext.get("sessionScope"));
   
       }
   
  @@ -622,7 +652,7 @@
       }
   
   
  -    // -------------------------------------------------------- Utility Methods
  +    // ------------------------------------------------------- Protected Methods
   
   
       protected void checkMapSize(Map map, int size) {
  @@ -646,6 +676,12 @@
           assertEquals(size, nv);
           // Count the values
           assertEquals(size, map.values().size());
  +    }
  +
  +
  +    // Create a new instance of the appropriate Context type for this test case
  +    protected Context createContext() {
  +        return (new ServletWebContext(scontext, request, response));
       }
   
   
  
  
  

Re: cvs commit: jakarta-commons-sandbox/chain/src/test/org/apache/commons/chain/web/servlet ServletGetLocaleCommandTestCase.java ServletSetLocaleCommandTestCase.java ServletWebContextTestCase.java

Posted by "Craig R. McClanahan" <cr...@apache.org>.
Ted Husted wrote:

> craigmcc@apache.org wrote:
>
>>   Initial phase of switching to Context "is-a" Map instead of
>>   Context "has-a" Map.  There are some pretty interesting intricacies
>>   to implementing the entire Map contract.
>
>
> I moved my current development over this morning. It seemed to go 
> fine, except that I had a "isNew" method on the original. It's not a 
> property, but a utility method that tested properties. This being a 
> young project, I refactored the name to "newEntry" for now, and 
> everything fell into place. Of course, that wouldn't work for 
> everyone. I didn't try to figure out if there's a fix, so here's the 
> trace:
>
> Testcase: testAddPermit took 1.422 sec
>     Caused an ERROR
> Exception writing property 'new': Property 'new' is not writeable
> java.lang.UnsupportedOperationException: Exception writing property 
> 'new': Property 'new' is not writeable
>     at 
> org.apache.commons.chain.impl.ContextBase.writeProperty(ContextBase.java:629) 
>
>     at 
> org.apache.commons.chain.impl.ContextBase.put(ContextBase.java:361)
>     at 
> org.apache.commons.chain.impl.ContextBase.putAll(ContextBase.java:390)
>     at 
> us_ok_deq_wqdata.context.CpuPermitContext.<init>(CpuPermitContext.java:35) 
>
>     at 
> us_ok_deq_wqdata.dao.mock.MockCpuPermitDao.insert(MockCpuPermitDao.java:80) 
>
>     at 
> us_ok_deq_wqdata.command.PermitInsert.execute(PermitInsert.java:20)
>     at 
> us_ok_deq_wqdata.command.CpuPermitInsertTest.testAddPermit(CpuPermitInsertTest.java:17) 
>
>     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
>     at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
>     at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)

That's what you would get if you have isNew() without a setNew() on your 
Context implementation.

>
>
>>   FIXME:  Missing unit tests for ...
>
>
> I can work on these this afternoon.
>
>
> [related thread]
> > * For the property transparency thing:
>
> I haven't tried this yet, but will. To give the new Base a test, I 
> temporarily gave my properties member fields [gotta love those IDE 
> refactoring features :)]

In a "Context is-a Map" world I would likely be against having something 
like getField/setField -- the way that the Context implementation 
chooses to store its state information should be invisible outside the 
implementation class.

You'll also find that the attribute-property transparency really does 
work already, comes for free if you subclass ContextBase, and that it's 
quite cool :-).

>
> -Ted.

Craig



Re: cvs commit: jakarta-commons-sandbox/chain/src/test/org/apache/commons/chain/web/servlet ServletGetLocaleCommandTestCase.java ServletSetLocaleCommandTestCase.java ServletWebContextTestCase.java

Posted by "Craig R. McClanahan" <cr...@apache.org>.
Ted Husted wrote:

> craigmcc@apache.org wrote:
>
>>   Initial phase of switching to Context "is-a" Map instead of
>>   Context "has-a" Map.  There are some pretty interesting intricacies
>>   to implementing the entire Map contract.
>
>
> I moved my current development over this morning. It seemed to go 
> fine, except that I had a "isNew" method on the original. It's not a 
> property, but a utility method that tested properties. This being a 
> young project, I refactored the name to "newEntry" for now, and 
> everything fell into place. Of course, that wouldn't work for 
> everyone. I didn't try to figure out if there's a fix, so here's the 
> trace:
>
> Testcase: testAddPermit took 1.422 sec
>     Caused an ERROR
> Exception writing property 'new': Property 'new' is not writeable
> java.lang.UnsupportedOperationException: Exception writing property 
> 'new': Property 'new' is not writeable
>     at 
> org.apache.commons.chain.impl.ContextBase.writeProperty(ContextBase.java:629) 
>
>     at 
> org.apache.commons.chain.impl.ContextBase.put(ContextBase.java:361)
>     at 
> org.apache.commons.chain.impl.ContextBase.putAll(ContextBase.java:390)
>     at 
> us_ok_deq_wqdata.context.CpuPermitContext.<init>(CpuPermitContext.java:35) 
>
>     at 
> us_ok_deq_wqdata.dao.mock.MockCpuPermitDao.insert(MockCpuPermitDao.java:80) 
>
>     at 
> us_ok_deq_wqdata.command.PermitInsert.execute(PermitInsert.java:20)
>     at 
> us_ok_deq_wqdata.command.CpuPermitInsertTest.testAddPermit(CpuPermitInsertTest.java:17) 
>
>     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
>     at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
>     at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)

That's what you would get if you have isNew() without a setNew() on your 
Context implementation.

>
>
>>   FIXME:  Missing unit tests for ...
>
>
> I can work on these this afternoon.
>
>
> [related thread]
> > * For the property transparency thing:
>
> I haven't tried this yet, but will. To give the new Base a test, I 
> temporarily gave my properties member fields [gotta love those IDE 
> refactoring features :)]

In a "Context is-a Map" world I would likely be against having something 
like getField/setField -- the way that the Context implementation 
chooses to store its state information should be invisible outside the 
implementation class.

You'll also find that the attribute-property transparency really does 
work already, comes for free if you subclass ContextBase, and that it's 
quite cool :-).

>
> -Ted.

Craig



---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org


Re: cvs commit: jakarta-commons-sandbox/chain/src/test/org/apache/commons/chain/web/servlet ServletGetLocaleCommandTestCase.java ServletSetLocaleCommandTestCase.java ServletWebContextTestCase.java

Posted by Ted Husted <hu...@apache.org>.
craigmcc@apache.org wrote:
>   Initial phase of switching to Context "is-a" Map instead of
>   Context "has-a" Map.  There are some pretty interesting intricacies
>   to implementing the entire Map contract.

I moved my current development over this morning. It seemed to go fine, 
except that I had a "isNew" method on the original. It's not a property, 
but a utility method that tested properties. This being a young project, 
I refactored the name to "newEntry" for now, and everything fell into 
place. Of course, that wouldn't work for everyone. I didn't try to 
figure out if there's a fix, so here's the trace:

Testcase: testAddPermit took 1.422 sec
	Caused an ERROR
Exception writing property 'new': Property 'new' is not writeable
java.lang.UnsupportedOperationException: Exception writing property 
'new': Property 'new' is not writeable
	at 
org.apache.commons.chain.impl.ContextBase.writeProperty(ContextBase.java:629)
	at org.apache.commons.chain.impl.ContextBase.put(ContextBase.java:361)
	at org.apache.commons.chain.impl.ContextBase.putAll(ContextBase.java:390)
	at 
us_ok_deq_wqdata.context.CpuPermitContext.<init>(CpuPermitContext.java:35)
	at 
us_ok_deq_wqdata.dao.mock.MockCpuPermitDao.insert(MockCpuPermitDao.java:80)
	at us_ok_deq_wqdata.command.PermitInsert.execute(PermitInsert.java:20)
	at 
us_ok_deq_wqdata.command.CpuPermitInsertTest.testAddPermit(CpuPermitInsertTest.java:17)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)


>   FIXME:  Missing unit tests for ...

I can work on these this afternoon.


[related thread]
 > * For the property transparency thing:

I haven't tried this yet, but will. To give the new Base a test, I 
temporarily gave my properties member fields [gotta love those IDE 
refactoring features :)]

-Ted.









Re: cvs commit: jakarta-commons-sandbox/chain/src/test/org/apache/commons/chain/web/servlet ServletGetLocaleCommandTestCase.java ServletSetLocaleCommandTestCase.java ServletWebContextTestCase.java

Posted by Ted Husted <hu...@apache.org>.
craigmcc@apache.org wrote:
>   Initial phase of switching to Context "is-a" Map instead of
>   Context "has-a" Map.  There are some pretty interesting intricacies
>   to implementing the entire Map contract.

I moved my current development over this morning. It seemed to go fine, 
except that I had a "isNew" method on the original. It's not a property, 
but a utility method that tested properties. This being a young project, 
I refactored the name to "newEntry" for now, and everything fell into 
place. Of course, that wouldn't work for everyone. I didn't try to 
figure out if there's a fix, so here's the trace:

Testcase: testAddPermit took 1.422 sec
	Caused an ERROR
Exception writing property 'new': Property 'new' is not writeable
java.lang.UnsupportedOperationException: Exception writing property 
'new': Property 'new' is not writeable
	at 
org.apache.commons.chain.impl.ContextBase.writeProperty(ContextBase.java:629)
	at org.apache.commons.chain.impl.ContextBase.put(ContextBase.java:361)
	at org.apache.commons.chain.impl.ContextBase.putAll(ContextBase.java:390)
	at 
us_ok_deq_wqdata.context.CpuPermitContext.<init>(CpuPermitContext.java:35)
	at 
us_ok_deq_wqdata.dao.mock.MockCpuPermitDao.insert(MockCpuPermitDao.java:80)
	at us_ok_deq_wqdata.command.PermitInsert.execute(PermitInsert.java:20)
	at 
us_ok_deq_wqdata.command.CpuPermitInsertTest.testAddPermit(CpuPermitInsertTest.java:17)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)


>   FIXME:  Missing unit tests for ...

I can work on these this afternoon.


[related thread]
 > * For the property transparency thing:

I haven't tried this yet, but will. To give the new Base a test, I 
temporarily gave my properties member fields [gotta love those IDE 
refactoring features :)]

-Ted.









---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org