[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>