[COCOON-2347] Fixes made by Gabriel Gruber @ggruber4711 - This fixes #4

git-svn-id: https://svn.apache.org/repos/asf/cocoon/branches/BRANCH_2_2_COCOON-2347@1828352 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/blocks/cocoon-portal/cocoon-portal-impl/src/main/java/org/apache/cocoon/portal/spring/AspectsBeanDefinitionParser.java b/blocks/cocoon-portal/cocoon-portal-impl/src/main/java/org/apache/cocoon/portal/spring/AspectsBeanDefinitionParser.java
index d863030..711ab6e 100644
--- a/blocks/cocoon-portal/cocoon-portal-impl/src/main/java/org/apache/cocoon/portal/spring/AspectsBeanDefinitionParser.java
+++ b/blocks/cocoon-portal/cocoon-portal-impl/src/main/java/org/apache/cocoon/portal/spring/AspectsBeanDefinitionParser.java
@@ -92,7 +92,7 @@
             }
         }
         try {
-            beanDef.getConstructorArgumentValues().addIndexedArgumentValue(0, ClassUtils.forName(this.baseClass));
+        	beanDef.getConstructorArgumentValues().addIndexedArgumentValue(0, ClassUtils.forName(this.baseClass, getClass().getClassLoader()));
         } catch (ClassNotFoundException e) {
             throw new BeanDefinitionStoreException("Unable to load aspect class: " + this.baseClass, e);
         }
@@ -105,7 +105,7 @@
 
             List aliases = new ArrayList();
             if (StringUtils.hasLength(nameAttr)) {
-                String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, BeanDefinitionParserDelegate.BEAN_NAME_DELIMITERS);
+            	String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
                 aliases.addAll(Arrays.asList(nameArr));
             }
 
diff --git a/blocks/cocoon-template/cocoon-template-impl/src/test/resources/org/apache/cocoon/template/jxtg/formatDate-output.xml b/blocks/cocoon-template/cocoon-template-impl/src/test/resources/org/apache/cocoon/template/jxtg/formatDate-output.xml
index 7438420..5b1b334 100644
--- a/blocks/cocoon-template/cocoon-template-impl/src/test/resources/org/apache/cocoon/template/jxtg/formatDate-output.xml
+++ b/blocks/cocoon-template/cocoon-template-impl/src/test/resources/org/apache/cocoon/template/jxtg/formatDate-output.xml
@@ -16,6 +16,6 @@
   limitations under the License.
 -->
 <root xmlns:jx="http://apache.org/cocoon/templates/jx/1.0">
-	<date locale="pl_PL">01 styczeń 1979</date>
+	<date locale="de_DE">01 Januar 1979</date>
 	<date locale="sv_SE">01 januari 1979</date>
 </root>
diff --git a/blocks/cocoon-template/cocoon-template-impl/src/test/resources/org/apache/cocoon/template/jxtg/formatDate.xml b/blocks/cocoon-template/cocoon-template-impl/src/test/resources/org/apache/cocoon/template/jxtg/formatDate.xml
index 4c1685e..cb1fb78 100644
--- a/blocks/cocoon-template/cocoon-template-impl/src/test/resources/org/apache/cocoon/template/jxtg/formatDate.xml
+++ b/blocks/cocoon-template/cocoon-template-impl/src/test/resources/org/apache/cocoon/template/jxtg/formatDate.xml
@@ -16,6 +16,6 @@
   limitations under the License.
 -->
 <root xmlns:jx="http://apache.org/cocoon/templates/jx/1.0">
-	<date locale="pl_PL"><jx:formatDate value="${date}" pattern="dd MMMM yyyy" locale="pl_PL"/></date>
+	<date locale="de_DE"><jx:formatDate value="${date}" pattern="dd MMMM yyyy" locale="de_DE"/></date>
 	<date locale="sv_SE"><jx:formatDate value="${date}" pattern="dd MMMM yyyy" locale="sv_SE"/></date>
 </root>
diff --git a/blocks/cocoon-template/cocoon-template-impl/src/test/resources/org/apache/cocoon/template/jxtg/jxAttribute-output.xml b/blocks/cocoon-template/cocoon-template-impl/src/test/resources/org/apache/cocoon/template/jxtg/jxAttribute-output.xml
index c204742..c3f9ca2 100644
--- a/blocks/cocoon-template/cocoon-template-impl/src/test/resources/org/apache/cocoon/template/jxtg/jxAttribute-output.xml
+++ b/blocks/cocoon-template/cocoon-template-impl/src/test/resources/org/apache/cocoon/template/jxtg/jxAttribute-output.xml
@@ -21,5 +21,5 @@
 	<three foo="bar" foo2="bar2" dd="dd">
 		<abc>def</abc>
 	</three>
-	<nestedjx value="01 styczeń 1979"/>
+	<nestedjx value="01 Januar 1979"/>
 </root>
diff --git a/blocks/cocoon-template/cocoon-template-impl/src/test/resources/org/apache/cocoon/template/jxtg/jxAttribute.xml b/blocks/cocoon-template/cocoon-template-impl/src/test/resources/org/apache/cocoon/template/jxtg/jxAttribute.xml
index 7b150c5..2a87cdd 100644
--- a/blocks/cocoon-template/cocoon-template-impl/src/test/resources/org/apache/cocoon/template/jxtg/jxAttribute.xml
+++ b/blocks/cocoon-template/cocoon-template-impl/src/test/resources/org/apache/cocoon/template/jxtg/jxAttribute.xml
@@ -30,6 +30,6 @@
 		<abc>def</abc>
 	</three>
 	<nestedjx>
