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