You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by gg...@apache.org on 2022/08/30 15:08:09 UTC

[commons-chain] branch master updated: Use standard Javadoc @since tag format

This is an automated email from the ASF dual-hosted git repository.

ggregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-chain.git


The following commit(s) were added to refs/heads/master by this push:
     new b5a968f  Use standard Javadoc @since tag format
b5a968f is described below

commit b5a968f123ff4eaddb7d10b8cad7d58abaed7b37
Author: Gary Gregory <gg...@rocketsoftware.com>
AuthorDate: Tue Aug 30 11:07:57 2022 -0400

    Use standard Javadoc @since tag format
---
 .../org/apache/commons/chain2/CatalogFactory.java  | 230 +++---
 .../java/org/apache/commons/chain2/Processing.java |  96 +--
 .../commons/chain2/base/DispatchCommand.java       | 382 +++++-----
 .../commons/chain2/base/DispatchLookupCommand.java | 488 ++++++-------
 .../apache/commons/chain2/base/LookupCommand.java  | 796 ++++++++++-----------
 .../apache/commons/chain2/impl/CatalogBase.java    | 286 ++++----
 .../apache/commons/chain2/web/ChainResources.java  | 308 ++++----
 .../org/apache/commons/chain2/web/WebContext.java  | 208 +++---
 .../commons/chain2/web/faces/FacesWebContext.java  | 464 ++++++------
 .../chain2/web/portlet/PortletWebContext.java      | 622 ++++++++--------
 .../commons/chain2/web/servlet/PathInfoMapper.java | 172 ++---
 .../chain2/web/servlet/RequestParameterMapper.java | 226 +++---
 .../chain2/web/servlet/ServletCookieMap.java       | 298 ++++----
 .../chain2/web/servlet/ServletPathMapper.java      | 186 ++---
 .../chain2/web/servlet/ServletWebContext.java      | 272 +++----
 15 files changed, 2517 insertions(+), 2517 deletions(-)