-		<jx:attribute name="value"><jx:formatDate value="${date}" pattern="dd MMMM yyyy" locale="pl_PL"/></jx:attribute>
+		<jx:attribute name="value"><jx:formatDate value="${date}" pattern="dd MMMM yyyy" locale="de_DE"/></jx:attribute>
 	</nestedjx>
 </root>
diff --git a/blocks/cocoon-template/cocoon-template-impl/src/test/resources/org/apache/cocoon/template/jxtg/jxElement-output.xml b/blocks/cocoon-template/cocoon-template-impl/src/test/resources/org/apache/cocoon/template/jxtg/jxElement-output.xml
index c4503a2..fb3d54e 100644
--- a/blocks/cocoon-template/cocoon-template-impl/src/test/resources/org/apache/cocoon/template/jxtg/jxElement-output.xml
+++ b/blocks/cocoon-template/cocoon-template-impl/src/test/resources/org/apache/cocoon/template/jxtg/jxElement-output.xml
@@ -1,35 +1,35 @@
-<?xml version="1.0"?>
-<!--
-  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.
--->
-<root xmlns:jx="http://apache.org/cocoon/templates/jx/1.0">
-	<Empty/>
-	<ElementWithValue>value</ElementWithValue>
-	<OneFixedValueChildNode><ChildNode>Test</ChildNode></OneFixedValueChildNode>	
-	<WithChildGeneratedNode><ChildNode>dd</ChildNode></WithChildGeneratedNode>	
-	<DynamicElement>01 styczeń 1979</DynamicElement>	
-	<WithAttribute attribute="attr"/>
-	<AttributeAndChildNode attribute="attr"><ChildNode>A</ChildNode></AttributeAndChildNode>
-	<MixedContent attribute="attr">A<B/></MixedContent>
-	<MixedContent2 attribute="attr">A<B/></MixedContent2>		
-	<EmptyElementWithNamespace xmlns="http://cocoon.apache.org/kamal"/>
-	<EmptyElementWithGeneratedNamespace xmlns="http://cocoon.apache.org/kamalbhatt"/>	
-	<GeneratedElementWithGeneratedChild xmlns="http://cocoon.apache.org/kamalbhatt">
-	  <GeneratedChild xmlns="http://cocoon.apache.org/kamal">Test</GeneratedChild>
-	</GeneratedElementWithGeneratedChild>	
-	<prefix:ElementWithNamespaceAndHardCodedPrefix xmlns:prefix="http://cocoon.apache.org/kamalbhatt"/>
-	<kb:ElementWithNamespaceAndGeneratedPrefix xmlns:kb="http://cocoon.apache.org/kamalbhatt"/> 
-</root>
+<?xml version="1.0"?>

+<!--

+  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.

+-->

+<root xmlns:jx="http://apache.org/cocoon/templates/jx/1.0">

+	<Empty/>

+	<ElementWithValue>value</ElementWithValue>

+	<OneFixedValueChildNode><ChildNode>Test</ChildNode></OneFixedValueChildNode>	

+	<WithChildGeneratedNode><ChildNode>dd</ChildNode></WithChildGeneratedNode>	

+	<DynamicElement>01 Januar 1979</DynamicElement>	

+	<WithAttribute attribute="attr"/>

+	<AttributeAndChildNode attribute="attr"><ChildNode>A</ChildNode></AttributeAndChildNode>

+	<MixedContent attribute="attr">A<B/></MixedContent>

+	<MixedContent2 attribute="attr">A<B/></MixedContent2>		

+	<EmptyElementWithNamespace xmlns="http://cocoon.apache.org/kamal"/>

+	<EmptyElementWithGeneratedNamespace xmlns="http://cocoon.apache.org/kamalbhatt"/>	

+	<GeneratedElementWithGeneratedChild xmlns="http://cocoon.apache.org/kamalbhatt">

+	  <GeneratedChild xmlns="http://cocoon.apache.org/kamal">Test</GeneratedChild>

+	</GeneratedElementWithGeneratedChild>	

+	<prefix:ElementWithNamespaceAndHardCodedPrefix xmlns:prefix="http://cocoon.apache.org/kamalbhatt"/>

+	<kb:ElementWithNamespaceAndGeneratedPrefix xmlns:kb="http://cocoon.apache.org/kamalbhatt"/> 

+</root>

