Tag RC3 for Chain 1.2 release

git-svn-id: https://svn.apache.org/repos/asf/commons/proper/chain/tags/CHAIN_1_2_RC3@661389 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt
index fe30b35..640ee9c 100644
--- a/RELEASE-NOTES.txt
+++ b/RELEASE-NOTES.txt
@@ -33,6 +33,7 @@
       
 BUG REPORTS ADDRESSED:
 =====================
+o CHAIN-44: CatalogFactory instance variable prevents ChainProcessor from being serializable.
 o CHAIN-43: ChainListener URL translation does not work as expected. 
 o CHAIN-42: Various scope mappers use incorrect equalization.
 o CHAIN-41: Ant build fails due to usage of old Digester.
diff --git a/apps/example/README.txt b/apps/example/README.txt
deleted file mode 100644
index 4a2d791..0000000
--- a/apps/example/README.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-
-To build the example webapp you need Maven 2 installed:
-   http://maven.apache.org/
-
-Run the the following command to build the webapp war file:
-
-   mvn package
\ No newline at end of file
diff --git a/apps/example1/README.txt b/apps/example1/README.txt
new file mode 100644
index 0000000..3ba752f
--- /dev/null
+++ b/apps/example1/README.txt
@@ -0,0 +1,14 @@
+Example 1
+=========
+An example using the ChainProcessor servlet and showing examples of
+using the PathInfoMapper, RequestParameterMapper and ServletPathMapper
+Commands to map requests to Commands.
+
+BUILDING
+========
+To build the example webapp you need Maven 2 installed:
+   http://maven.apache.org/
+
+Run the the following command to build the webapp war file:
+
+   mvn package
\ No newline at end of file
diff --git a/apps/example/pom.xml b/apps/example1/pom.xml
similarity index 96%
copy from apps/example/pom.xml
copy to apps/example1/pom.xml
index 6a73551..6e41c2a 100644
--- a/apps/example/pom.xml
+++ b/apps/example1/pom.xml
@@ -28,10 +28,10 @@
         <version>10</version>
     </parent>
 
-    <artifactId>chain-example</artifactId>
+    <artifactId>chain-example1</artifactId>
     <packaging>war</packaging>
     <version>1.2</version>
-    <name>Chan Example App</name>
+    <name>Chan Example 1 App</name>
 
     <dependencies>
 
@@ -74,7 +74,7 @@
         <dependency>
             <groupId>commons-logging</groupId>
             <artifactId>commons-logging</artifactId>
-            <version>1.0.4</version>
+            <version>1.1.1</version>
         </dependency>
 
         <dependency>