diff --git a/api/src/main/java/org/apache/commons/chain2/CatalogFactory.java b/api/src/main/java/org/apache/commons/chain2/CatalogFactory.java
index c58c6f8..804bd64 100644
--- a/api/src/main/java/org/apache/commons/chain2/CatalogFactory.java
+++ b/api/src/main/java/org/apache/commons/chain2/CatalogFactory.java
@@ -1,115 +1,115 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.chain2;
-
-import java.util.Iterator;
-import java.util.Map;
-
-/**
- * A <code>CatalogFactory</code> stores and retrieves catalogs. 
- * <p>
- * The factory allows for a default {@link Catalog} as well as Catalog's 
- * stored with a name key. It follows the Factory pattern (see GoF).
- * <p>
- * The base implementation provides command lookup based on a single
- * String. This String encodes both the catalog and command names.
- *
- * @param <K> the type of keys maintained by the context associated with this {@link Command}
- * @param <V> the type of mapped values
- * @param <C> Type of the context associated with this command
- *
- * @version $Id: CatalogFactory.java 1486528 2013-05-27 07:38:38Z simonetripodi $
- */
-public interface CatalogFactory<K, V, C extends Map<K, V>> {
-
-    /**
-     * <p>Values passed to the <code>getCommand(String)</code> method should
-     * use this as the delimiter between the "catalog" name and the "command"
-     * name.</p>
-     */
-    public static final String DELIMITER = ":";
-
-    /**
-     * <p>Gets the default instance of Catalog associated with the factory
-     * (if any); otherwise, return <code>null</code>.</p>
-     *
-     * @return the default Catalog instance
-     */
-    public abstract Catalog<K, V, C> getCatalog();
-
-    /**
-     * <p>Sets the default instance of Catalog associated with the factory.</p>
-     *
-     * @param catalog the default Catalog instance
-     */
-    public abstract void setCatalog(Catalog<K, V, C> catalog);
-
-    /**
-     * <p>Retrieves a Catalog instance by name (if any); otherwise
-     * return <code>null</code>.</p>
-     *
-     * @param name the name of the Catalog to retrieve
-     * @return the specified Catalog
-     */
-    public abstract Catalog<K, V, C> getCatalog(String name);
-
-    /**
-     * <p>Adds a named instance of Catalog to the factory (for subsequent
-     * retrieval later).</p>
-     *
-     * @param name the name of the Catalog to add
-     * @param catalog the Catalog to add
-     */
-    public abstract void addCatalog(String name, Catalog<K, V, C> catalog);
-
-    /**
-     * <p>Return an <code>Iterator</code> over the set of named
-     * {@link Catalog}s known to this instance.
-     * If there are no known catalogs, an empty Iterator is returned.</p>
-     * @return An Iterator of the names of the Catalogs known by this factory.
-     */
-    public abstract Iterator<String> getNames();
-
-    /**
-     * <p>Return a <code>Command</code> based on the given commandID.</p>
-     *
-     * <p>At this time, the structure of commandID is relatively simple:  if the
-     * commandID contains a DELIMITER, treat the segment of the commandID
-     * up to (but not including) the DELIMITER as the name of a catalog, and the
-     * segment following the DELIMITER as a command name within that catalog.
-     * If the commandID contains no DELIMITER, treat the commandID as the name
-     * of a command in the default catalog.</p>
-     *
-     * <p>To preserve the possibility of future extensions to this lookup
-     * mechanism, the DELIMITER string should be considered reserved, and
-     * should not be used in command names.  commandID values which contain
-     * more than one DELIMITER will cause an
-     * <code>IllegalArgumentException</code> to be thrown.</p>
-     *
-     * @param <CMD> the expected {@link Command} type to be returned
-     * @param commandID the identifier of the command to return
-     * @return the command located with commandID, or <code>null</code>
-     *  if either the command name or the catalog name cannot be resolved
-     * @throws IllegalArgumentException if the commandID contains more than
-     *  one DELIMITER
-     *
-     * @since Chain 1.1
-     */
-    public abstract <CMD extends Command<K, V, C>> CMD getCommand(
-            String commandID);
-
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.chain2;
+
+import java.util.Iterator;
+import java.util.Map;
+
+/**
+ * A <code>CatalogFactory</code> stores and retrieves catalogs. 
+ * <p>
+ * The factory allows for a default {@link Catalog} as well as Catalog's 
+ * stored with a name key. It follows the Factory pattern (see GoF).
+ * <p>
+ * The base implementation provides command lookup based on a single
+ * String. This String encodes both the catalog and command names.
+ *
+ * @param <K> the type of keys maintained by the context associated with this {@link Command}
+ * @param <V> the type of mapped values
+ * @param <C> Type of the context associated with this command
+ *
+ * @version $Id: CatalogFactory.java 1486528 2013-05-27 07:38:38Z simonetripodi $
+ */
+public interface CatalogFactory<K, V, C extends Map<K, V>> {
+
+    /**
+     * <p>Values passed to the <code>getCommand(String)</code> method should
+     * use this as the delimiter between the "catalog" name and the "command"
+     * name.</p>
+     */
+    public static final String DELIMITER = ":";
+
+    /**
+     * <p>Gets the default instance of Catalog associated with the factory
+     * (if any); otherwise, return <code>null</code>.</p>
+     *
+     * @return the default Catalog instance
+     */
+    public abstract Catalog<K, V, C> getCatalog();
+
+    /**
+     * <p>Sets the default instance of Catalog associated with the factory.</p>
+     *
+     * @param catalog the default Catalog instance
+     */
+    public abstract void setCatalog(Catalog<K, V, C> catalog);
+
+    /**
+     * <p>Retrieves a Catalog instance by name (if any); otherwise
+     * return <code>null</code>.</p>
+     *
+     * @param name the name of the Catalog to retrieve
+     * @return the specified Catalog
+     */
+    public abstract Catalog<K, V, C> getCatalog(String name);
+
+    /**
+     * <p>Adds a named instance of Catalog to the factory (for subsequent
+     * retrieval later).</p>
+     *
+     * @param name the name of the Catalog to add
+     * @param catalog the Catalog to add
+     */
+    public abstract void addCatalog(String name, Catalog<K, V, C> catalog);
+
+    /**
+     * <p>Return an <code>Iterator</code> over the set of named
+     * {@link Catalog}s known to this instance.
+     * If there are no known catalogs, an empty Iterator is returned.</p>
+     * @return An Iterator of the names of the Catalogs known by this factory.
+     */
+    public abstract Iterator<String> getNames();
+
+    /**
+     * <p>Return a <code>Command</code> based on the given commandID.</p>
+     *
+     * <p>At this time, the structure of commandID is relatively simple:  if the
+     * commandID contains a DELIMITER, treat the segment of the commandID
+     * up to (but not including) the DELIMITER as the name of a catalog, and the
+     * segment following the DELIMITER as a command name within that catalog.
+     * If the commandID contains no DELIMITER, treat the commandID as the name
+     * of a command in the default catalog.</p>
+     *
+     * <p>To preserve the possibility of future extensions to this lookup
+     * mechanism, the DELIMITER string should be considered reserved, and
+     * should not be used in command names.  commandID values which contain
+     * more than one DELIMITER will cause an
+     * <code>IllegalArgumentException</code> to be thrown.</p>
+     *
+     * @param <CMD> the expected {@link Command} type to be returned
+     * @param commandID the identifier of the command to return
+     * @return the command located with commandID, or <code>null</code>
+     *  if either the command name or the catalog name cannot be resolved
+     * @throws IllegalArgumentException if the commandID contains more than
+     *  one DELIMITER
+     *
+     * @since 1.1
+     */
+    public abstract <CMD extends Command<K, V, C>> CMD getCommand(
+            String commandID);
+
+}
diff --git a/api/src/main/java/org/apache/commons/chain2/Processing.java b/api/src/main/java/org/apache/commons/chain2/Processing.java
index 4400c47..84766b3 100644
--- a/api/src/main/java/org/apache/commons/chain2/Processing.java
+++ b/api/src/main/java/org/apache/commons/chain2/Processing.java
@@ -1,48 +1,48 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.chain2;
-
-/**
- * A <code>Processing</code> encapsulates states that can be returned by
- * commands. 
- * <p>
- * {@link Command}s should either return <code>FINISHED</code> if the
- * processing of the given context has been completed, or return
- * <code>CONTINUE</code> if the processing of the given {@link Context} should
- * be delegated to a subsequent command in an enclosing {@link Chain}.
- *
- * @version $Id $
- */
-public enum Processing {
-
-    /**
-     * Commands should return continue if the processing of the given 
-     * context should be delegated to a subsequent command in an enclosing chain.
-     *
-     * @since Chain 2.0
-     */
-    CONTINUE,
-
-    /**
-     * Commands should return finished if the processing of the given context
-     * has been completed.
-     *
-     * @since Chain 2.0
-     */
-    FINISHED;
-
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.chain2;
+
+/**
+ * A <code>Processing</code> encapsulates states that can be returned by
+ * commands. 
+ * <p>
+ * {@link Command}s should either return <code>FINISHED</code> if the
+ * processing of the given context has been completed, or return
+ * <code>CONTINUE</code> if the processing of the given {@link Context} should
+ * be delegated to a subsequent command in an enclosing {@link Chain}.
+ *
+ * @version $Id $
+ */
+public enum Processing {
+
+    /**
+     * Commands should return continue if the processing of the given 
+     * context should be delegated to a subsequent command in an enclosing chain.
+     *
+     * @since 2.0
+     */
+    CONTINUE,
+
+    /**
+     * Commands should return finished if the processing of the given context
+     * has been completed.
+     *
+     * @since 2.0
+     */
+    FINISHED;
+
+}
diff --git a/base/src/main/java/org/apache/commons/chain2/base/DispatchCommand.java b/base/src/main/java/org/apache/commons/chain2/base/DispatchCommand.java
index b7f044a..d9a97c5 100644
--- a/base/src/main/java/org/apache/commons/chain2/base/DispatchCommand.java
+++ b/base/src/main/java/org/apache/commons/chain2/base/DispatchCommand.java
@@ -1,191 +1,191 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.chain2.base;
-
-import org.apache.commons.chain2.Command;
-import org.apache.commons.chain2.Context;
-import org.apache.commons.chain2.Processing;
-
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.util.Map;
-import java.util.WeakHashMap;
-
-/**
- * An abstract base command which uses introspection to look up a method to execute.
- * For use by developers who prefer to group related functionality into a single class
- * rather than an inheritance family.
- *
- * @param <K> the type of keys maintained by the context associated with this command
- * @param <V> the type of mapped values
- * @param <C> Type of the context associated with this command
- *
- * @since Chain 1.1
- */
-public abstract class DispatchCommand<K, V, C extends Context<K, V>> implements Command<K, V, C> {
-
-    /** Cache of methods */
-    private final Map<String, Method> methods = new WeakHashMap<String, Method>();
-
-    /** Method name */
-    private String method = null;
-
-    /** Method key */
-    private String methodKey = null;
-
-    /**
-     * The base implementation expects dispatch methods to take a <code>Context</code>
-     * as their only argument.
-     */
-    protected static final Class<?>[] DEFAULT_SIGNATURE = new Class<?>[] {Context.class};
-
-    /**
-     * Look up the method specified by either "method" or "methodKey" and invoke it,
-     * returning a {@link Processing} value as interpreted by <code>evaluateResult</code>.
-     * @param context The Context to be processed by this Command.
-     * @return the result of method being dispatched to.
-     * @throws IllegalStateException if neither 'method' nor 'methodKey' properties are defined
-     * @throws DispatchException if any is thrown by the invocation. Note that if invoking the method
-     * results in an InvocationTargetException, the cause of that exception is thrown instead of
-     * the exception itself, unless the cause is an <code>Error</code> or other <code>Throwable</code>
-     * which is not an <code>Exception</code>.
-     */
-    public Processing execute(C context) {
-        if (this.getMethod() == null && this.getMethodKey() == null) {
-            throw new IllegalStateException("Neither 'method' nor 'methodKey' properties are defined ");
-        }
-
-        try {
-            Method methodObject = extractMethod(context);
-            return evaluateResult(methodObject.invoke(this,
-                    getArguments(context)));
-
-        } catch (NoSuchMethodException e) {
-            throw new DispatchException("Error extracting method from context", e, context, this);
-        } catch (IllegalAccessException e) {
-            throw new DispatchException("Error accessing method", e, context, this);
-        } catch (InvocationTargetException e) {
-            Throwable cause = e.getTargetException();
-            throw new DispatchException("Error in reflected dispatched command", cause, context, this);
-        }
-    }
-
-    /**
-     * Extract the dispatch method.  The base implementation uses the command's
-     * <code>method</code> property as the name of a method to look up, or, if that is not defined,
-     * looks up the the method name in the Context using the <code>methodKey</code>.
-     *
-     * @param context The Context being processed by this Command.
-     * @return The method to execute
-     * @throws NoSuchMethodException if no method can be found under the specified name.
-     * @throws NullPointerException if no methodName cannot be determined
-     */
-    protected Method extractMethod(C context) throws NoSuchMethodException {
-        String methodName = this.getMethod();
-
-        if (methodName == null) {
-            Object methodContextObj = context.get(this.getMethodKey());
-            if (methodContextObj == null) {
-                throw new NullPointerException("No value found in context under " + this.getMethodKey());
-            }
-            methodName = methodContextObj.toString();
-        }
-
-        Method theMethod = null;
-
-        synchronized (methods) {
-            theMethod = methods.get(methodName);
-
-            if (theMethod == null) {
-                theMethod = getClass().getMethod(methodName, getSignature());
-                methods.put(methodName, theMethod);
-            }
-        }
-
-        return theMethod;
-    }
-
-    /**
-     * Evaluate the result of the method invocation as a processing value. Base implementation
-     * expects that the invoked method returns processing, but subclasses might
-     * implement other interpretations.
-     * @param obj The result of the method execution
-     * @return The evaluated result/
-     */
-    protected Processing evaluateResult(Object obj) {
-        if(obj instanceof Processing) {
-            Processing result = (Processing) obj;
-            return result;
-        } else {
-            return Processing.CONTINUE;
-        }
-    }
-
-    /**
-     * Return a <code>Class[]</code> describing the expected signature of the method.
-     * @return The method signature.
-     */
-    protected Class<?>[] getSignature() {
-        return DEFAULT_SIGNATURE;
-    }
-
-    /**
-     * Get the arguments to be passed into the dispatch method.
-     * Default implementation simply returns the context which was passed in, but subclasses
-     * could use this to wrap the context in some other type, or extract key values from the
-     * context to pass in.  The length and types of values returned by this must coordinate
-     * with the return value of <code>getSignature()</code>
-     * @param context The Context being processed by this Command.
-     * @return The method arguments.
-     */
-    protected Object[] getArguments(C context) {
-        return new Object[] {context};
-    }
-
-    /**
-     * Return the method name.
-     * @return The method name.
-     */
-    public String getMethod() {
-        return method;
-    }
-
-    /**
-     * Return the Context key for the method name.
-     * @return The Context key for the method name.
-     */
-    public String getMethodKey() {
-        return methodKey;
-    }
-
-    /**
-     * Set the method name.
-     * @param method The method name.
-     */
-    public void setMethod(String method) {
-        this.method = method;
-    }
-
-    /**
-     * Set the Context key for the method name.
-     * @param methodKey The Context key for the method name.
-     */
-    public void setMethodKey(String methodKey) {
-        this.methodKey = methodKey;
-    }
-
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.chain2.base;
+
+import org.apache.commons.chain2.Command;
+import org.apache.commons.chain2.Context;
+import org.apache.commons.chain2.Processing;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Map;
+import java.util.WeakHashMap;
+
+/**
+ * An abstract base command which uses introspection to look up a method to execute.
+ * For use by developers who prefer to group related functionality into a single class
+ * rather than an inheritance family.
+ *
+ * @param <K> the type of keys maintained by the context associated with this command
+ * @param <V> the type of mapped values
+ * @param <C> Type of the context associated with this command
+ *
+ * @since 1.1
+ */
+public abstract class DispatchCommand<K, V, C extends Context<K, V>> implements Command<K, V, C> {
+
+    /** Cache of methods */
+    private final Map<String, Method> methods = new WeakHashMap<String, Method>();
+
+    /** Method name */
+    private String method = null;
+
+    /** Method key */
+    private String methodKey = null;
+
+    /**
+     * The base implementation expects dispatch methods to take a <code>Context</code>
+     * as their only argument.
+     */
+    protected static final Class<?>[] DEFAULT_SIGNATURE = new Class<?>[] {Context.class};
+
+    /**
+     * Look up the method specified by either "method" or "methodKey" and invoke it,
+     * returning a {@link Processing} value as interpreted by <code>evaluateResult</code>.
+     * @param context The Context to be processed by this Command.
+     * @return the result of method being dispatched to.
+     * @throws IllegalStateException if neither 'method' nor 'methodKey' properties are defined
+     * @throws DispatchException if any is thrown by the invocation. Note that if invoking the method
+     * results in an InvocationTargetException, the cause of that exception is thrown instead of
+     * the exception itself, unless the cause is an <code>Error</code> or other <code>Throwable</code>
+     * which is not an <code>Exception</code>.
+     */
+    public Processing execute(C context) {
+        if (this.getMethod() == null && this.getMethodKey() == null) {
+            throw new IllegalStateException("Neither 'method' nor 'methodKey' properties are defined ");
+        }
+
+        try {
+            Method methodObject = extractMethod(context);
+            return evaluateResult(methodObject.invoke(this,
+                    getArguments(context)));
+
+        } catch (NoSuchMethodException e) {
+            throw new DispatchException("Error extracting method from context", e, context, this);
+        } catch (IllegalAccessException e) {
+            throw new DispatchException("Error accessing method", e, context, this);
+        } catch (InvocationTargetException e) {
+            Throwable cause = e.getTargetException();
+            throw new DispatchException("Error in reflected dispatched command", cause, context, this);
+        }
+    }
+
+    /**
+     * Extract the dispatch method.  The base implementation uses the command's
+     * <code>method</code> property as the name of a method to look up, or, if that is not defined,
+     * looks up the the method name in the Context using the <code>methodKey</code>.
+     *
+     * @param context The Context being processed by this Command.
+     * @return The method to execute
+     * @throws NoSuchMethodException if no method can be found under the specified name.
+     * @throws NullPointerException if no methodName cannot be determined
+     */
+    protected Method extractMethod(C context) throws NoSuchMethodException {
+        String methodName = this.getMethod();
+
+        if (methodName == null) {
+            Object methodContextObj = context.get(this.getMethodKey());
+            if (methodContextObj == null) {
+                throw new NullPointerException("No value found in context under " + this.getMethodKey());
+            }
+            methodName = methodContextObj.toString();
+        }
+
+        Method theMethod = null;
+
+        synchronized (methods) {
+            theMethod = methods.get(methodName);
+
+            if (theMethod == null) {
+                theMethod = getClass().getMethod(methodName, getSignature());
+                methods.put(methodName, theMethod);
+            }
+        }
+
+        return theMethod;
+    }
+
+    /**
+     * Evaluate the result of the method invocation as a processing value. Base implementation
+     * expects that the invoked method returns processing, but subclasses might
+     * implement other interpretations.
+     * @param obj The result of the method execution
+     * @return The evaluated result/
+     */
+    protected Processing evaluateResult(Object obj) {
+        if(obj instanceof Processing) {
+            Processing result = (Processing) obj;
+            return result;
+        } else {
+            return Processing.CONTINUE;
+        }
+    }
+
+    /**
+     * Return a <code>Class[]</code> describing the expected signature of the method.
+     * @return The method signature.
+     */
+    protected Class<?>[] getSignature() {
+        return DEFAULT_SIGNATURE;
+    }
+
+    /**
+     * Get the arguments to be passed into the dispatch method.
+     * Default implementation simply returns the context which was passed in, but subclasses
+     * could use this to wrap the context in some other type, or extract key values from the
+     * context to pass in.  The length and types of values returned by this must coordinate
+     * with the return value of <code>getSignature()</code>
+     * @param context The Context being processed by this Command.
+     * @return The method arguments.
+     */
+    protected Object[] getArguments(C context) {
+        return new Object[] {context};
+    }
+
+    /**
+     * Return the method name.
+     * @return The method name.
+     */
+    public String getMethod() {
+        return method;
+    }
+
+    /**
+     * Return the Context key for the method name.
+     * @return The Context key for the method name.
+     */
+    public String getMethodKey() {
+        return methodKey;
+    }
+
+    /**
+     * Set the method name.
+     * @param method The method name.
+     */
+    public void setMethod(String method) {
+        this.method = method;
+    }
+
+    /**
+     * Set the Context key for the method name.
+     * @param methodKey The Context key for the method name.
+     */
+    public void setMethodKey(String methodKey) {
+        this.methodKey = methodKey;
+    }
+
+}
diff --git a/base/src/main/java/org/apache/commons/chain2/base/DispatchLookupCommand.java b/base/src/main/java/org/apache/commons/chain2/base/DispatchLookupCommand.java
index c9d5619..936c265 100644
--- a/base/src/main/java/org/apache/commons/chain2/base/DispatchLookupCommand.java
+++ b/base/src/main/java/org/apache/commons/chain2/base/DispatchLookupCommand.java
@@ -1,244 +1,244 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.chain2.base;
-
-import org.apache.commons.chain2.CatalogFactory;
-import org.apache.commons.chain2.Command;
-import org.apache.commons.chain2.Context;
-import org.apache.commons.chain2.Filter;
-import org.apache.commons.chain2.Processing;
-
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.util.WeakHashMap;
-
-/**
- * <p>This command combines elements of the {@link LookupCommand} with the
- * {@link DispatchCommand}.  Look up a specified {@link Command} (which could
- * also be a {@link org.apache.commons.chain2.Chain}) in a
- * {@link org.apache.commons.chain2.Catalog}, and delegate execution to
- * it.  Introspection is used to lookup the appropriate method to delegate
- * execution to.  If the delegated-to {@link Command} is also a
- * {@link Filter}, its <code>postprocess()</code> method will also be invoked
- * at the appropriate time.</p>
- *
- * <p>The name of the {@link Command} can be specified either directly (via
- * the <code>name</code> property) or indirectly (via the <code>nameKey</code>
- * property).  Exactly one of these must be set.</p>
- *
- * <p>The name of the method to be called can be specified either directly
- * (via the <code>method</code> property) or indirectly (via the <code>
- * methodKey</code> property).  Exactly one of these must be set.</p>
- *
- * <p>If the <code>optional</code> property is set to <code>true</code>,
- * failure to find the specified command in the specified catalog will be
- * silently ignored.  Otherwise, a lookup failure will trigger an
- * <code>IllegalArgumentException</code>.</p>
- *
- * @param <K> the type of keys maintained by the context associated with this catalog
- * @param <V> the type of mapped values
- * @param <C> Type of the context associated with this command
- *
- * @since Chain 1.1
- */
-public class DispatchLookupCommand<K, V, C extends Context<K, V>>
-    extends LookupCommand<K, V, C> implements Filter<K, V, C> {
-
-    // -------------------------------------------------------------- Constructors
-
-    /**
-     * Create an instance with an unspecified <code>catalogFactory</code> property.
-     * This property can be set later using <code>setProperty</code>, or if it is not set,
-     * the static singleton instance from <code>CatalogFactory.getInstance()</code> will be used.
-     */
-    public DispatchLookupCommand() {  }
-
-    /**
-     * Create an instance and initialize the <code>catalogFactory</code> property
-     * to given <code>factory</code>.
-     * @param factory The Catalog Factory.
-     */
-    public DispatchLookupCommand(CatalogFactory<K, V, C> factory) {
-        super(factory);
-    }
-
-    // ------------------------------------------------------- Static Variables
-
-    /**
-     * The base implementation expects dispatch methods to take a <code>
-     * Context</code> as their only argument.
-     */
-    private static final Class<?>[] DEFAULT_SIGNATURE = new Class<?>[] {Context.class};
-
-    // ----------------------------------------------------- Instance Variables
-
-    private final WeakHashMap<String, Method> methods = new WeakHashMap<String, Method>();
-
-    // ------------------------------------------------------------- Properties
-
-    private String method = null;
-
-    private String methodKey = null;
-
-    /**
-     * Return the method name.
-     * @return The method name.
-     */
-    public String getMethod() {
-        return method;
-    }
-
-    /**
-     * Return the Context key for the method name.
-     * @return The Context key for the method name.
-     */
-    public String getMethodKey() {
-        return methodKey;
-    }
-
-    /**
-     * Set the method name.
-     * @param method The method name.
-     */
-    public void setMethod(String method) {
-        this.method = method;
-    }
-
-    /**
-     * Set the Context key for the method name.
-     * @param methodKey The Context key for the method name.
-     */
-    public void setMethodKey(String methodKey) {
-        this.methodKey = methodKey;
-    }
-
-    // --------------------------------------------------------- Public Methods
-
-    /**
-     * <p>Look up the specified command, and (if found) execute it.</p>
-     *
-     * @param context The context for this request
-     * @return the result of executing the looked-up command's method, or
-     * {@link Processing#CONTINUE} if no command is found.
-     *
-     * @throws DispatchException if no such {@link Command} can be found and the
-     *  <code>optional</code> property is set to <code>false</code>
-     */
-    @Override
-    public Processing execute(C context) {
-        if (this.getMethod() == null && this.getMethodKey() == null) {
-            throw new IllegalStateException("Neither 'method' nor 'methodKey' properties are defined");
-        }
-
-        Command<K, V, C> command = getCommand(context);
-
-        if (command != null) {
-            try {
-                Method methodObject = extractMethod(command, context);
-                Object obj = methodObject.invoke(command, getArguments(context));
-                
-                if(obj instanceof Processing) {
-                    Processing result = (Processing) obj;
-                    return result;
-                } else {
-                    return Processing.CONTINUE;
-                }
-            } catch (NoSuchMethodException e) {
-                throw new DispatchException("Error extracting method from context", e, context, this);
-            } catch (IllegalAccessException e) {
-                throw new DispatchException("Error accessing method", e, context, this);
-            } catch (InvocationTargetException e) {
-                Throwable cause = e.getTargetException();
-                throw new DispatchException("Error in reflected dispatched command", cause, context, this);
-            }
-        }
-        return Processing.CONTINUE;
-    }
-
-    // ------------------------------------------------------ Protected Methods
-
-    /**
-     * <p>Return a <code>Class[]</code> describing the expected signature of
-     * the method.  The default is a signature that just accepts the command's
-     * {@link Context}.  The method can be overidden to provide a different
-     * method signature.<p>
-     *
-     * @return the expected method signature
-     */
-    protected Class<?>[] getSignature() {
-        return DEFAULT_SIGNATURE;
-    }
-
-    /**
-     * Get the arguments to be passed into the dispatch method.
-     * Default implementation simply returns the context which was passed in,
-     * but subclasses could use this to wrap the context in some other type,
-     * or extract key values from the context to pass in.  The length and types
-     * of values returned by this must coordinate with the return value of
-     * <code>getSignature()</code>
-     *
-     * @param context The context associated with the request
-     * @return the method arguments to be used
-     */
-    protected Object[] getArguments(C context) {
-        return new Object[] {context};
-    }
-
-    // -------------------------------------------------------- Private Methods
-
-    /**
-     * Extract the dispatch method.  The base implementation uses the
-     * command's <code>method</code> property at the name of a method
-     * to look up, or, if that is not defined, uses the <code>
-     * methodKey</code> to lookup the method name in the context.
-     *
-     * @param command The commmand that contains the method to be
-     *    executed.
-     * @param context The context associated with this request
-     * @return the dispatch method
-     *
-     * @throws NoSuchMethodException if no method can be found under the
-     *    specified name.
-     * @throws NullPointerException if no methodName can be determined
-     */
-    private Method extractMethod(Command<K, V, C> command, C context) throws NoSuchMethodException {
-        String methodName = this.getMethod();
-
-        if (methodName == null) {
-            Object methodContextObj = context.get(getMethodKey());
-            if (methodContextObj == null) {
-                throw new NullPointerException("No value found in context under " + getMethodKey());
-            }
-            methodName = methodContextObj.toString();
-        }
-
-        Method theMethod = null;
-
-        synchronized (methods) {
-            theMethod = methods.get(methodName);
-
-            if (theMethod == null) {
-                theMethod = command.getClass().getMethod(methodName,
-                                                         getSignature());
-                methods.put(methodName, theMethod);
-            }
-        }
-
-        return theMethod;
-    }
-
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.chain2.base;
+
+import org.apache.commons.chain2.CatalogFactory;
+import org.apache.commons.chain2.Command;
+import org.apache.commons.chain2.Context;
+import org.apache.commons.chain2.Filter;
+import org.apache.commons.chain2.Processing;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.WeakHashMap;
+
+/**
+ * <p>This command combines elements of the {@link LookupCommand} with the
+ * {@link DispatchCommand}.  Look up a specified {@link Command} (which could
+ * also be a {@link org.apache.commons.chain2.Chain}) in a
+ * {@link org.apache.commons.chain2.Catalog}, and delegate execution to
+ * it.  Introspection is used to lookup the appropriate method to delegate
+ * execution to.  If the delegated-to {@link Command} is also a
+ * {@link Filter}, its <code>postprocess()</code> method will also be invoked
+ * at the appropriate time.</p>
+ *
+ * <p>The name of the {@link Command} can be specified either directly (via
+ * the <code>name</code> property) or indirectly (via the <code>nameKey</code>
+ * property).  Exactly one of these must be set.</p>
+ *
+ * <p>The name of the method to be called can be specified either directly
+ * (via the <code>method</code> property) or indirectly (via the <code>
+ * methodKey</code> property).  Exactly one of these must be set.</p>
+ *
+ * <p>If the <code>optional</code> property is set to <code>true</code>,
+ * failure to find the specified command in the specified catalog will be
+ * silently ignored.  Otherwise, a lookup failure will trigger an
+ * <code>IllegalArgumentException</code>.</p>
+ *
+ * @param <K> the type of keys maintained by the context associated with this catalog
+ * @param <V> the type of mapped values
+ * @param <C> Type of the context associated with this command
+ *
+ * @since 1.1
+ */
+public class DispatchLookupCommand<K, V, C extends Context<K, V>>
+    extends LookupCommand<K, V, C> implements Filter<K, V, C> {
+
+    // -------------------------------------------------------------- Constructors
+
+    /**
+     * Create an instance with an unspecified <code>catalogFactory</code> property.
+     * This property can be set later using <code>setProperty</code>, or if it is not set,
+     * the static singleton instance from <code>CatalogFactory.getInstance()</code> will be used.
+     */
+    public DispatchLookupCommand() {  }
+
+    /**
+     * Create an instance and initialize the <code>catalogFactory</code> property
+     * to given <code>factory</code>.
+     * @param factory The Catalog Factory.
+     */
+    public DispatchLookupCommand(CatalogFactory<K, V, C> factory) {
+        super(factory);
+    }
+
+    // ------------------------------------------------------- Static Variables
+
+    /**
+     * The base implementation expects dispatch methods to take a <code>
+     * Context</code> as their only argument.
+     */
+    private static final Class<?>[] DEFAULT_SIGNATURE = new Class<?>[] {Context.class};
+
+    // ----------------------------------------------------- Instance Variables
+
+    private final WeakHashMap<String, Method> methods = new WeakHashMap<String, Method>();
+
+    // ------------------------------------------------------------- Properties
+
+    private String method = null;
+
+    private String methodKey = null;
+
+    /**
+     * Return the method name.
+     * @return The method name.
+     */
+    public String getMethod() {
+        return method;
+    }
+
+    /**
+     * Return the Context key for the method name.
+     * @return The Context key for the method name.
+     */
+    public String getMethodKey() {
+        return methodKey;
+    }
+
+    /**
+     * Set the method name.
+     * @param method The method name.
+     */
+    public void setMethod(String method) {
+        this.method = method;
+    }
+
+    /**
+     * Set the Context key for the method name.
+     * @param methodKey The Context key for the method name.
+     */
+    public void setMethodKey(String methodKey) {
+        this.methodKey = methodKey;
+    }
+
+    // --------------------------------------------------------- Public Methods
+
+    /**
+     * <p>Look up the specified command, and (if found) execute it.</p>
+     *
+     * @param context The context for this request
+     * @return the result of executing the looked-up command's method, or
+     * {@link Processing#CONTINUE} if no command is found.
+     *
+     * @throws DispatchException if no such {@link Command} can be found and the
+     *  <code>optional</code> property is set to <code>false</code>
+     */
+    @Override
+    public Processing execute(C context) {
+        if (this.getMethod() == null && this.getMethodKey() == null) {
+            throw new IllegalStateException("Neither 'method' nor 'methodKey' properties are defined");
+        }
+
+        Command<K, V, C> command = getCommand(context);
+
+        if (command != null) {
+            try {
+                Method methodObject = extractMethod(command, context);
+                Object obj = methodObject.invoke(command, getArguments(context));
+                
+                if(obj instanceof Processing) {
+                    Processing result = (Processing) obj;
+                    return result;
+                } else {
+                    return Processing.CONTINUE;
+                }
+            } catch (NoSuchMethodException e) {
+                throw new DispatchException("Error extracting method from context", e, context, this);
+            } catch (IllegalAccessException e) {
+                throw new DispatchException("Error accessing method", e, context, this);
+            } catch (InvocationTargetException e) {
+                Throwable cause = e.getTargetException();
+                throw new DispatchException("Error in reflected dispatched command", cause, context, this);
+            }
+        }
+        return Processing.CONTINUE;
+    }
+
+    // ------------------------------------------------------ Protected Methods
+
+    /**
+     * <p>Return a <code>Class[]</code> describing the expected signature of
+     * the method.  The default is a signature that just accepts the command's
+     * {@link Context}.  The method can be overidden to provide a different
+     * method signature.<p>
+     *
+     * @return the expected method signature
+     */
+    protected Class<?>[] getSignature() {
+        return DEFAULT_SIGNATURE;
+    }
+
+    /**
+     * Get the arguments to be passed into the dispatch method.
+     * Default implementation simply returns the context which was passed in,
+     * but subclasses could use this to wrap the context in some other type,
+     * or extract key values from the context to pass in.  The length and types
+     * of values returned by this must coordinate with the return value of
+     * <code>getSignature()</code>
+     *
+     * @param context The context associated with the request
+     * @return the method arguments to be used
+     */
+    protected Object[] getArguments(C context) {
+        return new Object[] {context};
+    }
+
+    // -------------------------------------------------------- Private Methods
+
+    /**
+     * Extract the dispatch method.  The base implementation uses the
+     * command's <code>method</code> property at the name of a method
+     * to look up, or, if that is not defined, uses the <code>
+     * methodKey</code> to lookup the method name in the context.
+     *
+     * @param command The commmand that contains the method to be
+     *    executed.
+     * @param context The context associated with this request
+     * @return the dispatch method
+     *
+     * @throws NoSuchMethodException if no method can be found under the
+     *    specified name.
+     * @throws NullPointerException if no methodName can be determined
+     */
+    private Method extractMethod(Command<K, V, C> command, C context) throws NoSuchMethodException {
+        String methodName = this.getMethod();
+
+        if (methodName == null) {
+            Object methodContextObj = context.get(getMethodKey());
+            if (methodContextObj == null) {
+                throw new NullPointerException("No value found in context under " + getMethodKey());
+            }
+            methodName = methodContextObj.toString();
+        }
+
+        Method theMethod = null;
+
+        synchronized (methods) {
+            theMethod = methods.get(methodName);
+
+            if (theMethod == null) {
+                theMethod = command.getClass().getMethod(methodName,
+                                                         getSignature());
+                methods.put(methodName, theMethod);
+            }
+        }
+
+        return theMethod;
+    }
+
+}
diff --git a/base/src/main/java/org/apache/commons/chain2/base/LookupCommand.java b/base/src/main/java/org/apache/commons/chain2/base/LookupCommand.java
index be7cf76..1fca4de 100644
--- a/base/src/main/java/org/apache/commons/chain2/base/LookupCommand.java
+++ b/base/src/main/java/org/apache/commons/chain2/base/LookupCommand.java
@@ -1,398 +1,398 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.chain2.base;
-
-import org.apache.commons.chain2.Catalog;
-import org.apache.commons.chain2.CatalogFactory;
-import org.apache.commons.chain2.Command;
-import org.apache.commons.chain2.Context;
-import org.apache.commons.chain2.Filter;
-import org.apache.commons.chain2.Processing;
-import org.apache.commons.chain2.impl.CatalogFactoryBase;
-
-import java.util.Map;
-
-/**
- * <p>Look up a specified {@link Command} (which could also be a
- * {@link org.apache.commons.chain2.Chain})
- * in a {@link Catalog}, and delegate execution to it.  If the delegated-to
- * {@link Command} is also a {@link Filter}, its <code>postprocess()</code>
- * method will also be invoked at the appropriate time.</p>
- *
- * <p>The name of the {@link Command} can be specified either directly (via
- * the <code>name</code> property) or indirectly (via the <code>nameKey</code>
- * property).  Exactly one of these must be set.</p>
- *
- * <p>If the <code>optional</code> property is set to <code>true</code>,
- * failure to find the specified command in the specified catalog will be
- * silently ignored.  Otherwise, a lookup failure will trigger an
- * <code>IllegalArgumentException</code>.</p>
- *
- * @param <K> Context key type
- * @param <V> Context value type
- * @param <C> Type of the context associated with this command
- *
- */
-public class LookupCommand<K, V, C extends Map<K, V>> implements Filter<K, V, C> {
-
-    // -------------------------------------------------------------- Constructors
-
-    /**
-     * Create an instance, setting its <code>catalogFactory</code> property to the
-     * value of <code>CatalogFactory.getInstance()</code>.
-     *
-     * @since Chain 1.1
-     */
-    public LookupCommand() {
-        this(CatalogFactoryBase.<K, V, C>getInstance());
-    }
-
-    /**
-     * Create an instance and initialize the <code>catalogFactory</code> property
-     * to given <code>factory</code>/
-     *
-     * @param factory The Catalog Factory.
-     *
-     * @since Chain 1.1
-     */
-    public LookupCommand(CatalogFactory<K, V, C> factory) {
-        this.catalogFactory = factory;
-    }
-
-    // -------------------------------------------------------------- Properties
-
-    private CatalogFactory<K, V, C> catalogFactory = null;
-
-    /**
-     * <p>Set the {@link CatalogFactoryBase} from which lookups will be
-     * performed.</p>
-     *
-     * @param catalogFactory The Catalog Factory.
-     *
-     * @since Chain 1.1
-     */
-    public void setCatalogFactory(CatalogFactory<K, V, C> catalogFactory) {
-        this.catalogFactory = catalogFactory;
-    }
-
-    /**
-     * Return the {@link CatalogFactoryBase} from which lookups will be performed.
-     * @return The Catalog factory.
-     *
-     * @since Chain 1.1
-     */
-    public CatalogFactory<K, V, C> getCatalogFactory() {
-        return this.catalogFactory;
-    }
-
-    private String catalogName = null;
-
-    /**
-     * <p>Return the name of the {@link Catalog} to be searched, or
-     * <code>null</code> to search the default {@link Catalog}.</p>
-     * @return The Catalog name.
-     */
-    public String getCatalogName() {
-        return this.catalogName;
-    }
-
-    /**
-     * <p>Set the name of the {@link Catalog} to be searched, or
-     * <code>null</code> to search the default {@link Catalog}.</p>
-     *
-     * @param catalogName The new {@link Catalog} name or <code>null</code>
-     */
-    public void setCatalogName(String catalogName) {
-        this.catalogName = catalogName;
-    }
-
-    private String name = null;
-
-    /**
-     * <p>Return the name of the {@link Command} that we will look up and
-     * delegate execution to.</p>
-     * @return The name of the Command.
-     */
-    public String getName() {
-        return this.name;
-    }
-
-    /**
-     * <p>Set the name of the {@link Command} that we will look up and
-     * delegate execution to.</p>
-     *
-     * @param name The new command name
-     */
-    public void setName(String name) {
-        this.name = name;
-    }
-
-    private String nameKey = null;
-
-    /**
-     * <p>Return the context attribute key under which the {@link Command}
-     * name is stored.</p>
-     * @return The context key of the Command.
-     */
-    public String getNameKey() {
-        return this.nameKey;
-    }
-
-    /**
-     * <p>Set the context attribute key under which the {@link Command}
-     * name is stored.</p>
-     *
-     * @param nameKey The new context attribute key
-     */
-    public void setNameKey(String nameKey) {
-        this.nameKey = nameKey;
-    }
-
-    private boolean optional = false;
-
-    /**
-     * <p>Return <code>true</code> if locating the specified command
-     * is optional.</p>
-     * @return <code>true</code> if the Command is optional.
-     */
-    public boolean isOptional() {
-        return this.optional;
-    }
-
-    /**
-     * <p>Set the optional flag for finding the specified command.</p>
-     *
-     * @param optional The new optional flag
-     */
-    public void setOptional(boolean optional) {
-        this.optional = optional;
-    }
-
-    private boolean ignoreExecuteResult = false;
-
-    /**
-     * <p>Return <code>true</code> if this command should ignore
-     * the return value from executing the looked-up command.
-     * Defaults to <code>false</code>, which means that the return result
-     * of executing this lookup will be whatever is returned from that
-     * command.</p>
-     * @return <code>true</code> if result of the looked up Command
-     * should be ignored.
-     *
-     * @since Chain 1.1
-     */
-    public boolean isIgnoreExecuteResult() {
-        return ignoreExecuteResult;
-    }
-
-    /**
-     * <p>Set the rules for whether or not this class will ignore or
-     * pass through the value returned from executing the looked up
-     * command.</p>
-     * <p>If you are looking up a chain which may be "aborted" and
-     * you do not want this class to stop chain processing, then this
-     * value should be set to <code>true</code></p>
-     * @param ignoreReturn <code>true</code> if result of the
-     * looked up Command should be ignored.
-     *
-     * @since Chain 1.1
-     */
-    public void setIgnoreExecuteResult(boolean ignoreReturn) {
-        this.ignoreExecuteResult = ignoreReturn;
-    }
-
-    private boolean ignorePostprocessResult = false;
-
-    /**
-     * <p>Return <code>true</code> if this command is a Filter and
-     * should ignore the return value from executing the looked-up Filter's
-     * <code>postprocess()</code> method.
-     * Defaults to <code>false</code>, which means that the return result
-     * of executing this lookup will be whatever is returned from that
-     * Filter.</p>
-     * @return <code>true</code> if result of the looked up Filter's
-     * <code>postprocess()</code> method should be ignored.
-     *
-     * @since Chain 1.1
-     */
-    public boolean isIgnorePostprocessResult() {
-        return ignorePostprocessResult;
-    }
-
-    /**
-     * <p>Set the rules for whether or not this class will ignore or
-     * pass through the value returned from executing the looked up
-     * Filter's <code>postprocess()</code> method.</p>
-     * <p>If you are looking up a Filter which may be "aborted" and
-     * you do not want this class to stop chain processing, then this
-     * value should be set to <code>true</code></p>
-     * @param ignorePostprocessResult <code>true</code> if result of the
-     * looked up Filter's <code>postprocess()</code> method should be ignored.
-     *
-     * @since Chain 1.1
-     */
-    public void setIgnorePostprocessResult(boolean ignorePostprocessResult) {
-        this.ignorePostprocessResult = ignorePostprocessResult;
-    }
-
-    // ---------------------------------------------------------- Filter Methods
-
-    /**
-     * <p>Look up the specified command, and (if found) execute it.
-     * Unless <code>ignoreExecuteResult</code> is set to <code>true</code>,
-     * return the result of executing the found command.  If no command
-     * is found, return {@link Processing#CONTINUE}, unless the <code>optional</code>
-     * property is <code>false</code>, in which case an <code>IllegalArgumentException</code>
-     * will be thrown.
-     * </p>
-     *
-     * @param context The context for this request
-     *
-     * @throws IllegalArgumentException if no such {@link Command}
-     *  can be found and the <code>optional</code> property is set
-     *  to <code>false</code>
-     * @return the result of executing the looked-up command, or
-     * <code>CONTINUE</code> if no command is found or if the command
-     * is found but the <code>ignoreExecuteResult</code> property of this
-     * instance is <code>true</code>
-     * @throws org.apache.commons.chain2.ChainException if and error occurs in the looked-up Command.
-     */
-    public Processing execute(C context) {
-        Command<K, V, C> command = getCommand(context);
-        if (command != null) {
-            Processing result = command.execute(context);
-            if (isIgnoreExecuteResult()) {
-                return Processing.CONTINUE;
-            }
-            return result;
-        }
-        return Processing.CONTINUE;
-    }
-
-
-    /**
-     * <p>If the executed command was itself a {@link Filter}, call the
-     * <code>postprocess()</code> method of that {@link Filter} as well.</p>
-     *
-     * @param context The context for this request
-     * @param exception Any <code>Exception</code> thrown by command execution
-     *
-     * @return the result of executing the <code>postprocess</code> method
-     * of the looked-up command, unless <code>ignorePostprocessResult</code> is
-     * <code>true</code>.  If no command is found, return <code>false</code>,
-     * unless the <code>optional</code> property is <code>false</code>, in which
-     * case <code>IllegalArgumentException</code> will be thrown.
-     */
-    public boolean postprocess(C context, Exception exception) {
-        Command<K, V, C> command = getCommand(context);
-        if (command != null) {
-            if (command instanceof Filter) {
-                boolean result = ((Filter<K, V, C>) command).postprocess(context, exception);
-                return !isIgnorePostprocessResult() && result;
-            }
-        }
-        return false;
-    }
-
-    // --------------------------------------------------------- Private Methods
-
-    /**
-     * <p>Return the {@link Catalog} to look up the {@link Command} in.</p>
-     *
-     * @param context {@link Context} for this request
-     * @return The catalog.
-     * @throws IllegalArgumentException if no {@link Catalog}
-     *  can be found
-     *
-     * @since Chain 1.2
-     */
-    protected Catalog<K, V, C> getCatalog(C context) {
-        CatalogFactory<K, V, C> lookupFactory = this.catalogFactory;
-        if (lookupFactory == null) {
-            lookupFactory = CatalogFactoryBase.getInstance();
-        }
-
-        String catalogName = getCatalogName();
-        Catalog<K, V, C> catalog = null;
-        if (catalogName == null) {
-            // use default catalog
-            catalog = lookupFactory.getCatalog();
-        } else {
-            catalog = lookupFactory.getCatalog(catalogName);
-        }
-        if (catalog == null) {
-            if (catalogName == null) {
-                throw new IllegalArgumentException
-                    ("Cannot find default catalog");
-            } else {
-                throw new IllegalArgumentException
-                    ("Cannot find catalog '" + catalogName + "'");
-            }
-        }
-
-        return catalog;
-    }
-
-    /**
-     * <p>Return the {@link Command} instance to be delegated to.</p>
-     *
-     * @param context {@link Context} for this request
-     * @return The looked-up Command.
-     * @throws IllegalArgumentException if no such {@link Command}
-     *  can be found and the <code>optional</code> property is set
-     *  to <code>false</code>
-     */
-    protected Command<K, V, C> getCommand(C context) {
-        Catalog<K, V, C> catalog = getCatalog(context);
-
-        Command<K, V, C> command;
-        String name = getCommandName(context);
-        if (name != null) {
-            command = catalog.getCommand(name);
-            if (command == null && !isOptional()) {
-                if (catalogName == null) {
-                    throw new IllegalArgumentException
-                        ("Cannot find command '" + name
-                         + "' in default catalog");
-                } else {
-                    throw new IllegalArgumentException
-                        ("Cannot find command '" + name
-                         + "' in catalog '" + catalogName + "'");
-                }
-            }
-            return command;
-        }
-        throw new IllegalArgumentException("No command name");
-    }
-
-    /**
-     * <p>Return the name of the {@link Command} instance to be delegated to.</p>
-     *
-     * @param context {@link Context} for this request
-     * @return The name of the {@link Command} instance
-     *
-     * @since Chain 1.2
-     */
-    protected String getCommandName(C context) {
-        String name = getName();
-        if (name == null) {
-            name = (String) context.get(getNameKey());
-        }
-        return name;
-    }
-
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.chain2.base;
+
+import org.apache.commons.chain2.Catalog;
+import org.apache.commons.chain2.CatalogFactory;
+import org.apache.commons.chain2.Command;
+import org.apache.commons.chain2.Context;
+import org.apache.commons.chain2.Filter;
+import org.apache.commons.chain2.Processing;
+import org.apache.commons.chain2.impl.CatalogFactoryBase;
+
+import java.util.Map;
+
+/**
+ * <p>Look up a specified {@link Command} (which could also be a
+ * {@link org.apache.commons.chain2.Chain})
+ * in a {@link Catalog}, and delegate execution to it.  If the delegated-to
+ * {@link Command} is also a {@link Filter}, its <code>postprocess()</code>
+ * method will also be invoked at the appropriate time.</p>
+ *
+ * <p>The name of the {@link Command} can be specified either directly (via
+ * the <code>name</code> property) or indirectly (via the <code>nameKey</code>
+ * property).  Exactly one of these must be set.</p>
+ *
+ * <p>If the <code>optional</code> property is set to <code>true</code>,
+ * failure to find the specified command in the specified catalog will be
+ * silently ignored.  Otherwise, a lookup failure will trigger an
+ * <code>IllegalArgumentException</code>.</p>
+ *
+ * @param <K> Context key type
+ * @param <V> Context value type
+ * @param <C> Type of the context associated with this command
+ *
+ */
+public class LookupCommand<K, V, C extends Map<K, V>> implements Filter<K, V, C> {
+
+    // -------------------------------------------------------------- Constructors
+
+    /**
+     * Create an instance, setting its <code>catalogFactory</code> property to the
+     * value of <code>CatalogFactory.getInstance()</code>.
+     *
+     * @since 1.1
+     */
+    public LookupCommand() {
+        this(CatalogFactoryBase.<K, V, C>getInstance());
+    }
+
+    /**
+     * Create an instance and initialize the <code>catalogFactory</code> property
+     * to given <code>factory</code>/
+     *
+     * @param factory The Catalog Factory.
+     *
+     * @since 1.1
+     */
+    public LookupCommand(CatalogFactory<K, V, C> factory) {
+        this.catalogFactory = factory;
+    }
+
+    // -------------------------------------------------------------- Properties
+
+    private CatalogFactory<K, V, C> catalogFactory = null;
+
+    /**
+     * <p>Set the {@link CatalogFactoryBase} from which lookups will be
+     * performed.</p>
+     *
+     * @param catalogFactory The Catalog Factory.
+     *
+     * @since 1.1
+     */
+    public void setCatalogFactory(CatalogFactory<K, V, C> catalogFactory) {
+        this.catalogFactory = catalogFactory;
+    }
+
+    /**
+     * Return the {@link CatalogFactoryBase} from which lookups will be performed.
+     * @return The Catalog factory.
+     *
+     * @since 1.1
+     */
+    public CatalogFactory<K, V, C> getCatalogFactory() {
+        return this.catalogFactory;
+    }
+
+    private String catalogName = null;
+
+    /**
+     * <p>Return the name of the {@link Catalog} to be searched, or
+     * <code>null</code> to search the default {@link Catalog}.</p>
+     * @return The Catalog name.
+     */
+    public String getCatalogName() {
+        return this.catalogName;
+    }
+
+    /**
+     * <p>Set the name of the {@link Catalog} to be searched, or
+     * <code>null</code> to search the default {@link Catalog}.</p>
+     *
+     * @param catalogName The new {@link Catalog} name or <code>null</code>
+     */
+    public void setCatalogName(String catalogName) {
+        this.catalogName = catalogName;
+    }
+
+    private String name = null;
+
+    /**
+     * <p>Return the name of the {@link Command} that we will look up and
+     * delegate execution to.</p>
+     * @return The name of the Command.
+     */
+    public String getName() {
+        return this.name;
+    }
+
+    /**
+     * <p>Set the name of the {@link Command} that we will look up and
+     * delegate execution to.</p>
+     *
+     * @param name The new command name
+     */
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    private String nameKey = null;
+
+    /**
+     * <p>Return the context attribute key under which the {@link Command}
+     * name is stored.</p>
+     * @return The context key of the Command.
+     */
+    public String getNameKey() {
+        return this.nameKey;
+    }
+
+    /**
+     * <p>Set the context attribute key under which the {@link Command}
+     * name is stored.</p>
+     *
+     * @param nameKey The new context attribute key
+     */
+    public void setNameKey(String nameKey) {
+        this.nameKey = nameKey;
+    }
+
+    private boolean optional = false;
+
+    /**
+     * <p>Return <code>true</code> if locating the specified command
+     * is optional.</p>
+     * @return <code>true</code> if the Command is optional.
+     */
+    public boolean isOptional() {
+        return this.optional;
+    }
+
+    /**
+     * <p>Set the optional flag for finding the specified command.</p>
+     *
+     * @param optional The new optional flag
+     */
+    public void setOptional(boolean optional) {
+        this.optional = optional;
+    }
+
+    private boolean ignoreExecuteResult = false;
+
+    /**
+     * <p>Return <code>true</code> if this command should ignore
+     * the return value from executing the looked-up command.
+     * Defaults to <code>false</code>, which means that the return result
+     * of executing this lookup will be whatever is returned from that
+     * command.</p>
+     * @return <code>true</code> if result of the looked up Command
+     * should be ignored.
+     *
+     * @since 1.1
+     */
+    public boolean isIgnoreExecuteResult() {
+        return ignoreExecuteResult;
+    }
+
+    /**
+     * <p>Set the rules for whether or not this class will ignore or
+     * pass through the value returned from executing the looked up
+     * command.</p>
+     * <p>If you are looking up a chain which may be "aborted" and
+     * you do not want this class to stop chain processing, then this
+     * value should be set to <code>true</code></p>
+     * @param ignoreReturn <code>true</code> if result of the
+     * looked up Command should be ignored.
+     *
+     * @since 1.1
+     */
+    public void setIgnoreExecuteResult(boolean ignoreReturn) {
+        this.ignoreExecuteResult = ignoreReturn;
+    }
+
+    private boolean ignorePostprocessResult = false;
+
+    /**
+     * <p>Return <code>true</code> if this command is a Filter and
+     * should ignore the return value from executing the looked-up Filter's
+     * <code>postprocess()</code> method.
+     * Defaults to <code>false</code>, which means that the return result
+     * of executing this lookup will be whatever is returned from that
+     * Filter.</p>
+     * @return <code>true</code> if result of the looked up Filter's
+     * <code>postprocess()</code> method should be ignored.
+     *
+     * @since 1.1
+     */
+    public boolean isIgnorePostprocessResult() {
+        return ignorePostprocessResult;
+    }
+
+    /**
+     * <p>Set the rules for whether or not this class will ignore or
+     * pass through the value returned from executing the looked up
+     * Filter's <code>postprocess()</code> method.</p>
+     * <p>If you are looking up a Filter which may be "aborted" and
+     * you do not want this class to stop chain processing, then this
+     * value should be set to <code>true</code></p>
+     * @param ignorePostprocessResult <code>true</code> if result of the
+     * looked up Filter's <code>postprocess()</code> method should be ignored.
+     *
+     * @since 1.1
+     */
+    public void setIgnorePostprocessResult(boolean ignorePostprocessResult) {
+        this.ignorePostprocessResult = ignorePostprocessResult;
+    }
+
+    // ---------------------------------------------------------- Filter Methods
+
+    /**
+     * <p>Look up the specified command, and (if found) execute it.
+     * Unless <code>ignoreExecuteResult</code> is set to <code>true</code>,
+     * return the result of executing the found command.  If no command
+     * is found, return {@link Processing#CONTINUE}, unless the <code>optional</code>
+     * property is <code>false</code>, in which case an <code>IllegalArgumentException</code>
+     * will be thrown.
+     * </p>
+     *
+     * @param context The context for this request
+     *
+     * @throws IllegalArgumentException if no such {@link Command}
+     *  can be found and the <code>optional</code> property is set
+     *  to <code>false</code>
+     * @return the result of executing the looked-up command, or
+     * <code>CONTINUE</code> if no command is found or if the command
+     * is found but the <code>ignoreExecuteResult</code> property of this
+     * instance is <code>true</code>
+     * @throws org.apache.commons.chain2.ChainException if and error occurs in the looked-up Command.
+     */
+    public Processing execute(C context) {
+        Command<K, V, C> command = getCommand(context);
+        if (command != null) {
+            Processing result = command.execute(context);
+            if (isIgnoreExecuteResult()) {
+                return Processing.CONTINUE;
+            }
+            return result;
+        }
+        return Processing.CONTINUE;
+    }
+
+
+    /**
+     * <p>If the executed command was itself a {@link Filter}, call the
+     * <code>postprocess()</code> method of that {@link Filter} as well.</p>
+     *
+     * @param context The context for this request
+     * @param exception Any <code>Exception</code> thrown by command execution
+     *
+     * @return the result of executing the <code>postprocess</code> method
+     * of the looked-up command, unless <code>ignorePostprocessResult</code> is
+     * <code>true</code>.  If no command is found, return <code>false</code>,
+     * unless the <code>optional</code> property is <code>false</code>, in which
+     * case <code>IllegalArgumentException</code> will be thrown.
+     */
+    public boolean postprocess(C context, Exception exception) {
+        Command<K, V, C> command = getCommand(context);
+        if (command != null) {
+            if (command instanceof Filter) {
+                boolean result = ((Filter<K, V, C>) command).postprocess(context, exception);
+                return !isIgnorePostprocessResult() && result;
+            }
+        }
+        return false;
+    }
+
+    // --------------------------------------------------------- Private Methods
+
+    /**
+     * <p>Return the {@link Catalog} to look up the {@link Command} in.</p>
+     *
+     * @param context {@link Context} for this request
+     * @return The catalog.
+     * @throws IllegalArgumentException if no {@link Catalog}
+     *  can be found
+     *
+     * @since 1.2
+     */
+    protected Catalog<K, V, C> getCatalog(C context) {
+        CatalogFactory<K, V, C> lookupFactory = this.catalogFactory;
+        if (lookupFactory == null) {
+            lookupFactory = CatalogFactoryBase.getInstance();
+        }
+
+        String catalogName = getCatalogName();
+        Catalog<K, V, C> catalog = null;
+        if (catalogName == null) {
+            // use default catalog
+            catalog = lookupFactory.getCatalog();
+        } else {
+            catalog = lookupFactory.getCatalog(catalogName);
+        }
+        if (catalog == null) {
+            if (catalogName == null) {
+                throw new IllegalArgumentException
+                    ("Cannot find default catalog");
+            } else {
+                throw new IllegalArgumentException
+                    ("Cannot find catalog '" + catalogName + "'");
+            }
+        }
+
+        return catalog;
+    }
+
+    /**
+     * <p>Return the {@link Command} instance to be delegated to.</p>
+     *
+     * @param context {@link Context} for this request
+     * @return The looked-up Command.
+     * @throws IllegalArgumentException if no such {@link Command}
+     *  can be found and the <code>optional</code> property is set
+     *  to <code>false</code>
+     */
+    protected Command<K, V, C> getCommand(C context) {
+        Catalog<K, V, C> catalog = getCatalog(context);
+
+        Command<K, V, C> command;
+        String name = getCommandName(context);
+        if (name != null) {
+            command = catalog.getCommand(name);
+            if (command == null && !isOptional()) {
+                if (catalogName == null) {
+                    throw new IllegalArgumentException
+                        ("Cannot find command '" + name
+                         + "' in default catalog");
+                } else {
+                    throw new IllegalArgumentException
+                        ("Cannot find command '" + name
+                         + "' in catalog '" + catalogName + "'");
+                }
+            }
+            return command;
+        }
+        throw new IllegalArgumentException("No command name");
+    }
+
+    /**
+     * <p>Return the name of the {@link Command} instance to be delegated to.</p>
+     *
+     * @param context {@link Context} for this request
+     * @return The name of the {@link Command} instance
+     *
+     * @since 1.2
+     */
+    protected String getCommandName(C context) {
+        String name = getName();
+        if (name == null) {
+            name = (String) context.get(getNameKey());
+        }
+        return name;
+    }
+
+}
diff --git a/base/src/main/java/org/apache/commons/chain2/impl/CatalogBase.java b/base/src/main/java/org/apache/commons/chain2/impl/CatalogBase.java
index b886ade..db04884 100644
--- a/base/src/main/java/org/apache/commons/chain2/impl/CatalogBase.java
+++ b/base/src/main/java/org/apache/commons/chain2/impl/CatalogBase.java
@@ -1,143 +1,143 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.chain2.impl;
-
-import static java.util.Collections.unmodifiableMap;
-
-import java.util.Iterator;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
-import org.apache.commons.chain2.Catalog;
-import org.apache.commons.chain2.Command;
-
-/**
- * <p>Simple in-memory implementation of {@link Catalog}.  This class can
- * also be used as the basis for more advanced implementations.</p>
- *
- * <p>This implementation is thread-safe.</p>
- *
- * @param <K> the type of keys maintained by the context associated with this catalog
- * @param <V> the type of mapped values
- * @param <C> Type of the context associated with this catalog
- *
- */
-public class CatalogBase<K, V, C extends Map<K, V>> implements Catalog<K, V, C> {
-
-    // ----------------------------------------------------- Instance Variables
-
-    /**
-     * <p>The map of named {@link Command}s, keyed by name.
-     */
-    private final Map<String, Command<K, V, C>> commands = new ConcurrentHashMap<String, Command<K, V, C>>();
-
-    // --------------------------------------------------------- Constructors
-
-    /**
-     * Create an empty catalog.
-     */
-    public CatalogBase() { }
-
-    /**
-     * <p>Create a catalog whose commands are those specified in the given <code>Map</code>.
-     * All Map keys should be <code>String</code> and all values should be <code>Command</code>.</p>
-     *
-     * @param commands Map of Commands.
-     *
-     * @throws IllegalArgumentException if <code>commands</code>
-     * is <code>null</code>
-     *
-     * @since Chain 1.1
-     */
-    public CatalogBase(Map<String, Command<K, V, C>> commands) {
-        if (commands == null) {
-            throw new IllegalArgumentException("'commands' parameter must be not null");
-        }
-        this.commands.putAll( commands );
-    }
-
-    // --------------------------------------------------------- Public Methods
-
-    /**
-     * <p>Add a new name and associated {@link Command}
-     * to the set of named commands known to this {@link Catalog},
-     * replacing any previous command for that name.
-     *
-     * @param <CMD> the {@link Command} type to be added in the {@link Catalog}
-     * @param name Name of the new command
-     * @param command {@link Command} to be returned
-     *  for later lookups on this name
-     */
-    public <CMD extends Command<K, V, C>> void addCommand(String name, CMD command) {
-        commands.put(name, command);
-    }
-
-    /**
-     * <p>Return the {@link Command} associated with the
-     * specified name, if any; otherwise, return <code>null</code>.</p>
-     *
-     * @param <CMD> the expected {@link Command} type to be returned
-     * @param name Name for which a {@link Command}
-     *  should be retrieved
-     * @return The Command associated with the specified name.
-     */
-    public <CMD extends Command<K, V, C>> CMD getCommand(String name) {
-        @SuppressWarnings("unchecked") // it would throw ClassCastException if users try to cast to a different type
-        CMD command = (CMD) commands.get(name);
-        return command;
-    }
-
-    /**
-     * Returns the map of named {@link Command}s, keyed by name.
-     *
-     * @return The map of named {@link Command}s, keyed by name.
-     * @since 2.0
-     */
-    public Map<String, Command<K, V, C>> getCommands() {
-        return unmodifiableMap(commands);
-    }
-
-    /**
-     * <p>Return an <code>Iterator</code> over the set of named commands
-     * known to this {@link Catalog}.  If there are no known commands,
-     * an empty Iterator is returned.</p>
-     * @return An iterator of the names in this Catalog.
-     */
-    public Iterator<String> getNames() {
-        return commands.keySet().iterator();
-    }
-
-    /**
-     * Converts this Catalog to a String.  Useful for debugging purposes.
-     * @return a representation of this catalog as a String
-     */
-    @Override
-    public String toString() {
-        Iterator<String> names = getNames();
-        StringBuilder str = new StringBuilder("[").append(this.getClass().getName()).append(": ");
-
-        while (names.hasNext()) {
-            str.append(names.next());
-            if (names.hasNext()) {
-                str.append(", ");
-            }
-        }
-
-        return str.append("]").toString();
-    }
-
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.chain2.impl;
+
+import static java.util.Collections.unmodifiableMap;
+
+import java.util.Iterator;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.apache.commons.chain2.Catalog;
+import org.apache.commons.chain2.Command;
+
+/**
+ * <p>Simple in-memory implementation of {@link Catalog}.  This class can
+ * also be used as the basis for more advanced implementations.</p>
+ *
+ * <p>This implementation is thread-safe.</p>
+ *
+ * @param <K> the type of keys maintained by the context associated with this catalog
+ * @param <V> the type of mapped values
+ * @param <C> Type of the context associated with this catalog
+ *
+ */
+public class CatalogBase<K, V, C extends Map<K, V>> implements Catalog<K, V, C> {
+
+    // ----------------------------------------------------- Instance Variables
+
+    /**
+     * <p>The map of named {@link Command}s, keyed by name.
+     */
+    private final Map<String, Command<K, V, C>> commands = new ConcurrentHashMap<String, Command<K, V, C>>();
+
+    // --------------------------------------------------------- Constructors
+
+    /**
+     * Create an empty catalog.
+     */
+    public CatalogBase() { }
+
+    /**
+     * <p>Create a catalog whose commands are those specified in the given <code>Map</code>.
+     * All Map keys should be <code>String</code> and all values should be <code>Command</code>.</p>
+     *
+     * @param commands Map of Commands.
+     *
+     * @throws IllegalArgumentException if <code>commands</code>
+     * is <code>null</code>
+     *
+     * @since 1.1
+     */
+    public CatalogBase(Map<String, Command<K, V, C>> commands) {
+        if (commands == null) {
+            throw new IllegalArgumentException("'commands' parameter must be not null");
+        }
+        this.commands.putAll( commands );
+    }
+
+    // --------------------------------------------------------- Public Methods
+
+    /**
+     * <p>Add a new name and associated {@link Command}
+     * to the set of named commands known to this {@link Catalog},
+     * replacing any previous command for that name.
+     *
+     * @param <CMD> the {@link Command} type to be added in the {@link Catalog}
+     * @param name Name of the new command
+     * @param command {@link Command} to be returned
+     *  for later lookups on this name
+     */
+    public <CMD extends Command<K, V, C>> void addCommand(String name, CMD command) {
+        commands.put(name, command);
+    }
+
+    /**
+     * <p>Return the {@link Command} associated with the
+     * specified name, if any; otherwise, return <code>null</code>.</p>
+     *
+     * @param <CMD> the expected {@link Command} type to be returned
+     * @param name Name for which a {@link Command}
+     *  should be retrieved
+     * @return The Command associated with the specified name.
+     */
+    public <CMD extends Command<K, V, C>> CMD getCommand(String name) {
+        @SuppressWarnings("unchecked") // it would throw ClassCastException if users try to cast to a different type
+        CMD command = (CMD) commands.get(name);
+        return command;
+    }
+
+    /**
+     * Returns the map of named {@link Command}s, keyed by name.
+     *
+     * @return The map of named {@link Command}s, keyed by name.
+     * @since 2.0
+     */
+    public Map<String, Command<K, V, C>> getCommands() {
+        return unmodifiableMap(commands);
+    }
+
+    /**
+     * <p>Return an <code>Iterator</code> over the set of named commands
+     * known to this {@link Catalog}.  If there are no known commands,
+     * an empty Iterator is returned.</p>
+     * @return An iterator of the names in this Catalog.
+     */
+    public Iterator<String> getNames() {
+        return commands.keySet().iterator();
+    }
+
+    /**
+     * Converts this Catalog to a String.  Useful for debugging purposes.
+     * @return a representation of this catalog as a String
+     */
+    @Override
+    public String toString() {
+        Iterator<String> names = getNames();
+        StringBuilder str = new StringBuilder("[").append(this.getClass().getName()).append(": ");
+
+        while (names.hasNext()) {
+            str.append(names.next());
+            if (names.hasNext()) {
+                str.append(", ");
+            }
+        }
+
+        return str.append("]").toString();
+    }
+
+}
diff --git a/web/src/main/java/org/apache/commons/chain2/web/ChainResources.java b/web/src/main/java/org/apache/commons/chain2/web/ChainResources.java
index a1f113e..f065967 100644
--- a/web/src/main/java/org/apache/commons/chain2/web/ChainResources.java
+++ b/web/src/main/java/org/apache/commons/chain2/web/ChainResources.java
@@ -1,154 +1,154 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.chain2.web;
-
-import org.apache.commons.chain2.Catalog;
-import org.apache.commons.chain2.CatalogFactory;
-import org.apache.commons.chain2.config.xml.XmlConfigParser;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-import javax.servlet.ServletContext;
-import java.net.URL;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-import java.util.StringTokenizer;
-
-/**
- * <p>Utility methods for loading class loader and web application resources
- * to configure a {@link Catalog}.  These methods are shared between
- * <code>ChainListener</code> and <code>ChainServlet</code>.</p>
- *
- */
-final class ChainResources {
-
-    /**
-     * This class uses a private constructor because it is a utility class.
-     */
-    private ChainResources() {
-    }
-
-    // ---------------------------------------------------------- Static Methods
-
-    /**
-     * <p>Parse the specified class loader resources.</p>
-     *
-     * @param resources Comma-delimited list of resources (or <code>null</code>)
-     * @param parser {@link XmlConfigParser} to use for parsing
-     */
-    static void parseClassResources(String resources,
-                                    XmlConfigParser parser) {
-        if (resources == null) {
-            return;
-        }
-        Log log = LogFactory.getLog(ChainResources.class);
-        ClassLoader loader =
-            Thread.currentThread().getContextClassLoader();
-        if (loader == null) {
-            loader = ChainResources.class.getClassLoader();
-        }
-        String[] paths = getResourcePaths(resources);
-        String path = null;
-        try {
-            for (String path1 : paths) {
-                path = path1;
-                URL url = loader.getResource(path);
-                if (url == null) {
-                    throw new IllegalStateException
-                            ("Missing chain config resource '" + path + "'");
-                }
-                if (log.isDebugEnabled()) {
-                    log.debug("Loading chain config resource '" + path + "'");
-                }
-                @SuppressWarnings("unused") // FIXME we have to assign the factory here to help the compiler with the type arguments
-                CatalogFactory<Object,Object,Map<Object,Object>> factory = parser.parse(url);
-            }
-        } catch (Exception e) {
-            throw new RuntimeException
-                ("Exception parsing chain config resource '" + path + "': "
-                 + e.getMessage());
-        }
-    }
-
-    /**
-     * <p>Parse the specified web application resources.</p>
-     *
-     * @param context <code>ServletContext</code> for this web application
-     * @param resources Comma-delimited list of resources (or <code>null</code>)
-     * @param parser {@link XmlConfigParser} to use for parsing
-     */
-    static void parseWebResources(ServletContext context,
-                                  String resources,
-                                  XmlConfigParser parser) {
-        if (resources == null) {
-            return;
-        }
-        Log log = LogFactory.getLog(ChainResources.class);
-        String[] paths = getResourcePaths(resources);
-        String path = null;
-        try {
-            for (String path1 : paths) {
-                path = path1;
-                URL url = context.getResource(path);
-                if (url == null) {
-                    throw new IllegalStateException
-                            ("Missing chain config resource '" + path + "'");
-                }
-                if (log.isDebugEnabled()) {
-                    log.debug("Loading chain config resource '" + path + "'");
-                }
-                @SuppressWarnings("unused") // FIXME we have to assign the factory here to help the compiler with the type arguments
-                CatalogFactory<Object, Object, Map<Object, Object>> factory = parser.parse(url);
-            }
-        } catch (Exception e) {
-            throw new RuntimeException
-                ("Exception parsing chain config resource '" + path + "': "
-                 + e.getMessage());
-        }
-    }
-
-    /**
-     * <p> Parse the resource string into an array of paths. Empty entries will
-     * be skipped. (That is, all entries in the array are non-empty paths.)</p>
-     *
-     * @param resources A comma-delimited list of resource paths (or
-     *                  <code>null</code>).
-     *
-     * @return An array of non-empty paths. The array itself may be empty.
-     *
-     * @since Chain 1.1
-     */
-    static String[] getResourcePaths(String resources) {
-        if (resources == null || resources.isEmpty()) {
-            return new String[0];
-        }
-
-        StringTokenizer resourcesTokenizer = new StringTokenizer(resources, ",");
-        List<String> paths = new ArrayList<String>(resourcesTokenizer.countTokens());
-
-        while (resourcesTokenizer.hasMoreTokens()) {
-            String path = resourcesTokenizer.nextToken().trim();
-            if (!path.isEmpty()) {
-                paths.add(path);
-            }
-        }
-
-        return paths.toArray(new String[paths.size()]);
-    }
-
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.chain2.web;
+
+import org.apache.commons.chain2.Catalog;
+import org.apache.commons.chain2.CatalogFactory;
+import org.apache.commons.chain2.config.xml.XmlConfigParser;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import javax.servlet.ServletContext;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.StringTokenizer;
+
+/**
+ * <p>Utility methods for loading class loader and web application resources
+ * to configure a {@link Catalog}.  These methods are shared between
+ * <code>ChainListener</code> and <code>ChainServlet</code>.</p>
+ *
+ */
+final class ChainResources {
+
+    /**
+     * This class uses a private constructor because it is a utility class.
+     */
+    private ChainResources() {
+    }
+
+    // ---------------------------------------------------------- Static Methods
+
+    /**
+     * <p>Parse the specified class loader resources.</p>
+     *
+     * @param resources Comma-delimited list of resources (or <code>null</code>)
+     * @param parser {@link XmlConfigParser} to use for parsing
+     */
+    static void parseClassResources(String resources,
+                                    XmlConfigParser parser) {
+        if (resources == null) {
+            return;
+        }
+        Log log = LogFactory.getLog(ChainResources.class);
+        ClassLoader loader =
+            Thread.currentThread().getContextClassLoader();
+        if (loader == null) {
+            loader = ChainResources.class.getClassLoader();
+        }
+        String[] paths = getResourcePaths(resources);
+        String path = null;
+        try {
+            for (String path1 : paths) {
+                path = path1;
+                URL url = loader.getResource(path);
+                if (url == null) {
+                    throw new IllegalStateException
+                            ("Missing chain config resource '" + path + "'");
+                }
+                if (log.isDebugEnabled()) {
+                    log.debug("Loading chain config resource '" + path + "'");
+                }
+                @SuppressWarnings("unused") // FIXME we have to assign the factory here to help the compiler with the type arguments
+                CatalogFactory<Object,Object,Map<Object,Object>> factory = parser.parse(url);
+            }
+        } catch (Exception e) {
+            throw new RuntimeException
+                ("Exception parsing chain config resource '" + path + "': "
+                 + e.getMessage());
+        }
+    }
+
+    /**
+     * <p>Parse the specified web application resources.</p>
+     *
+     * @param context <code>ServletContext</code> for this web application
+     * @param resources Comma-delimited list of resources (or <code>null</code>)
+     * @param parser {@link XmlConfigParser} to use for parsing
+     */
+    static void parseWebResources(ServletContext context,
+                                  String resources,
+                                  XmlConfigParser parser) {
+        if (resources == null) {
+            return;
+        }
+        Log log = LogFactory.getLog(ChainResources.class);
+        String[] paths = getResourcePaths(resources);
+        String path = null;
+        try {
+            for (String path1 : paths) {
+                path = path1;
+                URL url = context.getResource(path);
+                if (url == null) {
+                    throw new IllegalStateException
+                            ("Missing chain config resource '" + path + "'");
+                }
+                if (log.isDebugEnabled()) {
+                    log.debug("Loading chain config resource '" + path + "'");
+                }
+                @SuppressWarnings("unused") // FIXME we have to assign the factory here to help the compiler with the type arguments
+                CatalogFactory<Object, Object, Map<Object, Object>> factory = parser.parse(url);
+            }
+        } catch (Exception e) {
+            throw new RuntimeException
+                ("Exception parsing chain config resource '" + path + "': "
+                 + e.getMessage());
+        }
+    }
+
+    /**
+     * <p> Parse the resource string into an array of paths. Empty entries will
+     * be skipped. (That is, all entries in the array are non-empty paths.)</p>
+     *
+     * @param resources A comma-delimited list of resource paths (or
+     *                  <code>null</code>).
+     *
+     * @return An array of non-empty paths. The array itself may be empty.
+     *
+     * @since 1.1
+     */
+    static String[] getResourcePaths(String resources) {
+        if (resources == null || resources.isEmpty()) {
+            return new String[0];
+        }
+
+        StringTokenizer resourcesTokenizer = new StringTokenizer(resources, ",");
+        List<String> paths = new ArrayList<String>(resourcesTokenizer.countTokens());
+
+        while (resourcesTokenizer.hasMoreTokens()) {
+            String path = resourcesTokenizer.nextToken().trim();
+            if (!path.isEmpty()) {
+                paths.add(path);
+            }
+        }
+
+        return paths.toArray(new String[paths.size()]);
+    }
+
+}
diff --git a/web/src/main/java/org/apache/commons/chain2/web/WebContext.java b/web/src/main/java/org/apache/commons/chain2/web/WebContext.java
index e6f56db..524d702 100644
--- a/web/src/main/java/org/apache/commons/chain2/web/WebContext.java
+++ b/web/src/main/java/org/apache/commons/chain2/web/WebContext.java
@@ -1,104 +1,104 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.commons.chain2.web;
-
-import org.apache.commons.chain2.Context;
-
-import javax.servlet.http.Cookie;
-import java.io.Serializable;
-import java.util.Map;
-
-/**
- *
- */
-public interface WebContext<K, V> extends Context<K, V>, Serializable {
-    /**
-     * <p>Return a mutable <code>Map</code> that maps application scope
-     * attribute names to their values.</p>
-     *
-     * @return Application scope Map.
-     */
-    Map<String, Object> getApplicationScope();
-
-    /**
-     * <p>Return an immutable <code>Map</code> that maps header names to
-     * the first (or only) header value (as a String).  Header names must
-     * be matched in a case-insensitive manner.</p>
-     *
-     * @return Header values Map.
-     */
-    Map<String, String> getHeader();
-
-    /**
-     * <p>Return an immutable <code>Map</code> that maps header names to
-     * the set of all values specified in the request (as a String array).
-     * Header names must be matched in a case-insensitive manner.</p>
-     *
-     * @return Header values Map.
-     */
-    Map<String, String[]> getHeaderValues();
-
-    /**
-     * <p>Return an immutable <code>Map</code> that maps context application
-     * initialization parameters to their values.</p>
-     *
-     * @return Initialization parameter Map.
-     */
-    Map<String, String> getInitParam();
-
-    /**
-     * <p>Return an immutable <code>Map</code> that maps request parameter
-     * names to the first (or only) value (as a String).</p>
-     *
-     * @return Request parameter Map.
-     */
-    Map<String, String> getParam();
-
-    /**
-     * <p>Return an immutable <code>Map</code> that maps request parameter
-     * names to the set of all values (as a String array).</p>
-     *
-     * @return Request parameter Map.
-     */
-    Map<String, String[]> getParamValues();
-
-    /**
-     * <p>Return an immutable <code>Map</code> that maps cookie names to
-     * the set of cookies specified in the request.
-     *
-     * @return Map of Cookies.
-     * @since Chain 1.1
-     */
-    Map<String, Cookie> getCookies();
-
-    /**
-     * <p>Return a mutable <code>Map</code> that maps request scope
-     * attribute names to their values.</p>
-     *
-     * @return Request scope Map.
-     */
-    Map<String, Object> getRequestScope();
-
-    /**
-     * <p>Return a mutable <code>Map</code> that maps session scope
-     * attribute names to their values.</p>
-     *
-     * @return Session scope Map.
-     */
-    Map<String, Object> getSessionScope();
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.chain2.web;
+
+import org.apache.commons.chain2.Context;
+
+import javax.servlet.http.Cookie;
+import java.io.Serializable;
+import java.util.Map;
+
+/**
+ *
+ */
+public interface WebContext<K, V> extends Context<K, V>, Serializable {
+    /**
+     * <p>Return a mutable <code>Map</code> that maps application scope
+     * attribute names to their values.</p>
+     *
+     * @return Application scope Map.
+     */
+    Map<String, Object> getApplicationScope();
+
+    /**
+     * <p>Return an immutable <code>Map</code> that maps header names to
+     * the first (or only) header value (as a String).  Header names must
+     * be matched in a case-insensitive manner.</p>
+     *
+     * @return Header values Map.
+     */
+    Map<String, String> getHeader();
+
+    /**
+     * <p>Return an immutable <code>Map</code> that maps header names to
+     * the set of all values specified in the request (as a String array).
+     * Header names must be matched in a case-insensitive manner.</p>
+     *
+     * @return Header values Map.
+     */
+    Map<String, String[]> getHeaderValues();
+
+    /**
+     * <p>Return an immutable <code>Map</code> that maps context application
+     * initialization parameters to their values.</p>
+     *
+     * @return Initialization parameter Map.
+     */
+    Map<String, String> getInitParam();
+
+    /**
+     * <p>Return an immutable <code>Map</code> that maps request parameter
+     * names to the first (or only) value (as a String).</p>
+     *
+     * @return Request parameter Map.
+     */
+    Map<String, String> getParam();
+
+    /**
+     * <p>Return an immutable <code>Map</code> that maps request parameter
+     * names to the set of all values (as a String array).</p>
+     *
+     * @return Request parameter Map.
+     */
+    Map<String, String[]> getParamValues();
+
+    /**
+     * <p>Return an immutable <code>Map</code> that maps cookie names to
+     * the set of cookies specified in the request.
+     *
+     * @return Map of Cookies.
+     * @since 1.1
+     */
+    Map<String, Cookie> getCookies();
+
+    /**
+     * <p>Return a mutable <code>Map</code> that maps request scope
+     * attribute names to their values.</p>
+     *
+     * @return Request scope Map.
+     */
+    Map<String, Object> getRequestScope();
+
+    /**
+     * <p>Return a mutable <code>Map</code> that maps session scope
+     * attribute names to their values.</p>
+     *
+     * @return Session scope Map.
+     */
+    Map<String, Object> getSessionScope();
+}
diff --git a/web/src/main/java/org/apache/commons/chain2/web/faces/FacesWebContext.java b/web/src/main/java/org/apache/commons/chain2/web/faces/FacesWebContext.java
index 72b135a..26f3768 100644
--- a/web/src/main/java/org/apache/commons/chain2/web/faces/FacesWebContext.java
+++ b/web/src/main/java/org/apache/commons/chain2/web/faces/FacesWebContext.java
@@ -1,232 +1,232 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.chain2.web.faces;
-
-import org.apache.commons.chain2.web.WebContextBase;
-
-import javax.faces.context.FacesContext;
-import javax.servlet.http.Cookie;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.Map;
-
-/**
- * <p>Concrete implementation of {@link org.apache.commons.chain2.web.WebContext} suitable for use in
- * JavaServer Faces apps.  The abstract methods are mapped to the appropriate
- * collections of the underlying <code>FacesContext</code> instance
- * that is passed to the constructor (or the initialize method).</p>
- *
- */
-public class FacesWebContext extends WebContextBase {
-
-    // ------------------------------------------------------------ Constructors
-
-    /**
-     *
-     */
-    private static final long serialVersionUID = 20120724L;
-
-    /**
-     * <p>Construct an uninitialized {@link FacesWebContext} instance.</p>
-     */
-    public FacesWebContext() {
-    }
-
-    /**
-     * <p>Construct a {@link FacesWebContext} instance that is initialized
-     * with the specified JavaServer Faces API objects.</p>
-     *
-     * @param context The <code>FacesContext</code> for this request
-     */
-    public FacesWebContext(FacesContext context) {
-        initialize(context);
-    }
-
-    // ------------------------------------------------------ Instance Variables
-
-    /**
-     * <p>The <code>FacesContext</code> instance for the request represented
-     * by this {@link org.apache.commons.chain2.web.WebContext}.</p>
-     */
-    private FacesContext context = null;
-
-    // ---------------------------------------------------------- Public Methods
-
-    /**
-     * <p>Return the <code>FacesContext</code> instance for the request
-     * associated with this {@link FacesWebContext}.</p>
-     *
-     * @return The <code>FacesContext</code> for this request
-     */
-    public FacesContext getContext() {
-        return (this.context);
-    }
-
-    /**
-     * <p>Initialize (or reinitialize) this {@link FacesWebContext} instance
-     * for the specified JavaServer Faces API objects.</p>
-     *
-     * @param context The <code>FacesContext</code> for this request
-     */
-    public void initialize(FacesContext context) {
-        this.context = context;
-    }
-
-    /**
-     * <p>Release references to allocated resources acquired in
-     * <code>initialize()</code> of via subsequent processing.  After this
-     * method is called, subsequent calls to any other method than
-     * <code>initialize()</code> will return undefined results.</p>
-     */
-    public void release() {
-        context = null;
-    }
-
-    // ------------------------------------------------------ WebContextBase Methods
-
-    /**
-     * See the {@link org.apache.commons.chain2.web.WebContext}'s Javadoc.
-     *
-     * @return Application scope Map.
-     */
-    public Map<String, Object> getApplicationScope() {
-        @SuppressWarnings("unchecked") // Assume faces is following contract
-        Map<String, Object> scope = context.getExternalContext().getApplicationMap();
-        return (scope);
-    }
-
-    /**
-     * See the {@link org.apache.commons.chain2.web.WebContext}'s Javadoc.
-     *
-     * @return Header values Map.
-     */
-    public Map<String, String> getHeader() {
-        @SuppressWarnings("unchecked") // Assume faces is following contract
-        Map<String, String> headers = context.getExternalContext().getRequestHeaderMap();
-
-        return (headers);
-    }
-
-    /**
-     * See the {@link org.apache.commons.chain2.web.WebContext}'s Javadoc.
-     *
-     * @return Header values Map.
-     */
-    public Map<String, String[]> getHeaderValues() {
-        @SuppressWarnings("unchecked") // Assume faces is following contract
-        Map<String, String[]> headerValues = context.getExternalContext().getRequestHeaderValuesMap();
-
-        return (headerValues);
-    }
-
-    /**
-     * See the {@link org.apache.commons.chain2.web.WebContext}'s Javadoc.
-     *
-     * @return Initialization parameter Map.
-     */
-    public Map<String, String> getInitParam() {
-        @SuppressWarnings("unchecked") // Assume faces is following contract
-        Map<String, String> initParams = context.getExternalContext().getInitParameterMap();
-
-        return (initParams);
-    }
-
-    /**
-     * See the {@link org.apache.commons.chain2.web.WebContext}'s Javadoc.
-     *
-     * @return Request parameter Map.
-     */
-    public Map<String, String> getParam() {
-        @SuppressWarnings("unchecked")
-        Map<String, String> params = context.getExternalContext().getRequestParameterMap();
-
-        return (params);
-    }
-
-    /**
-     * See the {@link org.apache.commons.chain2.web.WebContext}'s Javadoc.
-     *
-     * @return Request parameter Map.
-     */
-    public Map<String, String[]> getParamValues() {
-        @SuppressWarnings("unchecked") // Assume faces is following contract
-        Map<String, String[]> paramValues = context.getExternalContext().getRequestParameterValuesMap();
-
-        return (paramValues);
-    }
-
-    /**
-     * See the {@link org.apache.commons.chain2.web.WebContext}'s Javadoc.
-     *
-     * @return Map of Cookies.
-     * @since Chain 1.1
-     */
-    public Map<String, Cookie> getCookies() {
-        @SuppressWarnings("unchecked") // Assume faces is following contract
-        Map<String, Object> facesCookieMap = context.getExternalContext().getRequestCookieMap();
-
-        /* This ugly hack was done because the faces API implements
-         * the cookie collection using <String, Object> instead of <String, Cookie>.
-         * So we painstakingly check for type safety and cast it as a Map<String, Cookie>.
-         */
-        Iterator<Object> itr = facesCookieMap.values().iterator();
-
-        if (itr.hasNext()) {
-            Object cookieObj = itr.next();
-
-            if (cookieObj instanceof Cookie) {
-                // See comment above about type safety check
-                @SuppressWarnings({ "unchecked", "rawtypes" })
-                Map<String, Cookie> cookieMap = Collections.checkedMap(
-                        (Map) facesCookieMap, String.class, Cookie.class);
-
-                return cookieMap;
-            } else {
-                String msg = "Could not cast cookie Map into <String, Cookie>. " +
-                        "Actual Cookie type is: " + cookieObj.getClass().toString();
-                throw new ClassCastException(msg);
-            }
-        } else {
-            return Collections.emptyMap();
-        }
-    }
-
-    /**
-     * See the {@link org.apache.commons.chain2.web.WebContext}'s Javadoc.
-     *
-     * @return Request scope Map.
-     */
-    public Map<String, Object> getRequestScope() {
-        @SuppressWarnings("unchecked")  // Assume faces is following contract
-        Map<String, Object> scope = context.getExternalContext().getRequestMap();
-
-        return (scope);
-    }
-
-    /**
-     * See the {@link org.apache.commons.chain2.web.WebContext}'s Javadoc.
-     *
-     * @return Session scope Map.
-     */
-    public Map<String, Object> getSessionScope() {
-        @SuppressWarnings("unchecked")  // Assume faces is following contract
-        Map<String, Object> scope = context.getExternalContext().getSessionMap();
-
-        return (scope);
-    }
-
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.chain2.web.faces;
+
+import org.apache.commons.chain2.web.WebContextBase;
+
+import javax.faces.context.FacesContext;
+import javax.servlet.http.Cookie;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.Map;
+
+/**
+ * <p>Concrete implementation of {@link org.apache.commons.chain2.web.WebContext} suitable for use in
+ * JavaServer Faces apps.  The abstract methods are mapped to the appropriate
+ * collections of the underlying <code>FacesContext</code> instance
+ * that is passed to the constructor (or the initialize method).</p>
+ *
+ */
+public class FacesWebContext extends WebContextBase {
+
+    // ------------------------------------------------------------ Constructors
+
+    /**
+     *
+     */
+    private static final long serialVersionUID = 20120724L;
+
+    /**
+     * <p>Construct an uninitialized {@link FacesWebContext} instance.</p>
+     */
+    public FacesWebContext() {
+    }
+
+    /**
+     * <p>Construct a {@link FacesWebContext} instance that is initialized
+     * with the specified JavaServer Faces API objects.</p>
+     *
+     * @param context The <code>FacesContext</code> for this request
+     */
+    public FacesWebContext(FacesContext context) {
+        initialize(context);
+    }
+
+    // ------------------------------------------------------ Instance Variables
+
+    /**
+     * <p>The <code>FacesContext</code> instance for the request represented
+     * by this {@link org.apache.commons.chain2.web.WebContext}.</p>
+     */
+    private FacesContext context = null;
+
+    // ---------------------------------------------------------- Public Methods
+
+    /**
+     * <p>Return the <code>FacesContext</code> instance for the request
+     * associated with this {@link FacesWebContext}.</p>
+     *
+     * @return The <code>FacesContext</code> for this request
+     */
+    public FacesContext getContext() {
+        return (this.context);
+    }
+
+    /**
+     * <p>Initialize (or reinitialize) this {@link FacesWebContext} instance
+     * for the specified JavaServer Faces API objects.</p>
+     *
+     * @param context The <code>FacesContext</code> for this request
+     */
+    public void initialize(FacesContext context) {
+        this.context = context;
+    }
+
+    /**
+     * <p>Release references to allocated resources acquired in
+     * <code>initialize()</code> of via subsequent processing.  After this
+     * method is called, subsequent calls to any other method than
+     * <code>initialize()</code> will return undefined results.</p>
+     */
+    public void release() {
+        context = null;
+    }
+
+    // ------------------------------------------------------ WebContextBase Methods
+
+    /**
+     * See the {@link org.apache.commons.chain2.web.WebContext}'s Javadoc.
+     *
+     * @return Application scope Map.
+     */
+    public Map<String, Object> getApplicationScope() {
+        @SuppressWarnings("unchecked") // Assume faces is following contract
+        Map<String, Object> scope = context.getExternalContext().getApplicationMap();
+        return (scope);
+    }
+
+    /**
+     * See the {@link org.apache.commons.chain2.web.WebContext}'s Javadoc.
+     *
+     * @return Header values Map.
+     */
+    public Map<String, String> getHeader() {
+        @SuppressWarnings("unchecked") // Assume faces is following contract
+        Map<String, String> headers = context.getExternalContext().getRequestHeaderMap();
+
+        return (headers);
+    }
+
+    /**
+     * See the {@link org.apache.commons.chain2.web.WebContext}'s Javadoc.
+     *
+     * @return Header values Map.
+     */
+    public Map<String, String[]> getHeaderValues() {
+        @SuppressWarnings("unchecked") // Assume faces is following contract
+        Map<String, String[]> headerValues = context.getExternalContext().getRequestHeaderValuesMap();
+
+        return (headerValues);
+    }
+
+    /**
+     * See the {@link org.apache.commons.chain2.web.WebContext}'s Javadoc.
+     *
+     * @return Initialization parameter Map.
+     */
+    public Map<String, String> getInitParam() {
+        @SuppressWarnings("unchecked") // Assume faces is following contract
+        Map<String, String> initParams = context.getExternalContext().getInitParameterMap();
+
+        return (initParams);
+    }
+
+    /**
+     * See the {@link org.apache.commons.chain2.web.WebContext}'s Javadoc.
+     *
+     * @return Request parameter Map.
+     */
+    public Map<String, String> getParam() {
+        @SuppressWarnings("unchecked")
+        Map<String, String> params = context.getExternalContext().getRequestParameterMap();
+
+        return (params);
+    }
+
+    /**
+     * See the {@link org.apache.commons.chain2.web.WebContext}'s Javadoc.
+     *
+     * @return Request parameter Map.
+     */
+    public Map<String, String[]> getParamValues() {
+        @SuppressWarnings("unchecked") // Assume faces is following contract
+        Map<String, String[]> paramValues = context.getExternalContext().getRequestParameterValuesMap();
+
+        return (paramValues);
+    }
+
+    /**
+     * See the {@link org.apache.commons.chain2.web.WebContext}'s Javadoc.
+     *
+     * @return Map of Cookies.
+     * @since 1.1
+     */
+    public Map<String, Cookie> getCookies() {
+        @SuppressWarnings("unchecked") // Assume faces is following contract
+        Map<String, Object> facesCookieMap = context.getExternalContext().getRequestCookieMap();
+
+        /* This ugly hack was done because the faces API implements
+         * the cookie collection using <String, Object> instead of <String, Cookie>.
+         * So we painstakingly check for type safety and cast it as a Map<String, Cookie>.
+         */
+        Iterator<Object> itr = facesCookieMap.values().iterator();
+
+        if (itr.hasNext()) {
+            Object cookieObj = itr.next();
+
+            if (cookieObj instanceof Cookie) {
+                // See comment above about type safety check
+                @SuppressWarnings({ "unchecked", "rawtypes" })
+                Map<String, Cookie> cookieMap = Collections.checkedMap(
+                        (Map) facesCookieMap, String.class, Cookie.class);
+
+                return cookieMap;
+            } else {
+                String msg = "Could not cast cookie Map into <String, Cookie>. " +
+                        "Actual Cookie type is: " + cookieObj.getClass().toString();
+                throw new ClassCastException(msg);
+            }
+        } else {
+            return Collections.emptyMap();
+        }
+    }
+
+    /**
+     * See the {@link org.apache.commons.chain2.web.WebContext}'s Javadoc.
+     *
+     * @return Request scope Map.
+     */
+    public Map<String, Object> getRequestScope() {
+        @SuppressWarnings("unchecked")  // Assume faces is following contract
+        Map<String, Object> scope = context.getExternalContext().getRequestMap();
+
+        return (scope);
+    }
+
+    /**
+     * See the {@link org.apache.commons.chain2.web.WebContext}'s Javadoc.
+     *
+     * @return Session scope Map.
+     */
+    public Map<String, Object> getSessionScope() {
+        @SuppressWarnings("unchecked")  // Assume faces is following contract
+        Map<String, Object> scope = context.getExternalContext().getSessionMap();
+
+        return (scope);
+    }
+
+}
diff --git a/web/src/main/java/org/apache/commons/chain2/web/portlet/PortletWebContext.java b/web/src/main/java/org/apache/commons/chain2/web/portlet/PortletWebContext.java
index 0e541fa..de6d277 100644
--- a/web/src/main/java/org/apache/commons/chain2/web/portlet/PortletWebContext.java
+++ b/web/src/main/java/org/apache/commons/chain2/web/portlet/PortletWebContext.java
@@ -1,311 +1,311 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.chain2.web.portlet;
-
-import org.apache.commons.chain2.web.WebContextBase;
-
-import javax.portlet.PortletContext;
-import javax.portlet.PortletRequest;
-import javax.portlet.PortletResponse;
-import javax.servlet.http.Cookie;
-import java.util.Collections;
-import java.util.Map;
-
-/**
- * <p>Concrete implementation of {@link org.apache.commons.chain2.web.WebContext} suitable for use in
- * portlets.  The abstract methods are mapped to the appropriate
- * collections of the underlying portlet context, request, and response
- * instances that are passed to the constructor (or the initialize method).</p>
- *
- */
-public class PortletWebContext extends WebContextBase {
-
-    /**
-     *
-     */
-    private static final long serialVersionUID = 20120724L;
-
-    // ------------------------------------------------------------ Constructors
-
-    /**
-     * <p>Construct an uninitialized {@link PortletWebContext} instance.</p>
-     */
-    public PortletWebContext() {
-    }
-
-    /**
-     * <p>Construct a {@link PortletWebContext} instance that is initialized
-     * with the specified Portlet API objects.</p>
-     *
-     * @param context The <code>PortletContext</code> for this web application
-     * @param request The <code>PortletRequest</code> for this request
-     * @param response The <code>PortletResponse</code> for this request
-     */
-    public PortletWebContext(PortletContext context,
-                             PortletRequest request,
-                             PortletResponse response) {
-        initialize(context, request, response);
-    }
-
-    // ------------------------------------------------------ Instance Variables
-
-    /**
-     * <p>The lazily instantiated <code>Map</code> of application scope
-     * attributes.</p>
-     */
-    private Map<String, Object> applicationScope = null;
-
-    /**
-     * <p>The <code>PortletContext</code> for this web application.</p>
-     */
-    private PortletContext context = null;
-
-    /**
-     * <p>The lazily instantiated <code>Map</code> of header name-value
-     * combinations (immutable).</p>
-     */
-    private Map<String, String> header = null;
-
-    /**
-     * <p>The lazily instantitated <code>Map</code> of header name-values
-     * combinations (immutable).</p>
-     */
-    private Map<String, String[]> headerValues = null;
-
-    /**
-     * <p>The lazily instantiated <code>Map</code> of context initialization
-     * parameters.</p>
-     */
-    private Map<String, String> initParam = null;
-
-    /**
-     * <p>The lazily instantiated <code>Map</code> of request
-     * parameter name-value.</p>
-     */
-    private Map<String, String> param = null;
-
-    /**
-     * <p>The lazily instantiated <code>Map</code> of request
-     * parameter name-values.</p>
-     */
-    private Map<String, String[]> paramValues = null;
-
-    /**
-     * <p>The <code>PortletRequest</code> for this request.</p>
-     */
-    private PortletRequest request = null;
-
-    /**
-     * <p>The lazily instantiated <code>Map</code> of request scope
-     * attributes.</p>
-     */
-    private Map<String, Object> requestScope = null;
-
-    /**
-     * <p>The <code>PortletResponse</code> for this request.</p>
-     */
-    private PortletResponse response = null;
-
-    /**
-     * <p>The lazily instantiated <code>Map</code> of session scope
-     * attributes.</p>
-     */
-    private Map<String, Object> sessionScope = null;
-
-    // ---------------------------------------------------------- Public Methods
-
-    /**
-     * <p>Return the {@link PortletContext} for this context.</p>
-     *
-     * @return The <code>PortletContext</code> for this request
-     */
-    public PortletContext getContext() {
-        return (this.context);
-    }
-
-    /**
-     * <p>Return the {@link PortletRequest} for this context.</p>
-     *
-     * @return The <code>PortletRequest</code> for this context.
-     */
-    public PortletRequest getRequest() {
-        return (this.request);
-    }
-
-    /**
-     * <p>Return the {@link PortletResponse} for this context.</p>
-     *
-     * @return The <code>PortletResponse</code> for this context.
-     */
-    public PortletResponse getResponse() {
-        return (this.response);
-    }
-
-    /**
-     * <p>Initialize (or reinitialize) this {@link PortletWebContext} instance
-     * for the specified Portlet API objects.</p>
-     *
-     * @param context The <code>PortletContext</code> for this web application
-     * @param request The <code>PortletRequest</code> for this request
-     * @param response The <code>PortletResponse</code> for this request
-     */
-    public void initialize(PortletContext context,
-                           PortletRequest request,
-                           PortletResponse response) {
-        // Save the specified Portlet API object references
-        this.context = context;
-        this.request = request;
-        this.response = response;
-
-        // Perform other setup as needed
-    }
-
-    /**
-     * <p>Release references to allocated resources acquired in
-     * <code>initialize()</code> of via subsequent processing.  After this
-     * method is called, subsequent calls to any other method than
-     * <code>initialize()</code> will return undefined results.</p>
-     */
-    public void release() {
-        // Release references to allocated collections
-        applicationScope = null;
-        header = null;
-        headerValues = null;
-        initParam = null;
-        param = null;
-        paramValues = null;
-        requestScope = null;
-        sessionScope = null;
-
-        // Release references to Portlet API objects
-        context = null;
-        request = null;
-        response = null;
-    }
-
-    // ------------------------------------------------------ WebContextBase Methods
-
-    /**
-     * See the {@link org.apache.commons.chain2.web.WebContext}'s Javadoc.
-     *
-     * @return Application scope Map.
-     */
-    public Map<String, Object> getApplicationScope() {
-        if ((applicationScope == null) && (context != null)) {
-            applicationScope = new PortletApplicationScopeMap(context);
-        }
-        return (applicationScope);
-    }
-
-    /**
-     * See the {@link org.apache.commons.chain2.web.WebContext}'s Javadoc.
-     *
-     * @return Header values Map.
-     */
-    public Map<String, String> getHeader() {
-        if ((header == null) && (request != null)) {
-            // header = new PortletHeaderMap(request);
-            header = Collections.emptyMap();
-        }
-        return (header);
-    }
-
-    /**
-     * See the {@link org.apache.commons.chain2.web.WebContext}'s Javadoc.
-     *
-     * @return Header values Map.
-     */
-    public Map<String, String[]> getHeaderValues() {
-        if ((headerValues == null) && (request != null)) {
-            // headerValues = new PortletHeaderValuesMap(request);
-            headerValues = Collections.emptyMap();
-        }
-        return (headerValues);
-    }
-
-    /**
-     * See the {@link org.apache.commons.chain2.web.WebContext}'s Javadoc.
-     *
-     * @return Initialization parameter Map.
-     */
-    public Map<String, String> getInitParam() {
-        if ((initParam == null) && (context != null)) {
-            initParam = new PortletInitParamMap(context);
-        }
-        return (initParam);
-    }
-
-    /**
-     * See the {@link org.apache.commons.chain2.web.WebContext}'s Javadoc.
-     *
-     * @return Request parameter Map.
-     */
-    public Map<String, String> getParam() {
-        if ((param == null) && (request != null)) {
-            param = new PortletParamMap(request);
-        }
-        return (param);
-    }
-
-    /**
-     * See the {@link org.apache.commons.chain2.web.WebContext}'s Javadoc.
-     *
-     * @return Request parameter Map.
-     */
-    public Map<String, String[]> getParamValues() {
-        if ((paramValues == null) && (request != null)) {
-            paramValues = new PortletParamValuesMap(request);
-        }
-        return (paramValues);
-    }
-
-    /**
-     * Returns an empty Map - portlets don't support Cookies.
-     *
-     * @return An empty Map.
-     * @since Chain 1.1
-     */
-    public Map<String, Cookie> getCookies() {
-        return Collections.emptyMap();
-    }
-
-    /**
-     * See the {@link org.apache.commons.chain2.web.WebContext}'s Javadoc.
-     *
-     * @return Request scope Map.
-     */
-    public Map<String, Object> getRequestScope() {
-        if ((requestScope == null) && (request != null)) {
-            requestScope = new PortletRequestScopeMap(request);
-        }
-        return (requestScope);
-    }
-
-    /**
-     * See the {@link org.apache.commons.chain2.web.WebContext}'s Javadoc.
-     *
-     * @return Session scope Map.
-     */
-    public Map<String, Object> getSessionScope() {
-        if ((sessionScope == null) && (request != null)) {
-            sessionScope =
-            new PortletSessionScopeMap(request);
-        }
-        return (sessionScope);
-    }
-
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.chain2.web.portlet;
+
+import org.apache.commons.chain2.web.WebContextBase;
+
+import javax.portlet.PortletContext;
+import javax.portlet.PortletRequest;
+import javax.portlet.PortletResponse;
+import javax.servlet.http.Cookie;
+import java.util.Collections;
+import java.util.Map;
+
+/**
+ * <p>Concrete implementation of {@link org.apache.commons.chain2.web.WebContext} suitable for use in
+ * portlets.  The abstract methods are mapped to the appropriate
+ * collections of the underlying portlet context, request, and response
+ * instances that are passed to the constructor (or the initialize method).</p>
+ *
+ */
+public class PortletWebContext extends WebContextBase {
+
+    /**
+     *
+     */
+    private static final long serialVersionUID = 20120724L;
+
+    // ------------------------------------------------------------ Constructors
+
+    /**
+     * <p>Construct an uninitialized {@link PortletWebContext} instance.</p>
+     */
+    public PortletWebContext() {
+    }
+
+    /**
+     * <p>Construct a {@link PortletWebContext} instance that is initialized
+     * with the specified Portlet API objects.</p>
+     *
+     * @param context The <code>PortletContext</code> for this web application
+     * @param request The <code>PortletRequest</code> for this request
+     * @param response The <code>PortletResponse</code> for this request
+     */
+    public PortletWebContext(PortletContext context,
+                             PortletRequest request,
+                             PortletResponse response) {
+        initialize(context, request, response);
+    }
+
+    // ------------------------------------------------------ Instance Variables
+
+    /**
+     * <p>The lazily instantiated <code>Map</code> of application scope
+     * attributes.</p>
+     */
+    private Map<String, Object> applicationScope = null;
+
+    /**
+     * <p>The <code>PortletContext</code> for this web application.</p>
+     */
+    private PortletContext context = null;
+
+    /**
+     * <p>The lazily instantiated <code>Map</code> of header name-value
+     * combinations (immutable).</p>
+     */
+    private Map<String, String> header = null;
+
+    /**
+     * <p>The lazily instantitated <code>Map</code> of header name-values
+     * combinations (immutable).</p>
+     */
+    private Map<String, String[]> headerValues = null;
+
+    /**
+     * <p>The lazily instantiated <code>Map</code> of context initialization
+     * parameters.</p>
+     */
+    private Map<String, String> initParam = null;
+
+    /**
+     * <p>The lazily instantiated <code>Map</code> of request
+     * parameter name-value.</p>
+     */
+    private Map<String, String> param = null;
+
+    /**
+     * <p>The lazily instantiated <code>Map</code> of request
+     * parameter name-values.</p>
+     */
+    private Map<String, String[]> paramValues = null;
+
+    /**
+     * <p>The <code>PortletRequest</code> for this request.</p>
+     */
+    private PortletRequest request = null;
+
+    /**
+     * <p>The lazily instantiated <code>Map</code> of request scope
+     * attributes.</p>
+     */
+    private Map<String, Object> requestScope = null;
+
+    /**
+     * <p>The <code>PortletResponse</code> for this request.</p>
+     */
+    private PortletResponse response = null;
+
+    /**
+     * <p>The lazily instantiated <code>Map</code> of session scope
+     * attributes.</p>
+     */
+    private Map<String, Object> sessionScope = null;
+
+    // ---------------------------------------------------------- Public Methods
+
+    /**
+     * <p>Return the {@link PortletContext} for this context.</p>
+     *
+     * @return The <code>PortletContext</code> for this request
+     */
+    public PortletContext getContext() {
+        return (this.context);
+    }
+
+    /**
+     * <p>Return the {@link PortletRequest} for this context.</p>
+     *
+     * @return The <code>PortletRequest</code> for this context.
+     */
+    public PortletRequest getRequest() {
+        return (this.request);
+    }
+
+    /**
+     * <p>Return the {@link PortletResponse} for this context.</p>
+     *
+     * @return The <code>PortletResponse</code> for this context.
+     */
+    public PortletResponse getResponse() {
+        return (this.response);
+    }
+
+    /**
+     * <p>Initialize (or reinitialize) this {@link PortletWebContext} instance
+     * for the specified Portlet API objects.</p>
+     *
+     * @param context The <code>PortletContext</code> for this web application
+     * @param request The <code>PortletRequest</code> for this request
+     * @param response The <code>PortletResponse</code> for this request
+     */
+    public void initialize(PortletContext context,
+                           PortletRequest request,
+                           PortletResponse response) {
+        // Save the specified Portlet API object references
+        this.context = context;
+        this.request = request;
+        this.response = response;
+
+        // Perform other setup as needed
+    }
+
+    /**
+     * <p>Release references to allocated resources acquired in
+     * <code>initialize()</code> of via subsequent processing.  After this
+     * method is called, subsequent calls to any other method than
+     * <code>initialize()</code> will return undefined results.</p>
+     */
+    public void release() {
+        // Release references to allocated collections
+        applicationScope = null;
+        header = null;
+        headerValues = null;
+        initParam = null;
+        param = null;
+        paramValues = null;
+        requestScope = null;
+        sessionScope = null;
+
+        // Release references to Portlet API objects
+        context = null;
+        request = null;
+        response = null;
+    }
+
+    // ------------------------------------------------------ WebContextBase Methods
+
+    /**
+     * See the {@link org.apache.commons.chain2.web.WebContext}'s Javadoc.
+     *
+     * @return Application scope Map.
+     */
+    public Map<String, Object> getApplicationScope() {
+        if ((applicationScope == null) && (context != null)) {
+            applicationScope = new PortletApplicationScopeMap(context);
+        }
+        return (applicationScope);
+    }
+
+    /**
+     * See the {@link org.apache.commons.chain2.web.WebContext}'s Javadoc.
+     *
+     * @return Header values Map.
+     */
+    public Map<String, String> getHeader() {
+        if ((header == null) && (request != null)) {
+            // header = new PortletHeaderMap(request);
+            header = Collections.emptyMap();
+        }
+        return (header);
+    }
+
+    /**
+     * See the {@link org.apache.commons.chain2.web.WebContext}'s Javadoc.
+     *
+     * @return Header values Map.
+     */
+    public Map<String, String[]> getHeaderValues() {
+        if ((headerValues == null) && (request != null)) {
+            // headerValues = new PortletHeaderValuesMap(request);
+            headerValues = Collections.emptyMap();
+        }
+        return (headerValues);
+    }
+
+    /**
+     * See the {@link org.apache.commons.chain2.web.WebContext}'s Javadoc.
+     *
+     * @return Initialization parameter Map.
+     */
+    public Map<String, String> getInitParam() {
+        if ((initParam == null) && (context != null)) {
+            initParam = new PortletInitParamMap(context);
+        }
+        return (initParam);
+    }
+
+    /**
+     * See the {@link org.apache.commons.chain2.web.WebContext}'s Javadoc.
+     *
+     * @return Request parameter Map.
+     */
+    public Map<String, String> getParam() {
+        if ((param == null) && (request != null)) {
+            param = new PortletParamMap(request);
+        }
+        return (param);
+    }
+
+    /**
+     * See the {@link org.apache.commons.chain2.web.WebContext}'s Javadoc.
+     *
+     * @return Request parameter Map.
+     */
+    public Map<String, String[]> getParamValues() {
+        if ((paramValues == null) && (request != null)) {
+            paramValues = new PortletParamValuesMap(request);
+        }
+        return (paramValues);
+    }
+
+    /**
+     * Returns an empty Map - portlets don't support Cookies.
+     *
+     * @return An empty Map.
+     * @since 1.1
+     */
+    public Map<String, Cookie> getCookies() {
+        return Collections.emptyMap();
+    }
+
+    /**
+     * See the {@link org.apache.commons.chain2.web.WebContext}'s Javadoc.
+     *
+     * @return Request scope Map.
+     */
+    public Map<String, Object> getRequestScope() {
+        if ((requestScope == null) && (request != null)) {
+            requestScope = new PortletRequestScopeMap(request);
+        }
+        return (requestScope);
+    }
+
+    /**
+     * See the {@link org.apache.commons.chain2.web.WebContext}'s Javadoc.
+     *
+     * @return Session scope Map.
+     */
+    public Map<String, Object> getSessionScope() {
+        if ((sessionScope == null) && (request != null)) {
+            sessionScope =
+            new PortletSessionScopeMap(request);
+        }
+        return (sessionScope);
+    }
+
+}
diff --git a/web/src/main/java/org/apache/commons/chain2/web/servlet/PathInfoMapper.java b/web/src/main/java/org/apache/commons/chain2/web/servlet/PathInfoMapper.java
index 5b0b0c5..b3f4986 100644
--- a/web/src/main/java/org/apache/commons/chain2/web/servlet/PathInfoMapper.java
+++ b/web/src/main/java/org/apache/commons/chain2/web/servlet/PathInfoMapper.java
@@ -1,86 +1,86 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.chain2.web.servlet;
-
-import org.apache.commons.chain2.Catalog;
-import org.apache.commons.chain2.Command;
-import org.apache.commons.chain2.Context;
-import org.apache.commons.chain2.base.LookupCommand;
-
-import javax.servlet.http.HttpServletRequest;
-
-/**
- * <p>{@link Command} that uses the "path info" component of the request URI
- * to select a {@link Command} from the appropriate {@link Catalog}, and
- * execute it.  To use this command, you would typically map an instance
- * of {@link ChainProcessor} to a wildcard pattern like "/execute/*" and
- * then arrange that this is the default command to be executed.  In such
- * an environment, a request for the context-relative URI "/execute/foo"
- * would cause the "/foo" command to be loaded and executed.</p>
- *
- */
-public class PathInfoMapper extends LookupCommand<String, Object, ServletWebContext<String, Object>> {
-
-    // --------------------------------------------------------- Command Methods
-
-    /**
-     * <p>Look up the extra path information for this request, and use it to
-     * select an appropriate {@link Command} to be executed.
-     *
-     * @param context Context for the current request
-     * @return The name of the {@link Command} instance
-     *
-     * @since Chain 1.2
-     */
-    @Override
-    protected String getCommandName(ServletWebContext<String, Object> context) {
-        // Look up the extra path information for this request
-        HttpServletRequest request = context.getRequest();
-        String pathInfo = (String)
-            request.getAttribute("javax.servlet.include.path_info");
-        if (pathInfo == null) {
-            pathInfo = request.getPathInfo();
-        }
-
-        return pathInfo;
-    }
-
-    /**
-     * <p>Return the {@link Catalog} to look up the {@link Command} in.</p>
-     *
-     * @param context {@link Context} for this request
-     * @return The catalog.
-     * @throws IllegalArgumentException if no {@link Catalog}
-     *  can be found
-     *
-     * @since Chain 1.2
-     */
-    @Override
-    protected Catalog<String, Object, ServletWebContext<String, Object>>
-            getCatalog(ServletWebContext<String, Object> context) {
-        /* Assume that the object returned will be a catalog because of chain's
-         * historical contract. */
-        @SuppressWarnings("unchecked")
-        Catalog<String, Object, ServletWebContext<String, Object>> catalog =
-                (Catalog<String, Object, ServletWebContext<String, Object>>) context.get(getCatalogName());
-        if (catalog == null) {
-            catalog = super.getCatalog(context);
-        }
-        return catalog;
-    }
-
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.chain2.web.servlet;
+
+import org.apache.commons.chain2.Catalog;
+import org.apache.commons.chain2.Command;
+import org.apache.commons.chain2.Context;
+import org.apache.commons.chain2.base.LookupCommand;
+
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ * <p>{@link Command} that uses the "path info" component of the request URI
+ * to select a {@link Command} from the appropriate {@link Catalog}, and
+ * execute it.  To use this command, you would typically map an instance
+ * of {@link ChainProcessor} to a wildcard pattern like "/execute/*" and
+ * then arrange that this is the default command to be executed.  In such
+ * an environment, a request for the context-relative URI "/execute/foo"
+ * would cause the "/foo" command to be loaded and executed.</p>
+ *
+ */
+public class PathInfoMapper extends LookupCommand<String, Object, ServletWebContext<String, Object>> {
+
+    // --------------------------------------------------------- Command Methods
+
+    /**
+     * <p>Look up the extra path information for this request, and use it to
+     * select an appropriate {@link Command} to be executed.
+     *
+     * @param context Context for the current request
+     * @return The name of the {@link Command} instance
+     *
+     * @since 1.2
+     */
+    @Override
+    protected String getCommandName(ServletWebContext<String, Object> context) {
+        // Look up the extra path information for this request
+        HttpServletRequest request = context.getRequest();
+        String pathInfo = (String)
+            request.getAttribute("javax.servlet.include.path_info");
+        if (pathInfo == null) {
+            pathInfo = request.getPathInfo();
+        }
+
+        return pathInfo;
+    }
+
+    /**
+     * <p>Return the {@link Catalog} to look up the {@link Command} in.</p>
+     *
+     * @param context {@link Context} for this request
+     * @return The catalog.
+     * @throws IllegalArgumentException if no {@link Catalog}
+     *  can be found
+     *
+     * @since 1.2
+     */
+    @Override
+    protected Catalog<String, Object, ServletWebContext<String, Object>>
+            getCatalog(ServletWebContext<String, Object> context) {
+        /* Assume that the object returned will be a catalog because of chain's
+         * historical contract. */
+        @SuppressWarnings("unchecked")
+        Catalog<String, Object, ServletWebContext<String, Object>> catalog =
+                (Catalog<String, Object, ServletWebContext<String, Object>>) context.get(getCatalogName());
+        if (catalog == null) {
+            catalog = super.getCatalog(context);
+        }
+        return catalog;
+    }
+
+}
diff --git a/web/src/main/java/org/apache/commons/chain2/web/servlet/RequestParameterMapper.java b/web/src/main/java/org/apache/commons/chain2/web/servlet/RequestParameterMapper.java
index c4e2a22..ef44db6 100644
--- a/web/src/main/java/org/apache/commons/chain2/web/servlet/RequestParameterMapper.java
+++ b/web/src/main/java/org/apache/commons/chain2/web/servlet/RequestParameterMapper.java
@@ -1,113 +1,113 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.chain2.web.servlet;
-
-import org.apache.commons.chain2.Catalog;
-import org.apache.commons.chain2.Command;
-import org.apache.commons.chain2.Context;
-import org.apache.commons.chain2.base.LookupCommand;
-
-import javax.servlet.http.HttpServletRequest;
-
-/**
- * <p>{@link Command} that uses a specified request parameter
- * to select a {@link Command} from the appropriate {@link Catalog}, and
- * execute it.  To use this command, you would typically map an instance
- * of {@link ChainProcessor} to a wildcard pattern like "*.execute" and
- * then arrange that this is the default command to be executed.  In such
- * an environment, a request for the context-relative path
- * "/foo.execute?command=bar" would cause the "/bar" command to be loaded
- * and executed.</p>
- *
- */
-public class RequestParameterMapper
-        extends LookupCommand<String, Object, ServletWebContext<String, Object>> {
-
-    // ------------------------------------------------------ Instance Variables
-
-    private String catalogKey = ChainProcessor.CATALOG_DEFAULT;
-
-    private String parameter = "command";
-
-    // -------------------------------------------------------------- Properties
-
-    /**
-     * <p>Return the context key under which our {@link Catalog} has been
-     * stored.</p>
-     *
-     * @return The context key for the Catalog.
-     */
-    public String getCatalogKey() {
-        return (this.catalogKey);
-    }
-
-    /**
-     * <p>Set the name of the request parameter to use for
-     * selecting the {@link Command} to be executed.</p>
-     *
-     * @param parameter The new parameter name
-     */
-    public void setParameter(String parameter) {
-        this.parameter = parameter;
-    }
-
-    // --------------------------------------------------------- Command Methods
-
-    /**
-     * <p>Look up the specified request parameter for this request, and use it
-     * to select an appropriate {@link Command} to be executed.
-     *
-     * @param context Context for the current request
-     * @return The name of the {@link Command} instance
-     *
-     * @since Chain 1.2
-     */
-    @Override
-    protected String getCommandName(ServletWebContext context) {
-        // Look up the specified request parameter for this request
-        HttpServletRequest request = context.getRequest();
-        String value = request.getParameter(getCatalogName());
-        return value;
-    }
-
-    /**
-     * <p>Return the {@link Catalog} to look up the {@link Command} in.</p>
-     *
-     * @param context {@link Context} for this request
-     * @return The catalog.
-     * @throws IllegalArgumentException if no {@link Catalog}
-     *  can be found
-     *
-     * @since Chain 1.2
-     */
-    @Override
-    protected Catalog<String, Object, ServletWebContext<String, Object>>
-            getCatalog(ServletWebContext<String, Object> context) {
-        /* Assume that the returned value will be null or of a valid catalog
-         * type according to chain's historical contract. */
-        @SuppressWarnings("unchecked")
-        Catalog<String, Object, ServletWebContext<String, Object>> catalog =
-                (Catalog<String, Object, ServletWebContext<String, Object>>) context.get(getCatalogKey());
-
-        if (catalog == null) {
-            catalog = super.getCatalog(context);
-        }
-
-        return catalog;
-    }
-
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.chain2.web.servlet;
+
+import org.apache.commons.chain2.Catalog;
+import org.apache.commons.chain2.Command;
+import org.apache.commons.chain2.Context;
+import org.apache.commons.chain2.base.LookupCommand;
+
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ * <p>{@link Command} that uses a specified request parameter
+ * to select a {@link Command} from the appropriate {@link Catalog}, and
+ * execute it.  To use this command, you would typically map an instance
+ * of {@link ChainProcessor} to a wildcard pattern like "*.execute" and
+ * then arrange that this is the default command to be executed.  In such
+ * an environment, a request for the context-relative path
+ * "/foo.execute?command=bar" would cause the "/bar" command to be loaded
+ * and executed.</p>
+ *
+ */
+public class RequestParameterMapper
+        extends LookupCommand<String, Object, ServletWebContext<String, Object>> {
+
+    // ------------------------------------------------------ Instance Variables
+
+    private String catalogKey = ChainProcessor.CATALOG_DEFAULT;
+
+    private String parameter = "command";
+
+    // -------------------------------------------------------------- Properties
+
+    /**
+     * <p>Return the context key under which our {@link Catalog} has been
+     * stored.</p>
+     *
+     * @return The context key for the Catalog.
+     */
+    public String getCatalogKey() {
+        return (this.catalogKey);
+    }
+
+    /**
+     * <p>Set the name of the request parameter to use for
+     * selecting the {@link Command} to be executed.</p>
+     *
+     * @param parameter The new parameter name
+     */
+    public void setParameter(String parameter) {
+        this.parameter = parameter;
+    }
+
+    // --------------------------------------------------------- Command Methods
+
+    /**
+     * <p>Look up the specified request parameter for this request, and use it
+     * to select an appropriate {@link Command} to be executed.
+     *
+     * @param context Context for the current request
+     * @return The name of the {@link Command} instance
+     *
+     * @since 1.2
+     */
+    @Override
+    protected String getCommandName(ServletWebContext context) {
+        // Look up the specified request parameter for this request
+        HttpServletRequest request = context.getRequest();
+        String value = request.getParameter(getCatalogName());
+        return value;
+    }
+
+    /**
+     * <p>Return the {@link Catalog} to look up the {@link Command} in.</p>
+     *
+     * @param context {@link Context} for this request
+     * @return The catalog.
+     * @throws IllegalArgumentException if no {@link Catalog}
+     *  can be found
+     *
+     * @since 1.2
+     */
+    @Override
+    protected Catalog<String, Object, ServletWebContext<String, Object>>
+            getCatalog(ServletWebContext<String, Object> context) {
+        /* Assume that the returned value will be null or of a valid catalog
+         * type according to chain's historical contract. */
+        @SuppressWarnings("unchecked")
+        Catalog<String, Object, ServletWebContext<String, Object>> catalog =
+                (Catalog<String, Object, ServletWebContext<String, Object>>) context.get(getCatalogKey());
+
+        if (catalog == null) {
+            catalog = super.getCatalog(context);
+        }
+
+        return catalog;
+    }
+
+}
diff --git a/web/src/main/java/org/apache/commons/chain2/web/servlet/ServletCookieMap.java b/web/src/main/java/org/apache/commons/chain2/web/servlet/ServletCookieMap.java
index 5c15826..b33ed61 100644
--- a/web/src/main/java/org/apache/commons/chain2/web/servlet/ServletCookieMap.java
+++ b/web/src/main/java/org/apache/commons/chain2/web/servlet/ServletCookieMap.java
@@ -1,149 +1,149 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.chain2.web.servlet;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.Cookie;
-
-import org.apache.commons.chain2.web.MapEntry;
-
-/**
- * <p>Private implementation of <code>Map</code> for servlet cookies</p>
- *
- * @since Chain 1.1
- */
-final class ServletCookieMap implements Map<String, Cookie> {
-
-    public ServletCookieMap(HttpServletRequest request) {
-        this.request = request;
-    }
-
-    private final HttpServletRequest request;
-
-    public void clear() {
-        throw new UnsupportedOperationException();
-    }
-
-    public boolean containsKey(Object key) {
-        return (get(key) != null);
-    }
-
-    public boolean containsValue(Object value) {
-        Cookie[] cookies = request.getCookies();
-        if (cookies != null) {
-            for (int i = 0; i < cookies.length; i++) {
-                if (cookies[i].equals(value)) {
-                    return true;
-                }
-            }
-        }
-        return (false);
-    }
-
-    public Set<Entry<String, Cookie>> entrySet() {
-        Set<Entry<String, Cookie>> set = new HashSet<Entry<String, Cookie>>();
-        Cookie[] cookies = request.getCookies();
-        if (cookies != null) {
-            for (int i = 0; i < cookies.length; i++) {
-                set.add(new MapEntry<String, Cookie>(cookies[i].getName(), cookies[i], false));
-            }
-        }
-        return (set);
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        return (request.equals(o));
-    }
-
-    public Cookie get(Object key) {
-        Cookie[] cookies = request.getCookies();
-        if (cookies != null) {
-            for (int i = 0; i < cookies.length; i++) {
-                if (cookies[i].getName().equals(key(key))) {
-                    return cookies[i];
-                }
-            }
-        }
-        return null;
-    }
-
-    @Override
-    public int hashCode() {
-        return (request.hashCode());
-    }
-
-    public boolean isEmpty() {
-        return (size() < 1);
-    }
-
-    public Set<String> keySet() {
-        Set<String> set = new HashSet<String>();
-        Cookie[] cookies = request.getCookies();
-        if (cookies != null) {
-            for (int i = 0; i < cookies.length; i++) {
-                set.add(cookies[i].getName());
-            }
-        }
-        return (set);
-    }
-
-    public Cookie put(String key, Cookie value) {
-        throw new UnsupportedOperationException();
-    }
-
-    public void putAll(Map<? extends String, ? extends Cookie> map) {
-        throw new UnsupportedOperationException();
-    }
-
-    public Cookie remove(Object key) {
-        throw new UnsupportedOperationException();
-    }
-
-    public int size() {
-        Cookie[] cookies = request.getCookies();
-        return (cookies == null ?  0 : cookies.length);
-    }
-
-    public Collection<Cookie> values() {
-        List<Cookie> list = new ArrayList<Cookie>(size());
-        Cookie[] cookies = request.getCookies();
-        if (cookies != null) {
-            for (int i = 0; i < cookies.length; i++) {
-                list.add(cookies[i]);
-            }
-        }
-        return (list);
-    }
-
-    private String key(Object key) {
-        if (key == null) {
-            throw new IllegalArgumentException();
-        } else if (key instanceof String) {
-            return ((String) key);
-        } else {
-            return (key.toString());
-        }
-    }
-
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.chain2.web.servlet;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.Cookie;
+
+import org.apache.commons.chain2.web.MapEntry;
+
+/**
+ * <p>Private implementation of <code>Map</code> for servlet cookies</p>
+ *
+ * @since 1.1
+ */
+final class ServletCookieMap implements Map<String, Cookie> {
+
+    public ServletCookieMap(HttpServletRequest request) {
+        this.request = request;
+    }
+
+    private final HttpServletRequest request;
+
+    public void clear() {
+        throw new UnsupportedOperationException();
+    }
+
+    public boolean containsKey(Object key) {
+        return (get(key) != null);
+    }
+
+    public boolean containsValue(Object value) {
+        Cookie[] cookies = request.getCookies();
+        if (cookies != null) {
+            for (int i = 0; i < cookies.length; i++) {
+                if (cookies[i].equals(value)) {
+                    return true;
+                }
+            }
+        }
+        return (false);
+    }
+
+    public Set<Entry<String, Cookie>> entrySet() {
+        Set<Entry<String, Cookie>> set = new HashSet<Entry<String, Cookie>>();
+        Cookie[] cookies = request.getCookies();
+        if (cookies != null) {
+            for (int i = 0; i < cookies.length; i++) {
+                set.add(new MapEntry<String, Cookie>(cookies[i].getName(), cookies[i], false));
+            }
+        }
+        return (set);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        return (request.equals(o));
+    }
+
+    public Cookie get(Object key) {
+        Cookie[] cookies = request.getCookies();
+        if (cookies != null) {
+            for (int i = 0; i < cookies.length; i++) {
+                if (cookies[i].getName().equals(key(key))) {
+                    return cookies[i];
+                }
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public int hashCode() {
+        return (request.hashCode());
+    }
+
+    public boolean isEmpty() {
+        return (size() < 1);
+    }
+
+    public Set<String> keySet() {
+        Set<String> set = new HashSet<String>();
+        Cookie[] cookies = request.getCookies();
+        if (cookies != null) {
+            for (int i = 0; i < cookies.length; i++) {
+                set.add(cookies[i].getName());
+            }
+        }
+        return (set);
+    }
+
+    public Cookie put(String key, Cookie value) {
+        throw new UnsupportedOperationException();
+    }
+
+    public void putAll(Map<? extends String, ? extends Cookie> map) {
+        throw new UnsupportedOperationException();
+    }
+
+    public Cookie remove(Object key) {
+        throw new UnsupportedOperationException();
+    }
+
+    public int size() {
+        Cookie[] cookies = request.getCookies();
+        return (cookies == null ?  0 : cookies.length);
+    }
+
+    public Collection<Cookie> values() {
+        List<Cookie> list = new ArrayList<Cookie>(size());
+        Cookie[] cookies = request.getCookies();
+        if (cookies != null) {
+            for (int i = 0; i < cookies.length; i++) {
+                list.add(cookies[i]);
+            }
+        }
+        return (list);
+    }
+
+    private String key(Object key) {
+        if (key == null) {
+            throw new IllegalArgumentException();
+        } else if (key instanceof String) {
+            return ((String) key);
+        } else {
+            return (key.toString());
+        }
+    }
+
+}
diff --git a/web/src/main/java/org/apache/commons/chain2/web/servlet/ServletPathMapper.java b/web/src/main/java/org/apache/commons/chain2/web/servlet/ServletPathMapper.java
index e0cc390..8eeae5c 100644
--- a/web/src/main/java/org/apache/commons/chain2/web/servlet/ServletPathMapper.java
+++ b/web/src/main/java/org/apache/commons/chain2/web/servlet/ServletPathMapper.java
@@ -1,93 +1,93 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.chain2.web.servlet;
-
-import org.apache.commons.chain2.Catalog;
-import org.apache.commons.chain2.Command;
-import org.apache.commons.chain2.Context;
-import org.apache.commons.chain2.base.LookupCommand;
-
-import javax.servlet.http.HttpServletRequest;
-
-/**
- * <p>{@link Command} that uses the "servlet path" component of the request URI
- * to select a {@link Command} from the appropriate {@link Catalog}, and
- * execute it.  To use this command, you would typically map an instance
- * of {@link ChainProcessor} to an extension pattern like "*.execute" and
- * then arrange that this is the default command to be executed.  In such
- * an environment, a request for a context relative URI of "/foo.execute"
- * would cause the "/foo.execute" command to be loaded and executed.</p>
- *
- */
-public class ServletPathMapper extends LookupCommand<String, Object, ServletWebContext<String, Object>> {
-
-    // --------------------------------------------------------- Command Methods
-
-    /**
-     * <p>Look up the servlet path information for this request, and use it to
-     * select an appropriate {@link Command} to be executed.
-     *
-     * @param swcontext Context for the current request
-     * @return The name of the {@link Command} instance
-     *
-     * @since Chain 1.2
-     */
-    @Override
-    protected String getCommandName(ServletWebContext<String, Object> swcontext) {
-        // Look up the servlet path for this request
-        HttpServletRequest request = swcontext.getRequest();
-        String servletPath = (String)
-            request.getAttribute("javax.servlet.include.servlet_path");
-        if (servletPath == null) {
-            servletPath = request.getServletPath();
-        }
-
-        return servletPath;
-    }
-
-    /**
-     * <p>Return the {@link Catalog} to look up the {@link Command} in.</p>
-     *
-     * @param context {@link Context} for this request
-     * @return The catalog.
-     * @throws IllegalArgumentException if no {@link Catalog}
-     *  can be found
-     *
-     * @since Chain 1.2
-     */
-    @Override
-    protected Catalog<String, Object, ServletWebContext<String, Object>>
-            getCatalog(ServletWebContext<String, Object> context) {
-        /* If the object returned from the passed context is not a valid catalog
-         * then we use the super class's catalog extraction logic to pull it
-         * or to error gracefully.
-         */
-        Object testCatalog = context.get(getCatalogName());
-
-        /* Assume that the underlying implementation is following convention and
-         * returning a catalog with the current context.
-         */
-        @SuppressWarnings("unchecked")
-        Catalog<String, Object, ServletWebContext<String, Object>> catalog =
-                testCatalog instanceof Catalog ?
-                    (Catalog<String, Object, ServletWebContext<String, Object>>) testCatalog :
-                    super.getCatalog(context);
-
-        return catalog;
-    }
-
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.chain2.web.servlet;
+
+import org.apache.commons.chain2.Catalog;
+import org.apache.commons.chain2.Command;
+import org.apache.commons.chain2.Context;
+import org.apache.commons.chain2.base.LookupCommand;
+
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ * <p>{@link Command} that uses the "servlet path" component of the request URI
+ * to select a {@link Command} from the appropriate {@link Catalog}, and
+ * execute it.  To use this command, you would typically map an instance
+ * of {@link ChainProcessor} to an extension pattern like "*.execute" and
+ * then arrange that this is the default command to be executed.  In such
+ * an environment, a request for a context relative URI of "/foo.execute"
+ * would cause the "/foo.execute" command to be loaded and executed.</p>
+ *
+ */
+public class ServletPathMapper extends LookupCommand<String, Object, ServletWebContext<String, Object>> {
+
+    // --------------------------------------------------------- Command Methods
+
+    /**
+     * <p>Look up the servlet path information for this request, and use it to
+     * select an appropriate {@link Command} to be executed.
+     *
+     * @param swcontext Context for the current request
+     * @return The name of the {@link Command} instance
+     *
+     * @since 1.2
+     */
+    @Override
+    protected String getCommandName(ServletWebContext<String, Object> swcontext) {
+        // Look up the servlet path for this request
+        HttpServletRequest request = swcontext.getRequest();
+        String servletPath = (String)
+            request.getAttribute("javax.servlet.include.servlet_path");
+        if (servletPath == null) {
+            servletPath = request.getServletPath();
+        }
+
+        return servletPath;
+    }
+
+    /**
+     * <p>Return the {@link Catalog} to look up the {@link Command} in.</p>
+     *
+     * @param context {@link Context} for this request
+     * @return The catalog.
+     * @throws IllegalArgumentException if no {@link Catalog}
+     *  can be found
+     *
+     * @since 1.2
+     */
+    @Override
+    protected Catalog<String, Object, ServletWebContext<String, Object>>
+            getCatalog(ServletWebContext<String, Object> context) {
+        /* If the object returned from the passed context is not a valid catalog
+         * then we use the super class's catalog extraction logic to pull it
+         * or to error gracefully.
+         */
+        Object testCatalog = context.get(getCatalogName());
+
+        /* Assume that the underlying implementation is following convention and
+         * returning a catalog with the current context.
+         */
+        @SuppressWarnings("unchecked")
+        Catalog<String, Object, ServletWebContext<String, Object>> catalog =
+                testCatalog instanceof Catalog ?
+                    (Catalog<String, Object, ServletWebContext<String, Object>>) testCatalog :
+                    super.getCatalog(context);
+
+        return catalog;
+    }
+
+}
diff --git a/web/src/main/java/org/apache/commons/chain2/web/servlet/ServletWebContext.java b/web/src/main/java/org/apache/commons/chain2/web/servlet/ServletWebContext.java
index f303fc3..5f3f7c2 100644
--- a/web/src/main/java/org/apache/commons/chain2/web/servlet/ServletWebContext.java
+++ b/web/src/main/java/org/apache/commons/chain2/web/servlet/ServletWebContext.java
@@ -1,136 +1,136 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.commons.chain2.web.servlet;
-
-import org.apache.commons.chain2.web.WebContext;
-
-import javax.servlet.ServletContext;
-import javax.servlet.http.Cookie;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import java.util.Map;
-
-/**
- * @since 1.0.0
- */
-public interface ServletWebContext<K, V> extends WebContext<K, V> {
-    /**
-     * <p>Return the {@link javax.servlet.ServletContext} for this context.</p>
-     *
-     * @return The <code>ServletContext</code> for this context.
-     */
-    ServletContext getContext();
-
-    /**
-     * <p>Return the {@link javax.servlet.http.HttpServletRequest} for this context.</p>
-     *                     ServletWebContextBase
-     * @return The <code>HttpServletRequest</code> for this context.
-     */
-    HttpServletRequest getRequest();
-
-    /**
-     * <p>Return the {@link javax.servlet.http.HttpServletResponse} for this context.</p>
-     *
-     * @return The <code>HttpServletResponse</code> for this context.
-     */
-    HttpServletResponse getResponse();
-
-    /**
-     * <p>Initialize (or reinitialize) this {@link ServletWebContext} instance
-     * for the specified Servlet API objects.</p>
-     *
-     * @param context The <code>ServletContext</code> for this web application
-     * @param request The <code>HttpServletRequest</code> for this request
-     * @param response The <code>HttpServletResponse</code> for this request
-     */
-    void initialize(ServletContext context,
-                    HttpServletRequest request,
-                    HttpServletResponse response);
-
-    /**
-     * <p>Release references to allocated resources acquired in
-     * <code>initialize()</code> of via subsequent processing.  After this
-     * method is called, subsequent calls to any other method than
-     * <code>initialize()</code> will return undefined results.</p>
-     */
-    void release();
-
-    /**
-     * See the {@link org.apache.commons.chain2.web.WebContext}'s Javadoc.
-     *
-     * @return Application scope Map.
-     */
-    Map<String, Object> getApplicationScope();
-
-    /**
-     * See the {@link org.apache.commons.chain2.web.WebContext}'s Javadoc.
-     *
-     * @return Header values Map.
-     */
-    Map<String, String> getHeader();
-
-    /**
-     * See the {@link org.apache.commons.chain2.web.WebContext}'s Javadoc.
-     *
-     * @return Header values Map.
-     */
-    Map<String, String[]> getHeaderValues();
-
-    /**
-     * See the {@link org.apache.commons.chain2.web.WebContext}'s Javadoc.
-     *
-     * @return Initialization parameter Map.
-     */
-    Map<String, String> getInitParam();
-
-    /**
-     * See the {@link org.apache.commons.chain2.web.WebContext}'s Javadoc.
-     *
-     * @return Request parameter Map.
-     */
-    Map<String, String> getParam();
-
-    /**
-     * See the {@link org.apache.commons.chain2.web.WebContext}'s Javadoc.
-     *
-     * @return Request parameter Map.
-     */
-    Map<String, String[]> getParamValues();
-
-    /**
-     * See the {@link org.apache.commons.chain2.web.WebContext}'s Javadoc.
-     *
-     * @return Map of Cookies.
-     * @since Chain 1.1
-     */
-    Map<String, Cookie> getCookies();
-
-    /**
-     * See the {@link org.apache.commons.chain2.web.WebContext}'s Javadoc.
-     *
-     * @return Request scope Map.
-     */
-    Map<String, Object> getRequestScope();
-
-    /**
-     * See the {@link org.apache.commons.chain2.web.WebContext}'s Javadoc.
-     *
-     * @return Session scope Map.
-     */
-    Map<String, Object> getSessionScope();
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.chain2.web.servlet;
+
+import org.apache.commons.chain2.web.WebContext;
+
+import javax.servlet.ServletContext;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.util.Map;
+
+/**
+ * @since 1.0.0
+ */
+public interface ServletWebContext<K, V> extends WebContext<K, V> {
+    /**
+     * <p>Return the {@link javax.servlet.ServletContext} for this context.</p>
+     *
+     * @return The <code>ServletContext</code> for this context.
+     */
+    ServletContext getContext();
+
+    /**
+     * <p>Return the {@link javax.servlet.http.HttpServletRequest} for this context.</p>
+     *                     ServletWebContextBase
+     * @return The <code>HttpServletRequest</code> for this context.
+     */
+    HttpServletRequest getRequest();
+
+    /**
+     * <p>Return the {@link javax.servlet.http.HttpServletResponse} for this context.</p>
+     *
+     * @return The <code>HttpServletResponse</code> for this context.
+     */
+    HttpServletResponse getResponse();
+
+    /**
+     * <p>Initialize (or reinitialize) this {@link ServletWebContext} instance
+     * for the specified Servlet API objects.</p>
+     *
+     * @param context The <code>ServletContext</code> for this web application
+     * @param request The <code>HttpServletRequest</code> for this request
+     * @param response The <code>HttpServletResponse</code> for this request
+     */
+    void initialize(ServletContext context,
+                    HttpServletRequest request,
+                    HttpServletResponse response);
+
+    /**
+     * <p>Release references to allocated resources acquired in
+     * <code>initialize()</code> of via subsequent processing.  After this
+     * method is called, subsequent calls to any other method than
+     * <code>initialize()</code> will return undefined results.</p>
+     */
+    void release();
+
+    /**
+     * See the {@link org.apache.commons.chain2.web.WebContext}'s Javadoc.
+     *
+     * @return Application scope Map.
+     */
+    Map<String, Object> getApplicationScope();
+
+    /**
+     * See the {@link org.apache.commons.chain2.web.WebContext}'s Javadoc.
+     *
+     * @return Header values Map.
+     */
+    Map<String, String> getHeader();
+
+    /**
+     * See the {@link org.apache.commons.chain2.web.WebContext}'s Javadoc.
+     *
+     * @return Header values Map.
+     */
+    Map<String, String[]> getHeaderValues();
+
+    /**
+     * See the {@link org.apache.commons.chain2.web.WebContext}'s Javadoc.
+     *
+     * @return Initialization parameter Map.
+     */
+    Map<String, String> getInitParam();
+
+    /**
+     * See the {@link org.apache.commons.chain2.web.WebContext}'s Javadoc.
+     *
+     * @return Request parameter Map.
+     */
+    Map<String, String> getParam();
+
+    /**
+     * See the {@link org.apache.commons.chain2.web.WebContext}'s Javadoc.
+     *
+     * @return Request parameter Map.
+     */
+    Map<String, String[]> getParamValues();
+
+    /**
+     * See the {@link org.apache.commons.chain2.web.WebContext}'s Javadoc.
+     *
+     * @return Map of Cookies.
+     * @since 1.1
+     */
+    Map<String, Cookie> getCookies();
+
+    /**
+     * See the {@link org.apache.commons.chain2.web.WebContext}'s Javadoc.
+     *
+     * @return Request scope Map.
+     */
+    Map<String, Object> getRequestScope();
+
+    /**
+     * See the {@link org.apache.commons.chain2.web.WebContext}'s Javadoc.
+     *
+     * @return Session scope Map.
+     */
+    Map<String, Object> getSessionScope();
+}