diff --git a/blocks/cocoon-template/cocoon-template-impl/src/test/resources/org/apache/cocoon/template/jxtg/jxElement.xml b/blocks/cocoon-template/cocoon-template-impl/src/test/resources/org/apache/cocoon/template/jxtg/jxElement.xml
index 98ab317..275537e 100644
--- a/blocks/cocoon-template/cocoon-template-impl/src/test/resources/org/apache/cocoon/template/jxtg/jxElement.xml
+++ b/blocks/cocoon-template/cocoon-template-impl/src/test/resources/org/apache/cocoon/template/jxtg/jxElement.xml
@@ -1,42 +1,42 @@
-<?xml version="1.0"?>
-<!--
-  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.
--->
-<root xmlns:jx="http://apache.org/cocoon/templates/jx/1.0">
-	<jx:set var="a" value="dd"/>
-	<jx:set var="elem" value="DynamicElement"/>
-	<jx:set var="namespace" value="http://cocoon.apache.org/kamalbhatt"/>
-	<jx:set var="prefix" value="kb"/>
-    <jx:element name="Empty"/>
-    <jx:element name="ElementWithValue">value</jx:element>
-	<jx:element name="OneFixedValueChildNode"><ChildNode>Test</ChildNode></jx:element>
-	<jx:element name="WithChildGeneratedNode"><ChildNode><jx:out value="${a}"/></ChildNode></jx:element>
-	<jx:element name="${elem}"><jx:formatDate value="${date}" pattern="dd MMMM yyyy" locale="pl_PL"/></jx:element>
-    <jx:element name="WithAttribute"><jx:attribute name="attribute" value="attr"/></jx:element>	
-	<jx:element name="AttributeAndChildNode">
-	  <jx:attribute name="attribute" value="attr"/>
-	  <ChildNode>A</ChildNode>
-	</jx:element>
-	<jx:element name="MixedContent"><jx:attribute name="attribute" value="attr"/>A<B/></jx:element>
-	<jx:element name="MixedContent2">A<jx:attribute name="attribute" value="attr"/><B/></jx:element>
-	<jx:element name="EmptyElementWithNamespace" uri="http://cocoon.apache.org/kamal"></jx:element>
-	<jx:element name="EmptyElementWithGeneratedNamespace" uri="${namespace}"></jx:element>
-	<jx:element name="GeneratedElementWithGeneratedChild" uri="${namespace}">
-	  <jx:element name="GeneratedChild" uri="http://cocoon.apache.org/kamal">Test</jx:element>
-	</jx:element>
-	<jx:element name="ElementWithNamespaceAndHardCodedPrefix" uri="${namespace}" prefix="prefix"/>
-	<jx:element name="ElementWithNamespaceAndGeneratedPrefix" uri="${namespace}" prefix="${prefix}"/> 
-</root>
+<?xml version="1.0"?>

+<!--

+  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.

+-->

+<root xmlns:jx="http://apache.org/cocoon/templates/jx/1.0">

+	<jx:set var="a" value="dd"/>

+	<jx:set var="elem" value="DynamicElement"/>

+	<jx:set var="namespace" value="http://cocoon.apache.org/kamalbhatt"/>

+	<jx:set var="prefix" value="kb"/>

+    <jx:element name="Empty"/>

+    <jx:element name="ElementWithValue">value</jx:element>

+	<jx:element name="OneFixedValueChildNode"><ChildNode>Test</ChildNode></jx:element>

+	<jx:element name="WithChildGeneratedNode"><ChildNode><jx:out value="${a}"/></ChildNode></jx:element>

+	<jx:element name="${elem}"><jx:formatDate value="${date}" pattern="dd MMMM yyyy" locale="de_DE"/></jx:element>

+    <jx:element name="WithAttribute"><jx:attribute name="attribute" value="attr"/></jx:element>	

+	<jx:element name="AttributeAndChildNode">

+	  <jx:attribute name="attribute" value="attr"/>

+	  <ChildNode>A</ChildNode>

+	</jx:element>

+	<jx:element name="MixedContent"><jx:attribute name="attribute" value="attr"/>A<B/></jx:element>

+	<jx:element name="MixedContent2">A<jx:attribute name="attribute" value="attr"/><B/></jx:element>

+	<jx:element name="EmptyElementWithNamespace" uri="http://cocoon.apache.org/kamal"></jx:element>

+	<jx:element name="EmptyElementWithGeneratedNamespace" uri="${namespace}"></jx:element>

+	<jx:element name="GeneratedElementWithGeneratedChild" uri="${namespace}">

+	  <jx:element name="GeneratedChild" uri="http://cocoon.apache.org/kamal">Test</jx:element>

+	</jx:element>

+	<jx:element name="ElementWithNamespaceAndHardCodedPrefix" uri="${namespace}" prefix="prefix"/>

+	<jx:element name="ElementWithNamespaceAndGeneratedPrefix" uri="${namespace}" prefix="${prefix}"/> 

+</root>

diff --git a/core/cocoon-expression-language/cocoon-expression-language-api/src/main/java/org/apache/cocoon/el/objectmodel/ObjectModel.java b/core/cocoon-expression-language/cocoon-expression-language-api/src/main/java/org/apache/cocoon/el/objectmodel/ObjectModel.java
index d6e6712..5a123d9 100644
--- a/core/cocoon-expression-language/cocoon-expression-language-api/src/main/java/org/apache/cocoon/el/objectmodel/ObjectModel.java
+++ b/core/cocoon-expression-language/cocoon-expression-language-api/src/main/java/org/apache/cocoon/el/objectmodel/ObjectModel.java
@@ -18,7 +18,7 @@
 
 import java.util.Map;
 