diff --git a/apps/example/src/main/java/org/apache/commons/chain/apps/example/CountCommand.java b/apps/example1/src/main/java/org/apache/commons/chain/apps/example/CountCommand.java
similarity index 100%
rename from apps/example/src/main/java/org/apache/commons/chain/apps/example/CountCommand.java
rename to apps/example1/src/main/java/org/apache/commons/chain/apps/example/CountCommand.java
diff --git a/apps/example/src/main/java/org/apache/commons/chain/apps/example/ForwardCommand.java b/apps/example1/src/main/java/org/apache/commons/chain/apps/example/ForwardCommand.java
similarity index 100%
rename from apps/example/src/main/java/org/apache/commons/chain/apps/example/ForwardCommand.java
rename to apps/example1/src/main/java/org/apache/commons/chain/apps/example/ForwardCommand.java
diff --git a/apps/example1/src/main/webapp/WEB-INF/chain-config.xml b/apps/example1/src/main/webapp/WEB-INF/chain-config.xml
new file mode 100644
index 0000000..d536807
--- /dev/null
+++ b/apps/example1/src/main/webapp/WEB-INF/chain-config.xml
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+
+ 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.
+
+-->
+
+<catalogs>
+
+    <!-- Default Catalog: "Path Info" example -->
+    <catalog>
+
+        <!-- Command that maps "Path Info" patterns to Commands -->
+        <chain name="command">
+            <command                       className="org.apache.commons.chain.web.servlet.PathInfoMapper"/>
+            <command forward="/pathinfo.jsp"  className="org.apache.commons.chain.apps.example.ForwardCommand"/>
+        </chain>
+
+        <!-- Foo Command -->
+        <chain name="/foo">
+            <command attribute="pathinfoFooCount" className="org.apache.commons.chain.apps.example.CountCommand"/>
+        </chain>
+
+        <!-- Bar Command -->
+        <chain name="/bar">
+            <command attribute="pathinfoBarCount" className="org.apache.commons.chain.apps.example.CountCommand"/>
+        </chain>
+
+    </catalog>
+
+    <!-- Catalog for "Request Parameter" example -->
+    <catalog name="reqparam">
+
+        <!-- Command that maps a "Request Parameter" to Commands -->
+        <chain name="command">
+            <command catalogName="reqparam"  className="org.apache.commons.chain.web.servlet.RequestParameterMapper"/>
+            <command forward="/reqparam.jsp" className="org.apache.commons.chain.apps.example.ForwardCommand"/>
+        </chain>
+
+        <!-- Foo Command -->
+        <chain name="foo">
+            <command attribute="reqparamFooCount" className="org.apache.commons.chain.apps.example.CountCommand"/>
+        </chain>
+
+        <!-- Bar Command -->
+        <chain name="bar">
+            <command attribute="reqparamBarCount" className="org.apache.commons.chain.apps.example.CountCommand"/>
+        </chain>
+
+    </catalog>
+
+    <!-- Catalog for "Servlet Path" example -->
+    <catalog name="servletpath">
+
+        <!-- Command that maps "Servlet Path" patterns to Commands -->
+        <chain name="command">
+            <command catalogName="servletpath"  className="org.apache.commons.chain.web.servlet.ServletPathMapper"/>
+            <command forward="/servletpath.jsp" className="org.apache.commons.chain.apps.example.ForwardCommand"/>
+        </chain>
+
+        <!-- Foo Command -->
+        <chain name="/foo.execute">
+            <command attribute="servletpathFooCount" className="org.apache.commons.chain.apps.example.CountCommand"/>
+        </chain>
+
+        <!-- Bar Command -->
+        <chain name="/bar.execute">
+            <command attribute="servletpathBarCount" className="org.apache.commons.chain.apps.example.CountCommand"/>
+        </chain>
+
+
+    </catalog>
+
+</catalogs>
diff --git a/apps/example/src/main/webapp/WEB-INF/classes/log4j.properties b/apps/example1/src/main/webapp/WEB-INF/classes/log4j.properties
similarity index 100%
rename from apps/example/src/main/webapp/WEB-INF/classes/log4j.properties
rename to apps/example1/src/main/webapp/WEB-INF/classes/log4j.properties
diff --git a/apps/example1/src/main/webapp/WEB-INF/web.xml b/apps/example1/src/main/webapp/WEB-INF/web.xml
new file mode 100644
index 0000000..7077d37
--- /dev/null
+++ b/apps/example1/src/main/webapp/WEB-INF/web.xml
@@ -0,0 +1,87 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ 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.
+
+-->
+<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
+
+    <display-name>Chain Example</display-name>
+
+    <context-param>
+        <param-name>org.apache.commons.chain.CONFIG_WEB_RESOURCE</param-name>
+        <param-value>/WEB-INF/chain-config.xml</param-value>
+    </context-param>
+
+    <!-- "Path Info" Servlet Configuration (uses default catalog) -->
+    <servlet>
+        <servlet-name>pathinfo</servlet-name>
+        <servlet-class>org.apache.commons.chain.web.servlet.ChainProcessor</servlet-class>
+        <load-on-startup>1</load-on-startup>
+    </servlet>
+
+    <!-- "Request Parameter" Servlet Configuration -->
+    <servlet>
+        <servlet-name>reqparam</servlet-name>
+        <servlet-class>org.apache.commons.chain.web.servlet.ChainProcessor</servlet-class>
+        <load-on-startup>2</load-on-startup>
+
+        <!-- Configure catalog name -->
+        <init-param>
+            <param-name>org.apache.commons.chain.CATALOG</param-name>
+            <param-value>reqparam</param-value>
+        </init-param>
+
+    </servlet>
+
+    <!-- "Servlet Path" Servlet Configuration -->
+    <servlet>
+        <servlet-name>servletpath</servlet-name>
+        <servlet-class>org.apache.commons.chain.web.servlet.ChainProcessor</servlet-class>
+        <load-on-startup>3</load-on-startup>
+
+        <!-- Configure catalog name -->
+        <init-param>
+            <param-name>org.apache.commons.chain.CATALOG</param-name>
+            <param-value>servletpath</param-value>
+        </init-param>
+
+    </servlet>
+
+    <!-- "Path Info" Servlet Mappings -->
+    <servlet-mapping>
+        <servlet-name>pathinfo</servlet-name>
+        <url-pattern>/exec/*</url-pattern>
+    </servlet-mapping>
+
+    <!-- "Request Parameter" Servlet Mappings -->
+    <servlet-mapping>
+        <servlet-name>reqparam</servlet-name>
+        <url-pattern>/execute</url-pattern>
+    </servlet-mapping>
+
+    <!-- "Servlet Path" Servlet Mappings -->
+    <servlet-mapping>
+        <servlet-name>servletpath</servlet-name>
+        <url-pattern>*.execute</url-pattern>
+    </servlet-mapping>
+
+    <!-- Welcome File List -->
+    <welcome-file-list>
+        <welcome-file>index.jsp</welcome-file>
+    </welcome-file-list>
+
+</web-app>
diff --git a/apps/example/src/main/webapp/index.jsp b/apps/example1/src/main/webapp/index.jsp
similarity index 100%
rename from apps/example/src/main/webapp/index.jsp
rename to apps/example1/src/main/webapp/index.jsp
diff --git a/apps/example/src/main/webapp/pathinfo.jsp b/apps/example1/src/main/webapp/pathinfo.jsp
similarity index 100%
rename from apps/example/src/main/webapp/pathinfo.jsp
rename to apps/example1/src/main/webapp/pathinfo.jsp
diff --git a/apps/example/src/main/webapp/reqparam.jsp b/apps/example1/src/main/webapp/reqparam.jsp
similarity index 100%
rename from apps/example/src/main/webapp/reqparam.jsp
rename to apps/example1/src/main/webapp/reqparam.jsp
diff --git a/apps/example/src/main/webapp/servletpath.jsp b/apps/example1/src/main/webapp/servletpath.jsp
similarity index 100%
rename from apps/example/src/main/webapp/servletpath.jsp
rename to apps/example1/src/main/webapp/servletpath.jsp
diff --git a/apps/example2/README.txt b/apps/example2/README.txt
new file mode 100644
index 0000000..76b459f
--- /dev/null
+++ b/apps/example2/README.txt
@@ -0,0 +1,14 @@
+Example 2
+=========
+An example using the ChainListener to load configuration data and a custom
+servlet (ExampleServlet) and showing examples of using the PathInfoMapper,
+RequestParameterMapper and ServletPathMapper Commands to map requests to Commands.
+
+BUILDING
+========
+To build the example webapp you need Maven 2 installed:
+   http://maven.apache.org/
+
+Run the the following command to build the webapp war file:
+
+   mvn package
\ No newline at end of file
diff --git a/apps/example/pom.xml b/apps/example2/pom.xml
similarity index 96%
rename from apps/example/pom.xml
rename to apps/example2/pom.xml
index 6a73551..241bce7 100644
--- a/apps/example/pom.xml
+++ b/apps/example2/pom.xml
@@ -28,10 +28,10 @@
         <version>10</version>
     </parent>
 
-    <artifactId>chain-example</artifactId>
+    <artifactId>chain-example2</artifactId>
     <packaging>war</packaging>
     <version>1.2</version>
-    <name>Chan Example App</name>
+    <name>Chan Example 2 App</name>
 
     <dependencies>
 
@@ -74,7 +74,7 @@
         <dependency>
             <groupId>commons-logging</groupId>
             <artifactId>commons-logging</artifactId>
-            <version>1.0.4</version>
+            <version>1.1.1</version>
         </dependency>
 
         <dependency>
diff --git a/apps/example/src/main/java/org/apache/commons/chain/apps/example/CountCommand.java b/apps/example2/src/main/java/org/apache/commons/chain/apps/example/CountCommand.java
similarity index 100%
copy from apps/example/src/main/java/org/apache/commons/chain/apps/example/CountCommand.java
copy to apps/example2/src/main/java/org/apache/commons/chain/apps/example/CountCommand.java
diff --git a/apps/example/src/main/java/org/apache/commons/chain/apps/example/ExampleServlet.java b/apps/example2/src/main/java/org/apache/commons/chain/apps/example/ExampleServlet.java
similarity index 100%
rename from apps/example/src/main/java/org/apache/commons/chain/apps/example/ExampleServlet.java
rename to apps/example2/src/main/java/org/apache/commons/chain/apps/example/ExampleServlet.java
diff --git a/apps/example/src/main/java/org/apache/commons/chain/apps/example/ForwardCommand.java b/apps/example2/src/main/java/org/apache/commons/chain/apps/example/ForwardCommand.java
similarity index 100%
copy from apps/example/src/main/java/org/apache/commons/chain/apps/example/ForwardCommand.java
copy to apps/example2/src/main/java/org/apache/commons/chain/apps/example/ForwardCommand.java
diff --git a/apps/example/src/main/webapp/WEB-INF/chain-config.xml b/apps/example2/src/main/webapp/WEB-INF/chain-config.xml
similarity index 100%
rename from apps/example/src/main/webapp/WEB-INF/chain-config.xml
rename to apps/example2/src/main/webapp/WEB-INF/chain-config.xml
diff --git a/apps/example/src/main/webapp/WEB-INF/classes/log4j.properties b/apps/example2/src/main/webapp/WEB-INF/classes/log4j.properties
similarity index 100%
copy from apps/example/src/main/webapp/WEB-INF/classes/log4j.properties
copy to apps/example2/src/main/webapp/WEB-INF/classes/log4j.properties
diff --git a/apps/example/src/main/webapp/WEB-INF/web.xml b/apps/example2/src/main/webapp/WEB-INF/web.xml
similarity index 100%
rename from apps/example/src/main/webapp/WEB-INF/web.xml
rename to apps/example2/src/main/webapp/WEB-INF/web.xml
diff --git a/apps/example/src/main/webapp/index.jsp b/apps/example2/src/main/webapp/index.jsp
similarity index 100%
copy from apps/example/src/main/webapp/index.jsp
copy to apps/example2/src/main/webapp/index.jsp
diff --git a/apps/example/src/main/webapp/pathinfo.jsp b/apps/example2/src/main/webapp/pathinfo.jsp
similarity index 100%
copy from apps/example/src/main/webapp/pathinfo.jsp
copy to apps/example2/src/main/webapp/pathinfo.jsp
diff --git a/apps/example/src/main/webapp/reqparam.jsp b/apps/example2/src/main/webapp/reqparam.jsp
similarity index 100%
copy from apps/example/src/main/webapp/reqparam.jsp
copy to apps/example2/src/main/webapp/reqparam.jsp
diff --git a/apps/example/src/main/webapp/servletpath.jsp b/apps/example2/src/main/webapp/servletpath.jsp
similarity index 100%
copy from apps/example/src/main/webapp/servletpath.jsp
copy to apps/example2/src/main/webapp/servletpath.jsp
diff --git a/src/java/org/apache/commons/chain/web/portlet/PortletApplicationScopeMap.java b/src/java/org/apache/commons/chain/web/portlet/PortletApplicationScopeMap.java
index bd40a60..ff8588d 100644
--- a/src/java/org/apache/commons/chain/web/portlet/PortletApplicationScopeMap.java
+++ b/src/java/org/apache/commons/chain/web/portlet/PortletApplicationScopeMap.java
@@ -130,10 +130,10 @@
 
 
     public void putAll(Map map) {
-        Iterator keys = map.keySet().iterator();
-        while (keys.hasNext()) {
-            String key = (String) keys.next();
-            context.setAttribute(key, map.get(key));
+        Iterator entries = map.entrySet().iterator();
+        while (entries.hasNext()) {
+            Map.Entry entry = (Map.Entry)entries.next();
+            put(entry.getKey(), entry.getValue());
         }
     }
 
diff --git a/src/java/org/apache/commons/chain/web/portlet/PortletRequestScopeMap.java b/src/java/org/apache/commons/chain/web/portlet/PortletRequestScopeMap.java
index 0f99f5b..371f13f 100644
--- a/src/java/org/apache/commons/chain/web/portlet/PortletRequestScopeMap.java
+++ b/src/java/org/apache/commons/chain/web/portlet/PortletRequestScopeMap.java
@@ -130,10 +130,10 @@
 
 
     public void putAll(Map map) {
-        Iterator keys = map.keySet().iterator();
-        while (keys.hasNext()) {
-            String key = (String) keys.next();
-            request.setAttribute(key, map.get(key));
+        Iterator entries = map.entrySet().iterator();
+        while (entries.hasNext()) {
+            Map.Entry entry = (Map.Entry)entries.next();
+            put(entry.getKey(), entry.getValue());
         }
     }
 
diff --git a/src/java/org/apache/commons/chain/web/portlet/PortletSessionScopeMap.java b/src/java/org/apache/commons/chain/web/portlet/PortletSessionScopeMap.java
index 4d23f2e..68128a8 100644
--- a/src/java/org/apache/commons/chain/web/portlet/PortletSessionScopeMap.java
+++ b/src/java/org/apache/commons/chain/web/portlet/PortletSessionScopeMap.java
@@ -171,10 +171,10 @@
 
 
     public void putAll(Map map) {
-        Iterator keys = map.keySet().iterator();
-        while (keys.hasNext()) {
-            Object key = keys.next();
-            put(key, map.get(key));
+        Iterator entries = map.entrySet().iterator();
+        while (entries.hasNext()) {
+            Map.Entry entry = (Map.Entry)entries.next();
+            put(entry.getKey(), entry.getValue());
         }
     }
 
diff --git a/src/java/org/apache/commons/chain/web/portlet/PortletSetLocaleCommand.java b/src/java/org/apache/commons/chain/web/portlet/PortletSetLocaleCommand.java
index ca893a3..5000e89 100644
--- a/src/java/org/apache/commons/chain/web/portlet/PortletSetLocaleCommand.java
+++ b/src/java/org/apache/commons/chain/web/portlet/PortletSetLocaleCommand.java
@@ -18,7 +18,7 @@
 
 
 import java.util.Locale;
-import javax.portlet.PortletResponse;
+//import javax.portlet.PortletResponse;
 import org.apache.commons.chain.Context;
 import org.apache.commons.chain.web.AbstractSetLocaleCommand;
 
@@ -42,8 +42,8 @@
      */
     protected void setLocale(Context context, Locale locale) {
 
-    PortletResponse response = (PortletResponse)
-        context.get("response");
+    // PortletResponse response = (PortletResponse)
+    //    context.get("response");
     //  response.setLocale(locale);
     // Not supported by the Portlet API
 
diff --git a/src/java/org/apache/commons/chain/web/servlet/ChainProcessor.java b/src/java/org/apache/commons/chain/web/servlet/ChainProcessor.java
index dff9adf..f408b89 100644
--- a/src/java/org/apache/commons/chain/web/servlet/ChainProcessor.java
+++ b/src/java/org/apache/commons/chain/web/servlet/ChainProcessor.java
@@ -119,12 +119,6 @@
     private String command = null;
 
 
-    /**
-     * <p>The {@link CatalogFactory} for this application.</p>
-     */
-    private CatalogFactory factory = null;
-
-
     // --------------------------------------------------------- Servlet Methods
 
 
@@ -137,7 +131,6 @@
         attribute = null;
         catalog = null;
         command = null;
-        factory = null;
 
     }
 