-import org.apache.commons.collections.MultiMap;
+import org.apache.cocoon.el.util.MultiMap;
 
 /**
  * ObjectModel is a special {@link Map} that cannot be modified using standard {@link Map} methods, except
diff --git a/core/cocoon-expression-language/cocoon-expression-language-api/src/main/java/org/apache/cocoon/el/util/MultiMap.java b/core/cocoon-expression-language/cocoon-expression-language-api/src/main/java/org/apache/cocoon/el/util/MultiMap.java
new file mode 100644
index 0000000..c8b9d31
--- /dev/null
+++ b/core/cocoon-expression-language/cocoon-expression-language-api/src/main/java/org/apache/cocoon/el/util/MultiMap.java
@@ -0,0 +1,160 @@
+package org.apache.cocoon.el.util;

+

+/*

+ *  Copyright 2001-2004 The Apache Software Foundation

+ *

+ *  Licensed 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.

+ */

+

+import java.util.Collection;

+import java.util.Map;

+

+/** 

+ * Defines a map that holds a collection of values against each key.

+ * <p>

+ * A <code>MultiMap</code> is a Map with slightly different semantics.

+ * Putting a value into the map will add the value to a Collection at that key.

+ * Getting a value will return a Collection, holding all the values put to that key.

+ * <p>

+ * For example:

+ * <pre>

+ * MultiMap mhm = new MultiHashMap();

+ * mhm.put(key, "A");

+ * mhm.put(key, "B");

+ * mhm.put(key, "C");

+ * Collection coll = (Collection) mhm.get(key);</pre>

+ * <p>

+ * <code>coll</code> will be a collection containing "A", "B", "C".

+ * <p>

+ * NOTE: Additional methods were added to this interface in Commons Collections 3.1.

+ * These were added solely for documentation purposes and do not change the interface

+ * as they were defined in the superinterface <code>Map</code> anyway.

+ *

+ * @since Commons Collections 2.0

+ * @version $Revision: 155406 $ $Date: 2005-02-26 12:55:26 +0000 (Sat, 26 Feb 2005) $

+ * 

+ * @author Christopher Berry

+ * @author James Strachan

+ * @author Stephen Colebourne

+ */

+public interface MultiMap extends Map {

+

+    /**

+     * Removes a specific value from map.

+     * <p>

+     * The item is removed from the collection mapped to the specified key.

+     * Other values attached to that key are unaffected.

+     * <p>

+     * If the last value for a key is removed, implementations typically

+     * return <code>null</code> from a subsequant <code>get(Object)</code>, however

+     * they may choose to return an empty collection.

+     * 

+     * @param key  the key to remove from

+     * @param item  the item to remove

+     * @return the value removed (which was passed in), null if nothing removed

+     * @throws UnsupportedOperationException if the map is unmodifiable

+     * @throws ClassCastException if the key or value is of an invalid type

+     * @throws NullPointerException if the key or value is null and null is invalid

+     */

+    public boolean remove(Object key, Object item);

+

+    //-----------------------------------------------------------------------

+    /**

+     * Gets the number of keys in this map.

+     * <p>

+     * Implementations typically return only the count of keys in the map

+     * This cannot be mandated due to backwards compatability of this interface.

+     *

+     * @return the number of key-collection mappings in this map

+     */

+    int size();

+

+    /**

+     * Gets the collection of values associated with the specified key.

+     * <p>

+     * The returned value will implement <code>Collection</code>. Implementations

+     * are free to declare that they return <code>Collection</code> subclasses

+     * such as <code>List</code> or <code>Set</code>.

+     * <p>

+     * Implementations typically return <code>null</code> if no values have

+     * been mapped to the key, however the implementation may choose to

+     * return an empty collection.

+     * <p>

+     * Implementations may choose to return a clone of the internal collection.

+     *

+     * @param key  the key to retrieve

+     * @return the <code>Collection</code> of values, implementations should

+     *  return <code>null</code> for no mapping, but may return an empty collection

+     * @throws ClassCastException if the key is of an invalid type

+     * @throws NullPointerException if the key is null and null keys are invalid

+     */

+    Object get(Object key);

+

+    /**

+     * Checks whether the map contains the value specified.

+     * <p>

+     * Implementations typically check all collections against all keys for the value.

+     * This cannot be mandated due to backwards compatability of this interface.

+     *

+     * @param value  the value to search for

+     * @return true if the map contains the value

+     * @throws ClassCastException if the value is of an invalid type

+     * @throws NullPointerException if the value is null and null value are invalid

+     */

+    boolean containsValue(Object value);

+

+    /**

+     * Adds the value to the collection associated with the specified key.

+     * <p>

+     * Unlike a normal <code>Map</code> the previous value is not replaced.

+     * Instead the new value is added to the collection stored against the key.

+     * The collection may be a <code>List</code>, <code>Set</code> or other

+     * collection dependent on implementation.

+     *

+     * @param key  the key to store against

+     * @param value  the value to add to the collection at the key

+     * @return typically the value added if the map changed and null if the map did not change

+     * @throws UnsupportedOperationException if the map is unmodifiable

+     * @throws ClassCastException if the key or value is of an invalid type

+     * @throws NullPointerException if the key or value is null and null is invalid

+     * @throws IllegalArgumentException if the key or value is invalid

+     */

+    Object put(Object key, Object value);

+

+    /**

+     * Removes all values associated with the specified key.

+     * <p>

+     * Implementations typically return <code>null</code> from a subsequant

+     * <code>get(Object)</code>, however they may choose to return an empty collection.

+     *

+     * @param key  the key to remove values from

+     * @return the <code>Collection</code> of values removed, implementations should

+     *  return <code>null</code> for no mapping found, but may return an empty collection

+     * @throws UnsupportedOperationException if the map is unmodifiable

+     * @throws ClassCastException if the key is of an invalid type

+     * @throws NullPointerException if the key is null and null keys are invalid

+     */

+    Object remove(Object key);

+

+    /**

+     * Gets a collection containing all the values in the map.

+     * <p>

+     * Inplementations typically return a collection containing the combination

+     * of values from all keys.

+     * This cannot be mandated due to backwards compatability of this interface.

+     *

+     * @return a collection view of the values contained in this map

+     */

+    Collection values();

+

+}

diff --git a/core/cocoon-expression-language/cocoon-expression-language-api/src/main/java/org/apache/cocoon/el/util/MultiValueMap.java b/core/cocoon-expression-language/cocoon-expression-language-api/src/main/java/org/apache/cocoon/el/util/MultiValueMap.java
new file mode 100644
index 0000000..221277c
--- /dev/null
+++ b/core/cocoon-expression-language/cocoon-expression-language-api/src/main/java/org/apache/cocoon/el/util/MultiValueMap.java
@@ -0,0 +1,439 @@
+package org.apache.cocoon.el.util;

+

+/*

+ *  Copyright 2001-2005 The Apache Software Foundation

+ *

+ *  Licensed 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.

+ */

+import java.util.AbstractCollection;

+import java.util.ArrayList;

+import java.util.Collection;

+import java.util.HashMap;

+import java.util.Iterator;

+import java.util.Map;

+import java.util.Set;

+

+import org.apache.commons.collections.Factory;

+import org.apache.commons.collections.FunctorException;

+import org.apache.commons.collections.iterators.EmptyIterator;

+import org.apache.commons.collections.iterators.IteratorChain;

+import org.apache.commons.collections.map.AbstractMapDecorator;

+

+/**

+ * A MultiValueMap decorates another map, allowing it to have

+ * more than one value for a key.

+ * <p>

+ * A <code>MultiMap</code> is a Map with slightly different semantics.

+ * Putting a value into the map will add the value to a Collection at that key.

+ * Getting a value will return a Collection, holding all the values put to that key.

+ * <p>

+ * This implementation is a decorator, allowing any Map implementation

+ * to be used as the base.

+ * <p>

+ * In addition, this implementation allows the type of collection used

+ * for the values to be controlled. By default, an <code>ArrayList</code>

+ * is used, however a <code>Class</code> to instantiate may be specified,

+ * or a factory that returns a <code>Collection</code> instance.

+ * <p>

+ * <strong>Note that MultiValueMap is not synchronized and is not thread-safe.</strong>

+ * If you wish to use this map from multiple threads concurrently, you must use

+ * appropriate synchronization. This class may throw exceptions when accessed

+ * by concurrent threads without synchronization.

+ *

+ * @author James Carman

+ * @author Christopher Berry

+ * @author James Strachan

+ * @author Steve Downey

+ * @author Stephen Colebourne

+ * @author Julien Buret

+ * @author Serhiy Yevtushenko

+ * @version $Revision: 348007 $ $Date: 2005-11-21 22:52:57 +0000 (Mon, 21 Nov 2005) $

+ * @since Commons Collections 3.2

+ */