@@ -156,7 +149,6 @@
         if (command == null) {
             command = COMMAND_DEFAULT;
         }
-        factory = CatalogFactory.getInstance();
 
     }
 
@@ -183,9 +175,9 @@
             theCatalog = (Catalog) getServletContext().getAttribute
                 (this.attribute);
         } else if (catalog != null) {
-            theCatalog = factory.getCatalog(catalog);
+            theCatalog = CatalogFactory.getInstance().getCatalog(catalog);
         } else {
-            theCatalog = factory.getCatalog();
+            theCatalog = CatalogFactory.getInstance().getCatalog();
         }
         if (attribute == null) {
             request.setAttribute(CATALOG_DEFAULT, theCatalog);
diff --git a/src/java/org/apache/commons/chain/web/servlet/ServletApplicationScopeMap.java b/src/java/org/apache/commons/chain/web/servlet/ServletApplicationScopeMap.java
index 09a50ff..5525bcc 100644
--- a/src/java/org/apache/commons/chain/web/servlet/ServletApplicationScopeMap.java
+++ b/src/java/org/apache/commons/chain/web/servlet/ServletApplicationScopeMap.java
@@ -130,10 +130,10 @@
 
 
     public void putAll(Map map) {
-        Iterator keys = map.keySet().iterator();
-        while (keys.hasNext()) {
-            String key = (String) keys.next();
-            context.setAttribute(key, map.get(key));
+        Iterator entries = map.entrySet().iterator();
+        while (entries.hasNext()) {
+            Map.Entry entry = (Map.Entry)entries.next();
+            put(entry.getKey(), entry.getValue());
         }
     }
 
diff --git a/src/java/org/apache/commons/chain/web/servlet/ServletRequestScopeMap.java b/src/java/org/apache/commons/chain/web/servlet/ServletRequestScopeMap.java
index 2598b9b..7e135df 100644
--- a/src/java/org/apache/commons/chain/web/servlet/ServletRequestScopeMap.java
+++ b/src/java/org/apache/commons/chain/web/servlet/ServletRequestScopeMap.java
@@ -130,10 +130,10 @@
 
 
     public void putAll(Map map) {
-        Iterator keys = map.keySet().iterator();
-        while (keys.hasNext()) {
-            String key = (String) keys.next();
-            request.setAttribute(key, map.get(key));
+        Iterator entries = map.entrySet().iterator();
+        while (entries.hasNext()) {
+            Map.Entry entry = (Map.Entry)entries.next();
+            put(entry.getKey(), entry.getValue());
         }
     }
 
diff --git a/src/java/org/apache/commons/chain/web/servlet/ServletSessionScopeMap.java b/src/java/org/apache/commons/chain/web/servlet/ServletSessionScopeMap.java
index 8c09960..97063b1 100644
--- a/src/java/org/apache/commons/chain/web/servlet/ServletSessionScopeMap.java
+++ b/src/java/org/apache/commons/chain/web/servlet/ServletSessionScopeMap.java
@@ -168,10 +168,10 @@
 
 
     public void putAll(Map map) {
-        Iterator keys = map.keySet().iterator();
-        while (keys.hasNext()) {
-            Object key = keys.next();
-            put(key, map.get(key));
+        Iterator entries = map.entrySet().iterator();
+        while (entries.hasNext()) {
+            Map.Entry entry = (Map.Entry)entries.next();
+            put(entry.getKey(), entry.getValue());
         }
     }
 
diff --git a/src/test/org/apache/commons/chain/web/portlet/PortletWebContextTestCase.java b/src/test/org/apache/commons/chain/web/portlet/PortletWebContextTestCase.java
index 33b62c9..4e63ce3 100644
--- a/src/test/org/apache/commons/chain/web/portlet/PortletWebContextTestCase.java
+++ b/src/test/org/apache/commons/chain/web/portlet/PortletWebContextTestCase.java
@@ -166,6 +166,15 @@
         map.clear();
         checkMapSize(map, 0);
 
+        // Test putAll()
+        Map values = new HashMap();
+        values.put(new Integer(1), "One");
+        values.put("2", "Two");
+        map.putAll(values);
+        assertEquals("putAll(1)", "One", map.get("1"));
+        assertEquals("putAll(2)", "Two", map.get("2"));
+        checkMapSize(map, 2);
+
     }
 
 
@@ -519,6 +528,15 @@
         map.clear();
         checkMapSize(map, 0);
 
+        // Test putAll()
+        Map values = new HashMap();
+        values.put(new Integer(1), "One");
+        values.put("2", "Two");
+        map.putAll(values);
+        assertEquals("putAll(1)", "One", map.get("1"));
+        assertEquals("putAll(2)", "Two", map.get("2"));
+        checkMapSize(map, 2);
+
     }
 
 
@@ -571,6 +589,15 @@
         map.clear();
         checkMapSize(map, 0);
 
+        // Test putAll()
+        Map values = new HashMap();
+        values.put(new Integer(1), "One");
+        values.put("2", "Two");
+        map.putAll(values);
+        assertEquals("putAll(1)", "One", map.get("1"));
+        assertEquals("putAll(2)", "Two", map.get("2"));
+        checkMapSize(map, 2);
+
     }
 
 
diff --git a/src/test/org/apache/commons/chain/web/servlet/ChainProcessorTestCase.java b/src/test/org/apache/commons/chain/web/servlet/ChainProcessorTestCase.java
new file mode 100644
index 0000000..872147f
--- /dev/null
+++ b/src/test/org/apache/commons/chain/web/servlet/ChainProcessorTestCase.java
@@ -0,0 +1,127 @@
+/*
+ * 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.chain.web.servlet;
+
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+
+import javax.servlet.ServletConfig;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+/**
+ *  Test case for {@link ChainProcessor}.
+ */
+public class ChainProcessorTestCase extends TestCase {
+
+    // ---------------------------------------------------------- Constructors
+
+    /**
+     * Construct a new instance of this test case.
+     *
+     * @param name Name of the test case
+     */
+    public ChainProcessorTestCase(String name) {
+        super(name);
+    }
+
+    /**
+     * Return the tests included in this test suite.
+     * @return the test suite
+     */
+    public static Test suite() {
+        return new TestSuite(ChainProcessorTestCase.class);
+    }
+
+
+    /**
+     * Set up instance variables required by this test case.
+     */
+    public void setUp() {
+    }
+
+    /**
+     * Tear down instance variables required by this test case.
+     */
+    public void tearDown() {
+    }
+
+    /**
+     * Test serialization.
+     */
+    public void testSerialize() {
+
+        // Initialize a ChainProcessor
+        ChainProcessor processor = initServlet(new ChainProcessor(), new MockServletConfig("test"));
+
+        // Serialize/Deserialize & test value
+        processor = (ChainProcessor)serializeDeserialize(processor, "First Test");
+    }
+
+    /**
+     * Initialize the ChainProcessor.
+     *
+     * @param processor The chain processor instance
+     * @param config The servlet config to initialize with
+     * @return The chain processor
+     */
+    private ChainProcessor initServlet(ChainProcessor processor, ServletConfig config) {
+        try {
+            processor.init(config);
+        } catch (Throwable t) {
+            t.printStackTrace();
+            fail("ChainProcessor init() threw " + t);
+        }
+        return processor;
+    }
+
+    /**
+     * Do serialization and deserialization.
+     */
+    private Object serializeDeserialize(Object target, String text) {
+
+        // Serialize the test object
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        try {
+            ObjectOutputStream oos = new ObjectOutputStream(baos);
+            oos.writeObject(target);
+            oos.flush();
+            oos.close();
+        } catch (Exception e) {
+            fail(text + ": Exception during serialization: " + e);
+        }
+
+        // Deserialize the test object
+        Object result = null;
+        try {
+            ByteArrayInputStream bais =
+                new ByteArrayInputStream(baos.toByteArray());
+            ObjectInputStream ois = new ObjectInputStream(bais);
+            result = ois.readObject();
+            bais.close();
+        } catch (Exception e) {
+            fail(text + ": Exception during deserialization: " + e);
+        }
+        return result;
+
+    }
+}
diff --git a/src/test/org/apache/commons/chain/web/servlet/MockServletConfig.java b/src/test/org/apache/commons/chain/web/servlet/MockServletConfig.java
new file mode 100644
index 0000000..9349403
--- /dev/null
+++ b/src/test/org/apache/commons/chain/web/servlet/MockServletConfig.java
@@ -0,0 +1,110 @@
+/*
+ * 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.chain.web.servlet;
+
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletContext;
+
+import org.apache.commons.chain.web.MockEnumeration;
+
+/**
+ * Mock {@link ServletConfig} implementation.
+ */
+public class MockServletConfig implements ServletConfig {
+    private final String servletName;
+    private final ServletContext servletContext;
+    private final Map parameters = new HashMap();
+
+    /**
+     * Default Constructor.
+     */
+    public MockServletConfig() {
+        this("unspecified", new MockServletContext());
+    }
+
+    /**
+     * Construct an instance with the specified name.
+     *
+     * @param servletName the servlet name
+     */
+    public MockServletConfig(String servletName) {
+        this(servletName, new MockServletContext());
+    }
+
+    /**
+     * Construct an instance with the specified name and context.
+     *
+     * @param servletName the servlet name
+     * @param servletContext the servlet context
+     */
+    public MockServletConfig(String servletName, ServletContext servletContext) {
+        this.servletName = servletName;
+        this.servletContext = servletContext;
+    }
+
+    /**
+     * Get a specified init parameter.
+     *
+     * @param name parameter name
+     * @return the parameter value
+     */
+    public String getInitParameter(String name) {
+        return (String)parameters.get(name);
+    }
+
+    /**
+     * Get the init parameter names.
+     *
+     * @return the set of parameter names
+     */
+    public Enumeration getInitParameterNames() {
+        return (new MockEnumeration(parameters.keySet().iterator()));
+    }
+
+    /**
+     * Get the servlet context.
+     *
+     * @return the servlet context
+     */
+    public ServletContext getServletContext() {
+        return servletContext;
+    }
+
+    /**
+     * Return the servlet name.
+     *
+     * @return The servlet name
+     */
+    public String getServletName() {
+        return servletName;
+    }
+
+    /**
+     * Set a specified init parameter.
+     *
+     * @param name parameter name
+     * @param value the parameter value
+     */
+    public void setInitParameter(String name, String value) {
+        parameters.put(name, value);
+    }
+
+}
diff --git a/src/test/org/apache/commons/chain/web/servlet/MockServletContext.java b/src/test/org/apache/commons/chain/web/servlet/MockServletContext.java
index d835a61..23a22e5 100644
--- a/src/test/org/apache/commons/chain/web/servlet/MockServletContext.java
+++ b/src/test/org/apache/commons/chain/web/servlet/MockServletContext.java
@@ -21,6 +21,10 @@
 import javax.servlet.Servlet;
 import javax.servlet.ServletContext;
 import javax.servlet.ServletException;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
 import java.io.InputStream;
 import java.net.MalformedURLException;
 import java.net.URL;
@@ -33,6 +37,7 @@
 public class MockServletContext implements ServletContext {
 
 
+    private Log log = LogFactory.getLog(MockServletContext.class);
     private Hashtable attributes = new Hashtable();
     private Hashtable parameters = new Hashtable();
 
@@ -125,15 +130,15 @@
     }
 
     public void log(String message) {
-        throw new UnsupportedOperationException();
+        log.info(message);
     }
 
     public void log(Exception exception, String message) {
-        throw new UnsupportedOperationException();
+        log.error(message, exception);
     }
 
     public void log(String message, Throwable exception) {
-        throw new UnsupportedOperationException();
+        log.error(message, exception);
     }
 
     public void removeAttribute(String name) {
diff --git a/src/test/org/apache/commons/chain/web/servlet/ServletWebContextTestCase.java b/src/test/org/apache/commons/chain/web/servlet/ServletWebContextTestCase.java
index c49bb4b..4de813d 100644
--- a/src/test/org/apache/commons/chain/web/servlet/ServletWebContextTestCase.java
+++ b/src/test/org/apache/commons/chain/web/servlet/ServletWebContextTestCase.java
@@ -175,6 +175,14 @@
         map.clear();
         checkMapSize(map, 0);
 
+        // Test putAll()
+        Map values = new HashMap();
+        values.put(new Integer(1), "One");
+        values.put("2", "Two");
+        map.putAll(values);
+        assertEquals("putAll(1)", "One", map.get("1"));
+        assertEquals("putAll(2)", "Two", map.get("2"));
+        checkMapSize(map, 2);
     }
 
 
@@ -629,6 +637,15 @@
         map.clear();
         checkMapSize(map, 0);
 
+        // Test putAll()
+        Map values = new HashMap();
+        values.put(new Integer(1), "One");
+        values.put("2", "Two");
+        map.putAll(values);
+        assertEquals("putAll(1)", "One", map.get("1"));
+        assertEquals("putAll(2)", "Two", map.get("2"));
+        checkMapSize(map, 2);
+        
     }
 
 