+public class MultiValueMap extends AbstractMapDecorator implements MultiMap {

+

+    /** The factory for creating value collections. */

+    private final Factory collectionFactory;

+    /** The cached values. */

+    private transient Collection values;

+

+    /**

+     * Creates a map which wraps the given map and

+     * maps keys to ArrayLists.

+     *

+     * @param map  the map to wrap

+     */

+    public static MultiValueMap decorate(Map map) {

+        return new MultiValueMap(map, new ReflectionFactory(ArrayList.class));

+    }

+

+    /**

+     * Creates a map which decorates the given <code>map</code> and

+     * maps keys to collections of type <code>collectionClass</code>.

+     *

+     * @param map  the map to wrap

+     * @param collectionClass  the type of the collection class

+     */

+    public static MultiValueMap decorate(Map map, Class collectionClass) {

+        return new MultiValueMap(map, new ReflectionFactory(collectionClass));

+    }

+

+    /**

+     * Creates a map which decorates the given <code>map</code> and

+     * creates the value collections using the supplied <code>collectionFactory</code>.

+     *

+     * @param map  the map to decorate

+     * @param collectionFactory  the collection factory (must return a Collection object).

+     */

+    public static MultiValueMap decorate(Map map, Factory collectionFactory) {

+        return new MultiValueMap(map, collectionFactory);

+    }

+

+    //-----------------------------------------------------------------------

+    /**

+     * Creates a MultiValueMap based on a <code>HashMap</code> and

+     * storing the multiple values in an <code>ArrayList</code>.

+     */

+    public MultiValueMap() {

+        this(new HashMap(), new ReflectionFactory(ArrayList.class));

+    }

+

+    /**

+     * Creates a MultiValueMap which decorates the given <code>map</code> and

+     * creates the value collections using the supplied <code>collectionFactory</code>.

+     *

+     * @param map  the map to decorate

+     * @param collectionFactory  the collection factory which must return a Collection instance

+     */

+    protected MultiValueMap(Map map, Factory collectionFactory) {

+        super(map);

+        if (collectionFactory == null) {

+            throw new IllegalArgumentException("The factory must not be null");

+        }

+        this.collectionFactory = collectionFactory;

+    }

+

+    //-----------------------------------------------------------------------

+    /**

+     * Clear the map.

+     */

+    public void clear() {

+        // If you believe that you have GC issues here, try uncommenting this code

+//        Set pairs = getMap().entrySet();

+//        Iterator pairsIterator = pairs.iterator();

+//        while (pairsIterator.hasNext()) {

+//            Map.Entry keyValuePair = (Map.Entry) pairsIterator.next();

+//            Collection coll = (Collection) keyValuePair.getValue();

+//            coll.clear();

+//        }

+        getMap().clear();

+    }

+

+    /**

+     * Removes a specific value from map.

+     * <p>

+     * The item is removed from the collection mapped to the specified key.

+     * Other values attached to that key are unaffected.

+     * <p>

+     * If the last value for a key is removed, <code>null</code> will be returned

+     * from a subsequant <code>get(key)</code>.

+     *

+     * @param key  the key to remove from

+     * @param value the value to remove

+     * @return true if something was removed, false if nothing was removed

+     */

+    public boolean remove(Object key, Object value) {

+        Collection valuesForKey = getCollection(key);

+        if (valuesForKey == null) {

+            return false;

+        }

+        boolean removed = valuesForKey.remove(value);

+        if (removed == false) {

+            return false;

+        }

+        if (valuesForKey.isEmpty()) {

+            remove(key);

+        }

+        return true;

+    }

+

+    /**

+     * Checks whether the map contains the value specified.

+     * <p>

+     * This checks all collections against all keys for the value, and thus could be slow.

+     *

+     * @param value  the value to search for

+     * @return true if the map contains the value

+     */

+    public boolean containsValue(Object value) {

+        Set pairs = getMap().entrySet();

+        if (pairs == null) {

+            return false;

+        }

+        Iterator pairsIterator = pairs.iterator();

+        while (pairsIterator.hasNext()) {

+            Map.Entry keyValuePair = (Map.Entry) pairsIterator.next();

+            Collection coll = (Collection) keyValuePair.getValue();

+            if (coll.contains(value)) {

+                return true;

+            }

+        }

+        return false;

+    }

+

+    /**

+     * Adds the value to the collection associated with the specified key.

+     * <p>

+     * Unlike a normal <code>Map</code> the previous value is not replaced.

+     * Instead the new value is added to the collection stored against the key.

+     *

+     * @param key  the key to store against

+     * @param value  the value to add to the collection at the key

+     * @return the value added if the map changed and null if the map did not change

+     */

+    public Object put(Object key, Object value) {

+        boolean result = false;

+        Collection coll = getCollection(key);

+        if (coll == null) {

+            coll = createCollection(1);

+            result = coll.add(value);

+            if (coll.size() > 0) {

+                // only add if non-zero size to maintain class state

+                getMap().put(key, coll);

+                result = false;

+            }

+        } else {

+            result = coll.add(value);

+        }

+        return (result ? value : null);

+    }

+

+    /**

+     * Override superclass to ensure that MultiMap instances are

+     * correctly handled.

+     * <p>

+     * If you call this method with a normal map, each entry is

+     * added using <code>put(Object,Object)</code>.

+     * If you call this method with a multi map, each entry is

+     * added using <code>putAll(Object,Collection)</code>.

+     *

+     * @param map  the map to copy (either a normal or multi map)

+     */

+    public void putAll(Map map) {

+        if (map instanceof MultiMap) {

+            for (Iterator it = map.entrySet().iterator(); it.hasNext();) {

+                Map.Entry entry = (Map.Entry) it.next();

+                Collection coll = (Collection) entry.getValue();

+                putAll(entry.getKey(), coll);

+            }

+        } else {

+            for (Iterator it = map.entrySet().iterator(); it.hasNext();) {

+                Map.Entry entry = (Map.Entry) it.next();

+                put(entry.getKey(), entry.getValue());

+            }

+        }

+    }

+

+    /**

+     * Gets a collection containing all the values in the map.

+     * <p>

+     * This returns a collection containing the combination of values from all keys.

+     *

+     * @return a collection view of the values contained in this map

+     */

+    public Collection values() {

+        Collection vs = values;

+        return (vs != null ? vs : (values = new Values()));

+    }

+

+    /**

+     * Checks whether the collection at the specified key contains the value.

+     *

+     * @param value  the value to search for

+     * @return true if the map contains the value

+     */

+    public boolean containsValue(Object key, Object value) {

+        Collection coll = getCollection(key);

+        if (coll == null) {

+            return false;

+        }

+        return coll.contains(value);

+    }

+

+    /**

+     * Gets the collection mapped to the specified key.

+     * This method is a convenience method to typecast the result of <code>get(key)</code>.

+     *

+     * @param key  the key to retrieve

+     * @return the collection mapped to the key, null if no mapping

+     */

+    public Collection getCollection(Object key) {

+        return (Collection) getMap().get(key);

+    }

+

+    /**

+     * Gets the size of the collection mapped to the specified key.

+     *

+     * @param key  the key to get size for

+     * @return the size of the collection at the key, zero if key not in map

+     */

+    public int size(Object key) {

+        Collection coll = getCollection(key);

+        if (coll == null) {

+            return 0;

+        }

+        return coll.size();

+    }

+

+    /**

+     * Adds a collection of values to the collection associated with

+     * the specified key.

+     *

+     * @param key  the key to store against

+     * @param values  the values to add to the collection at the key, null ignored

+     * @return true if this map changed

+     */

+    public boolean putAll(Object key, Collection values) {

+        if (values == null || values.size() == 0) {

+            return false;

+        }

+        Collection coll = getCollection(key);

+        if (coll == null) {

+            coll = createCollection(values.size());

+            boolean result = coll.addAll(values);

+            if (coll.size() > 0) {

+                // only add if non-zero size to maintain class state

+                getMap().put(key, coll);

+                result = false;

+            }

+            return result;

+        } else {

+            return coll.addAll(values);

+        }

+    }

+

+    /**

+     * Gets an iterator for the collection mapped to the specified key.

+     *

+     * @param key  the key to get an iterator for

+     * @return the iterator of the collection at the key, empty iterator if key not in map

+     */

+    public Iterator iterator(Object key) {

+        if (!containsKey(key)) {

+            return EmptyIterator.INSTANCE;

+        } else {

+            return new ValuesIterator(key);

+        }

+    }

+

+    /**

+     * Gets the total size of the map by counting all the values.

+     *

+     * @return the total size of the map counting all values

+     */

+    public int totalSize() {

+        int total = 0;

+        Collection values = getMap().values();

+        for (Iterator it = values.iterator(); it.hasNext();) {

+            Collection coll = (Collection) it.next();

+            total += coll.size();

+        }

+        return total;

+    }

+

+    /**

+     * Creates a new instance of the map value Collection container

+     * using the factory.

+     * <p>

+     * This method can be overridden to perform your own processing

+     * instead of using the factory.

+     *

+     * @param size  the collection size that is about to be added

+     * @return the new collection

+     */

+    protected Collection createCollection(int size) {

+        return (Collection) collectionFactory.create();

+    }

+

+    //-----------------------------------------------------------------------

+    /**

+     * Inner class that provides the values view.

+     */

+    private class Values extends AbstractCollection {

+        public Iterator iterator() {

+            final IteratorChain chain = new IteratorChain();

+            for (Iterator it = keySet().iterator(); it.hasNext();) {

+                chain.addIterator(new ValuesIterator(it.next()));

+            }

+            return chain;

+        }

+

+        public int size() {

+            return totalSize();

+        }

+

+        public void clear() {

+            MultiValueMap.this.clear();

+        }

+    }

+

+    /**

+     * Inner class that provides the values iterator.

+     */

+    private class ValuesIterator implements Iterator {

+        private final Object key;

+        private final Collection values;

+        private final Iterator iterator;

+

+        public ValuesIterator(Object key) {

+            this.key = key;

+            this.values = getCollection(key);

+            this.iterator = values.iterator();

+        }

+

+        public void remove() {

+            iterator.remove();

+            if (values.isEmpty()) {

+                MultiValueMap.this.remove(key);

+            }

+        }

+

+        public boolean hasNext() {

+            return iterator.hasNext();

+        }

+

+        public Object next() {

+            return iterator.next();

+        }

+    }

+

+    /**

+     * Inner class that provides a simple reflection factory.

+     */

+    private static class ReflectionFactory implements Factory {

+        private final Class clazz;

+

+        public ReflectionFactory(Class clazz) {

+            this.clazz = clazz;

+        }

+

+        public Object create() {

+            try {

+                return clazz.newInstance();

+            } catch (Exception ex) {

+                throw new FunctorException("Cannot instantiate class: " + clazz, ex);

+            }

+        }

+    }

+

+}

diff --git a/core/cocoon-expression-language/cocoon-expression-language-impl/src/main/java/org/apache/cocoon/el/impl/objectmodel/ObjectModelImpl.java b/core/cocoon-expression-language/cocoon-expression-language-impl/src/main/java/org/apache/cocoon/el/impl/objectmodel/ObjectModelImpl.java
index c5a9839..68bcded 100644
--- a/core/cocoon-expression-language/cocoon-expression-language-impl/src/main/java/org/apache/cocoon/el/impl/objectmodel/ObjectModelImpl.java
+++ b/core/cocoon-expression-language/cocoon-expression-language-impl/src/main/java/org/apache/cocoon/el/impl/objectmodel/ObjectModelImpl.java
@@ -23,15 +23,15 @@
 import java.util.ListIterator;
 import java.util.Map;
 
+import org.apache.cocoon.el.util.MultiMap;
+import org.apache.cocoon.el.util.MultiValueMap;
 import org.apache.cocoon.el.objectmodel.ObjectModel;
 import org.apache.cocoon.el.objectmodel.ObjectModelProvider;
 import org.apache.commons.collections.ArrayStack;
 import org.apache.commons.collections.KeyValue;
-import org.apache.commons.collections.MultiMap;
 import org.apache.commons.collections.iterators.ReverseListIterator;
 import org.apache.commons.collections.keyvalue.DefaultKeyValue;
 import org.apache.commons.collections.map.AbstractMapDecorator;
-import org.apache.commons.collections.map.MultiValueMap;
 import org.apache.commons.jxpath.DynamicPropertyHandler;
 import org.apache.commons.jxpath.JXPathBeanInfo;
 import org.apache.commons.jxpath.JXPathIntrospector;