@@ -681,6 +698,15 @@
         map.clear();
         checkMapSize(map, 0);
 
+        // Test putAll()
+        Map values = new HashMap();
+        values.put(new Integer(1), "One");
+        values.put("2", "Two");
+        map.putAll(values);
+        assertEquals("putAll(1)", "One", map.get("1"));
+        assertEquals("putAll(2)", "Two", map.get("2"));
+        checkMapSize(map, 2);
+
     }
 
 
diff --git a/xdocs/changes.xml b/xdocs/changes.xml
index 94349c1..c37c344 100644
--- a/xdocs/changes.xml
+++ b/xdocs/changes.xml
@@ -39,7 +39,7 @@
   </properties>
   <body>
 
-    <release version="1.2" date="2008-05-25" description="OSGi enabled / minor bug fixes">
+    <release version="1.2" date="2008-06-02" description="OSGi enabled / minor bug fixes">
       <action dev="niallp" type="add">
          Chain 1.2 is the first OSGi-enabled release.
       </action>
@@ -55,6 +55,9 @@
       <action dev="niallp" type="update" issue="CHAIN-4" due-to="Joe Germuska">
          Update servlet implementation classes to be aware of CatalogFactory
       </action>
+      <action dev="niallp" type="fix" issue="CHAIN-44" due-to="FindBugs">
+         CatalogFactory instance variable prevents ChainProcessor from being serializable.
+      </action>
       <action dev="niallp" type="fix" issue="CHAIN-43" due-to="Ales Dolecek">
          ChainListener URL translation does not work as expected.
       </action>