diff --git a/core/cocoon-expression-language/cocoon-expression-language-impl/src/main/java/org/apache/cocoon/el/impl/objectmodel/UnmodifiableMultiMap.java b/core/cocoon-expression-language/cocoon-expression-language-impl/src/main/java/org/apache/cocoon/el/impl/objectmodel/UnmodifiableMultiMap.java
index 72ecf86..8183248 100644
--- a/core/cocoon-expression-language/cocoon-expression-language-impl/src/main/java/org/apache/cocoon/el/impl/objectmodel/UnmodifiableMultiMap.java
+++ b/core/cocoon-expression-language/cocoon-expression-language-impl/src/main/java/org/apache/cocoon/el/impl/objectmodel/UnmodifiableMultiMap.java
@@ -20,9 +20,9 @@
 import java.util.Map;
 import java.util.Set;
 
+import org.apache.cocoon.el.util.MultiMap;
 import org.apache.commons.collections.IterableMap;
 import org.apache.commons.collections.MapIterator;
-import org.apache.commons.collections.MultiMap;
 import org.apache.commons.collections.Unmodifiable;
 import org.apache.commons.collections.collection.UnmodifiableCollection;
 import org.apache.commons.collections.iterators.EntrySetMapIterator;
@@ -103,7 +103,7 @@
         throw new UnsupportedOperationException();
     }
     
-    public Object remove(Object key, Object item) {
+    public boolean remove(Object key, Object item) {
         throw new UnsupportedOperationException();
     }
 
diff --git a/core/cocoon-sitemap/cocoon-sitemap-impl/src/main/java/org/apache/cocoon/core/container/spring/avalon/AvalonBeanPostProcessor.java b/core/cocoon-sitemap/cocoon-sitemap-impl/src/main/java/org/apache/cocoon/core/container/spring/avalon/AvalonBeanPostProcessor.java
index 5021e4b..1e48bfd 100644
--- a/core/cocoon-sitemap/cocoon-sitemap-impl/src/main/java/org/apache/cocoon/core/container/spring/avalon/AvalonBeanPostProcessor.java
+++ b/core/cocoon-sitemap/cocoon-sitemap-impl/src/main/java/org/apache/cocoon/core/container/spring/avalon/AvalonBeanPostProcessor.java
@@ -272,4 +272,8 @@
         }
         ContainerUtil.dispose(bean);
     }
+    
+    public boolean requiresDestruction(Object bean) {
+    	return true;
+    }
 }
diff --git a/core/cocoon-sitemap/cocoon-sitemap-impl/src/main/java/org/apache/cocoon/core/container/spring/avalon/BridgeElementParser.java b/core/cocoon-sitemap/cocoon-sitemap-impl/src/main/java/org/apache/cocoon/core/container/spring/avalon/BridgeElementParser.java
index a89acf0..ae4dbbf 100644
--- a/core/cocoon-sitemap/cocoon-sitemap-impl/src/main/java/org/apache/cocoon/core/container/spring/avalon/BridgeElementParser.java
+++ b/core/cocoon-sitemap/cocoon-sitemap-impl/src/main/java/org/apache/cocoon/core/container/spring/avalon/BridgeElementParser.java
@@ -254,9 +254,9 @@
             if ( current.getDestroyMethodName() != null ) {
                 beanDef.setDestroyMethodName(current.getDestroyMethodName());
             }
-            if (singleton) {
-                beanDef.setScope(BeanDefinition.SCOPE_SINGLETON);
-            }
+            
+            beanDef.setScope( singleton ? BeanDefinition.SCOPE_SINGLETON : BeanDefinition.SCOPE_PROTOTYPE );
+            
             beanDef.setLazyInit(singleton && current.isLazyInit());
             if ( isSelector ) {
                 beanDef.getConstructorArgumentValues().
diff --git a/core/cocoon-sitemap/cocoon-sitemap-impl/src/test/java/org/apache/cocoon/AbstractTestCase.java b/core/cocoon-sitemap/cocoon-sitemap-impl/src/test/java/org/apache/cocoon/AbstractTestCase.java
index 9b73973..14cb8aa 100644
--- a/core/cocoon-sitemap/cocoon-sitemap-impl/src/test/java/org/apache/cocoon/AbstractTestCase.java
+++ b/core/cocoon-sitemap/cocoon-sitemap-impl/src/test/java/org/apache/cocoon/AbstractTestCase.java
@@ -153,6 +153,11 @@
 
         MockWebApplicationContext ctx = new MockWebApplicationContext(this.beanFactory, getContext());
         getContext().setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ctx);
+        
+        // COCOON-2374
+        // needed to avoid problem with 
+        // java.lang.IllegalStateException: org.apache.cocoon.MockWebApplicationContext@7d898981 has not been refreshed yet
+        ctx.refresh();
     }
 
     protected void createBeanFactory() throws Exception {
diff --git a/parent/pom.xml b/parent/pom.xml
index 2f9cdc0..55c8c9f 100644
--- a/parent/pom.xml
+++ b/parent/pom.xml
@@ -3179,7 +3179,7 @@
   <properties>
     <targetJdk>1.6</targetJdk>
     <maven.version>2.0.11</maven.version>
-    <spring.version>4.2.2.RELEASE</spring.version>
+    <spring.version>4.3.15.RELEASE</spring.version>
 
     <!-- General doc properties -->
     <docs.deploymentBaseUrl>file://${basedir}/../../../site/site</docs.deploymentBaseUrl>