You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by mb...@apache.org on 2009/03/09 23:48:07 UTC

svn commit: r751894 - in /commons/proper/collections/branches/collections_jdk5_branch/src: java/org/apache/commons/collections/splitmap/ test/org/apache/commons/collections/ test/org/apache/commons/collections/splitmap/

Author: mbenson
Date: Mon Mar  9 22:48:07 2009
New Revision: 751894

URL: http://svn.apache.org/viewvc?rev=751894&view=rev
Log:
add splitmap package whose original goal is to provide a more versatile TransformedMap implementation

Added:
    commons/proper/collections/branches/collections_jdk5_branch/src/java/org/apache/commons/collections/splitmap/
    commons/proper/collections/branches/collections_jdk5_branch/src/java/org/apache/commons/collections/splitmap/AbstractIterableGetMapDecorator.java   (with props)
    commons/proper/collections/branches/collections_jdk5_branch/src/java/org/apache/commons/collections/splitmap/SplitMapUtils.java   (with props)
    commons/proper/collections/branches/collections_jdk5_branch/src/java/org/apache/commons/collections/splitmap/TransformedMap.java   (with props)
    commons/proper/collections/branches/collections_jdk5_branch/src/java/org/apache/commons/collections/splitmap/package.html   (with props)
    commons/proper/collections/branches/collections_jdk5_branch/src/test/org/apache/commons/collections/splitmap/
    commons/proper/collections/branches/collections_jdk5_branch/src/test/org/apache/commons/collections/splitmap/TestAll.java   (with props)
    commons/proper/collections/branches/collections_jdk5_branch/src/test/org/apache/commons/collections/splitmap/TestSplitMapUtils.java   (with props)
    commons/proper/collections/branches/collections_jdk5_branch/src/test/org/apache/commons/collections/splitmap/TestTransformedMap.java   (with props)
Modified:
    commons/proper/collections/branches/collections_jdk5_branch/src/test/org/apache/commons/collections/TestAllPackages.java

Added: commons/proper/collections/branches/collections_jdk5_branch/src/java/org/apache/commons/collections/splitmap/AbstractIterableGetMapDecorator.java
URL: http://svn.apache.org/viewvc/commons/proper/collections/branches/collections_jdk5_branch/src/java/org/apache/commons/collections/splitmap/AbstractIterableGetMapDecorator.java?rev=751894&view=auto
==============================================================================
--- commons/proper/collections/branches/collections_jdk5_branch/src/java/org/apache/commons/collections/splitmap/AbstractIterableGetMapDecorator.java (added)
+++ commons/proper/collections/branches/collections_jdk5_branch/src/java/org/apache/commons/collections/splitmap/AbstractIterableGetMapDecorator.java Mon Mar  9 22:48:07 2009
@@ -0,0 +1,161 @@
+/*
+ * 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.collections.splitmap;
+
+import java.util.Collection;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.collections.Get;
+import org.apache.commons.collections.IterableGet;
+import org.apache.commons.collections.MapIterator;
+import org.apache.commons.collections.map.EntrySetToMapIteratorAdapter;
+
+/**
+ * {@link IterableGet} that uses a {@link Map}<K, V> for the {@link Get}<K, V>
+ * implementation.
+ *
+ * @since Commons Collections 5
+ * @TODO fix version
+ * @version $Revision$ $Date$
+ *
+ * @author Matt Benson
+ */
+public class AbstractIterableGetMapDecorator<K, V> implements IterableGet<K, V> {
+    /** The map to decorate */
+    protected transient Map<K, V> map;
+
+    /**
+     * Create a new AbstractSplitMapDecorator.
+     * @param decorated the Map to decorate
+     */
+    public AbstractIterableGetMapDecorator(Map<K, V> decorated) {
+        this.map = decorated;
+    }
+
+    /**
+     * Gets the map being decorated.
+     *
+     * @return the decorated map
+     */
+    protected Map<K, V> decorated() {
+        return map;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void clear() {
+        decorated().clear();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean containsKey(Object key) {
+        return decorated().containsKey(key);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean containsValue(Object value) {
+        return decorated().containsValue(value);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Set<Map.Entry<K, V>> entrySet() {
+        return decorated().entrySet();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public V get(Object key) {
+        return decorated().get(key);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public V remove(Object key) {
+        return decorated().remove(key);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isEmpty() {
+        return decorated().isEmpty();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Set<K> keySet() {
+        return decorated().keySet();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public int size() {
+        return decorated().size();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Collection<V> values() {
+        return decorated().values();
+    }
+
+    /**
+     * Get a MapIterator over this Get.
+     * @return MapIterator<K, V>
+     */
+    public MapIterator<K, V> mapIterator() {
+        return new EntrySetToMapIteratorAdapter<K, V>(entrySet());
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean equals(Object object) {
+        if (object == this) {
+            return true;
+        }
+        return decorated().equals(object);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public int hashCode() {
+        return decorated().hashCode();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String toString() {
+        return decorated().toString();
+    }
+
+}

Propchange: commons/proper/collections/branches/collections_jdk5_branch/src/java/org/apache/commons/collections/splitmap/AbstractIterableGetMapDecorator.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/proper/collections/branches/collections_jdk5_branch/src/java/org/apache/commons/collections/splitmap/AbstractIterableGetMapDecorator.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Added: commons/proper/collections/branches/collections_jdk5_branch/src/java/org/apache/commons/collections/splitmap/SplitMapUtils.java
URL: http://svn.apache.org/viewvc/commons/proper/collections/branches/collections_jdk5_branch/src/java/org/apache/commons/collections/splitmap/SplitMapUtils.java?rev=751894&view=auto
==============================================================================
--- commons/proper/collections/branches/collections_jdk5_branch/src/java/org/apache/commons/collections/splitmap/SplitMapUtils.java (added)
+++ commons/proper/collections/branches/collections_jdk5_branch/src/java/org/apache/commons/collections/splitmap/SplitMapUtils.java Mon Mar  9 22:48:07 2009
@@ -0,0 +1,233 @@
+package org.apache.commons.collections.splitmap;
+
+import java.util.Collection;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.collections.Get;
+import org.apache.commons.collections.IterableGet;
+import org.apache.commons.collections.IterableMap;
+import org.apache.commons.collections.MapIterator;
+import org.apache.commons.collections.MapUtils;
+import org.apache.commons.collections.Put;
+import org.apache.commons.collections.Unmodifiable;
+import org.apache.commons.collections.collection.UnmodifiableCollection;
+import org.apache.commons.collections.iterators.UnmodifiableMapIterator;
+import org.apache.commons.collections.map.EntrySetToMapIteratorAdapter;
+import org.apache.commons.collections.map.UnmodifiableEntrySet;
+import org.apache.commons.collections.set.UnmodifiableSet;
+
+/**
+ * Utilities for working with "split maps:" objects that implement {@link Put}
+ * and/or {@link Get} but not {@link Map}.
+ *
+ * @since Commons Collections 5
+ * @TODO fix version
+ * @version $Revision$ $Date$
+ * @see Get
+ * @see Put
+ * @author Matt Benson
+ */
+public class SplitMapUtils {
+
+    /**
+     * <code>SplitMapUtils</code> should not normally be instantiated.
+     */
+    public SplitMapUtils() {
+    }
+
+    private static class WrappedGet<K, V> implements IterableMap<K, V>, Unmodifiable {
+        private Get<K, V> get;
+
+        private WrappedGet(Get<K, V> get) {
+            this.get = get;
+        }
+
+        public void clear() {
+            throw new UnsupportedOperationException();
+        }
+
+        public boolean containsKey(Object key) {
+            return get.containsKey(key);
+        }
+
+        public boolean containsValue(Object value) {
+            return get.containsValue(value);
+        }
+
+        public Set<java.util.Map.Entry<K, V>> entrySet() {
+            return UnmodifiableEntrySet.decorate(get.entrySet());
+        }
+
+        @Override
+        public boolean equals(Object arg0) {
+            if (arg0 == this) {
+                return true;
+            }
+            return arg0 instanceof WrappedGet && ((WrappedGet<?, ?>) arg0).get.equals(this.get);
+        }
+
+        public V get(Object key) {
+            return get.get(key);
+        }
+
+        @Override
+        public int hashCode() {
+            return ("WrappedGet".hashCode() << 4) | get.hashCode();
+        }
+
+        public boolean isEmpty() {
+            return get.isEmpty();
+        }
+
+        public Set<K> keySet() {
+            return UnmodifiableSet.decorate(get.keySet());
+        }
+
+        public V put(K key, V value) {
+            throw new UnsupportedOperationException();
+        };
+
+        public void putAll(Map<? extends K, ? extends V> t) {
+            throw new UnsupportedOperationException();
+        }
+
+        public V remove(Object key) {
+            return get.remove(key);
+        }
+
+        public int size() {
+            return get.size();
+        }
+
+        public Collection<V> values() {
+            return UnmodifiableCollection.decorate(get.values());
+        }
+
+        public MapIterator<K, V> mapIterator() {
+            MapIterator<K, V> it;
+            if (get instanceof IterableGet) {
+                it = ((IterableGet<K, V>) get).mapIterator();
+            } else {
+                it = new EntrySetToMapIteratorAdapter<K, V>(get.entrySet());
+            }
+            return UnmodifiableMapIterator.decorate(it);
+        }
+    }
+
+    private static class WrappedPut<K, V> implements Map<K, V>, Put<K, V> {
+        private Put<K, V> put;
+
+        private WrappedPut(Put<K, V> put) {
+            this.put = put;
+        }
+
+        public void clear() {
+            put.clear();
+        }
+
+        public boolean containsKey(Object key) {
+            throw new UnsupportedOperationException();
+        }
+
+        public boolean containsValue(Object value) {
+            throw new UnsupportedOperationException();
+        }
+
+        public Set<java.util.Map.Entry<K, V>> entrySet() {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (obj == this) {
+                return true;
+            }
+            return obj instanceof WrappedPut && ((WrappedPut<?, ?>) obj).put.equals(this.put);
+        }
+
+        public V get(Object key) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public int hashCode() {
+            return ("WrappedPut".hashCode() << 4) | put.hashCode();
+        }
+
+        public boolean isEmpty() {
+            throw new UnsupportedOperationException();
+        }
+
+        public Set<K> keySet() {
+            throw new UnsupportedOperationException();
+        }
+
+        @SuppressWarnings("unchecked")
+        public V put(K key, V value) {
+            return (V) put.put(key, value);
+        };
+
+        public void putAll(Map<? extends K, ? extends V> t) {
+            put.putAll(t);
+        }
+
+        public V remove(Object key) {
+            throw new UnsupportedOperationException();
+        }
+
+        public int size() {
+            throw new UnsupportedOperationException();
+        }
+
+        public Collection<V> values() {
+            throw new UnsupportedOperationException();
+        }
+    }
+
+    /**
+     * Get the specified {@link Get} as an instance of {@link IterableMap}.
+     * If <code>get</code> implements {@link IterableMap} directly, no conversion will take place.
+     * If <code>get</code> implements {@link Map} but not {@link IterableMap} it will be decorated.
+     * Otherwise an {@link Unmodifiable} {@link IterableMap} will be returned.
+     * @param <K>
+     * @param <V>
+     * @param get to wrap, must not be null
+     * @return {@link IterableMap}
+     */
+    @SuppressWarnings("unchecked")
+    public static <K, V> IterableMap<K, V> readableMap(Get<K, V> get) {
+        if (get == null) {
+            throw new IllegalArgumentException("Get must not be null");
+        }
+        if (get instanceof Map) {
+            return get instanceof IterableMap ? ((IterableMap<K, V>) get) : MapUtils
+                    .iterableMap((Map<K, V>) get);
+        }
+        return new WrappedGet<K, V>(get);
+    }
+
+    /**
+     * Get the specified {@link Put} as an instanceof {@link Map}.
+     * If <code>put</code> implements {@link Map} directly, no conversion will take place.
+     * Otherwise a <em>write-only</em> {@link Map} will be returned.  On such a {@link Map}
+     * it is recommended that the result of #put(K, V) be discarded as it likely will not
+     * match <code>V</code> at runtime.
+     *
+     * @param <K>
+     * @param <V>
+     * @param put to wrap, must not be null
+     * @return {@link Map}
+     */
+    @SuppressWarnings("unchecked")
+    public static <K, V> Map<K, V> writableMap(Put<K, V> put) {
+        if (put == null) {
+            throw new IllegalArgumentException("Put must not be null");
+        }
+        if (put instanceof Map) {
+            return (Map<K, V>) put;
+        }
+        return new WrappedPut<K, V>(put);
+    }
+
+}

Propchange: commons/proper/collections/branches/collections_jdk5_branch/src/java/org/apache/commons/collections/splitmap/SplitMapUtils.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/proper/collections/branches/collections_jdk5_branch/src/java/org/apache/commons/collections/splitmap/SplitMapUtils.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Added: commons/proper/collections/branches/collections_jdk5_branch/src/java/org/apache/commons/collections/splitmap/TransformedMap.java
URL: http://svn.apache.org/viewvc/commons/proper/collections/branches/collections_jdk5_branch/src/java/org/apache/commons/collections/splitmap/TransformedMap.java?rev=751894&view=auto
==============================================================================
--- commons/proper/collections/branches/collections_jdk5_branch/src/java/org/apache/commons/collections/splitmap/TransformedMap.java (added)
+++ commons/proper/collections/branches/collections_jdk5_branch/src/java/org/apache/commons/collections/splitmap/TransformedMap.java Mon Mar  9 22:48:07 2009
@@ -0,0 +1,208 @@
+/*
+ * 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.collections.splitmap;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.util.Map;
+
+import org.apache.commons.collections.Put;
+import org.apache.commons.collections.Transformer;
+import org.apache.commons.collections.map.LinkedMap;
+
+/**
+ * Decorates another <code>Map</code> to transform objects that are added.
+ * <p>
+ * The Map put methods and Map.Entry setValue method are affected by this class.
+ * Thus objects must be removed or searched for using their transformed form.
+ * For example, if the transformation converts Strings to Integers, you must use
+ * the Integer form to remove objects.
+ * <p>
+ * <strong>Note that TransformedMap 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. The simplest approach
+ * is to wrap this map using {@link java.util.Collections#synchronizedMap(Map)}.
+ * This class may throw exceptions when accessed by concurrent threads without
+ * synchronization.
+ * 
+ * @since Commons Collections 5
+ * @TODO fix version
+ * @version $Revision$ $Date$
+ * 
+ * @author Stephen Colebourne
+ * @author Matt Benson
+ */
+public class TransformedMap<J, K, U, V> extends AbstractIterableGetMapDecorator<K, V> implements
+        Put<J, U>, Serializable {
+
+    /** Serialization version */
+    private static final long serialVersionUID = 5966875321133456994L;
+
+    /** The decorated map */
+    private Map<K, V> decorated;
+    /** The transformer to use for the key */
+    private final Transformer<? super J, ? extends K> keyTransformer;
+    /** The transformer to use for the value */
+    private final Transformer<? super U, ? extends V> valueTransformer;
+
+    /**
+     * Factory method to create a transforming map.
+     * <p>
+     * If there are any elements already in the map being decorated, they are
+     * NOT transformed.
+     * 
+     * @param map the map to decorate, must not be null
+     * @param keyTransformer the transformer to use for key conversion, null
+     * means no transformation
+     * @param valueTransformer the transformer to use for value conversion, null
+     * means no transformation
+     * @throws IllegalArgumentException if map is null
+     */
+    public static <J, K, U, V> TransformedMap<J, K, U, V> decorate(Map<K, V> map,
+            Transformer<? super J, ? extends K> keyTransformer,
+            Transformer<? super U, ? extends V> valueTransformer) {
+        return new TransformedMap<J, K, U, V>(map, keyTransformer, valueTransformer);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Constructor that wraps (not copies).
+     * <p>
+     * If there are any elements already in the collection being decorated, they
+     * are NOT transformed.
+     * 
+     * @param map the map to decorate, must not be null
+     * @param keyTransformer the transformer to use for key conversion, null
+     * means no conversion
+     * @param valueTransformer the transformer to use for value conversion, null
+     * means no conversion
+     * @throws IllegalArgumentException if map is null
+     */
+    protected TransformedMap(Map<K, V> map, Transformer<? super J, ? extends K> keyTransformer,
+            Transformer<? super U, ? extends V> valueTransformer) {
+        super(map);
+        if (keyTransformer == null) {
+            throw new IllegalArgumentException("keyTransformer cannot be null");
+        }
+        this.keyTransformer = keyTransformer;
+        if (valueTransformer == null) {
+            throw new IllegalArgumentException("valueTransformer cannot be null");
+        }
+        this.valueTransformer = valueTransformer;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Write the map out using a custom routine.
+     * 
+     * @param out the output stream
+     * @throws IOException
+     */
+    private void writeObject(ObjectOutputStream out) throws IOException {
+        out.defaultWriteObject();
+        out.writeObject(decorated);
+    }
+
+    /**
+     * Read the map in using a custom routine.
+     * 
+     * @param in the input stream
+     * @throws IOException
+     * @throws ClassNotFoundException
+     * @since Commons Collections 3.1
+     */
+    @SuppressWarnings("unchecked")
+    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+        in.defaultReadObject();
+        decorated = (Map) in.readObject();
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Transforms a key.
+     * <p>
+     * The transformer itself may throw an exception if necessary.
+     * 
+     * @param object the object to transform
+     * @throws the transformed object
+     */
+    protected K transformKey(J object) {
+        return keyTransformer.transform(object);
+    }
+
+    /**
+     * Transforms a value.
+     * <p>
+     * The transformer itself may throw an exception if necessary.
+     * 
+     * @param object the object to transform
+     * @throws the transformed object
+     */
+    protected V transformValue(U object) {
+        return valueTransformer.transform(object);
+    }
+
+    /**
+     * Transforms a map.
+     * <p>
+     * The transformer itself may throw an exception if necessary.
+     * 
+     * @param map the map to transform
+     * @throws the transformed object
+     */
+    @SuppressWarnings("unchecked")
+    protected Map<K, V> transformMap(Map<? extends J, ? extends U> map) {
+        if (map.isEmpty()) {
+            return (Map<K, V>) map;
+        }
+        Map<K, V> result = new LinkedMap<K, V>(map.size());
+
+        for (Map.Entry<? extends J, ? extends U> entry : map.entrySet()) {
+            result.put((K) transformKey(entry.getKey()), transformValue(entry.getValue()));
+        }
+        return result;
+    }
+
+    /**
+     * Override to transform the value when using <code>setValue</code>.
+     * 
+     * @param value the value to transform
+     * @return the transformed value
+     */
+    protected V checkSetValue(U value) {
+        return valueTransformer.transform(value);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * {@inheritDoc}
+     */
+    public V put(J key, U value) {
+        return decorated().put(transformKey(key), transformValue(value));
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void putAll(Map<? extends J, ? extends U> mapToCopy) {
+        decorated().putAll(transformMap(mapToCopy));
+    }
+
+    
+}

Propchange: commons/proper/collections/branches/collections_jdk5_branch/src/java/org/apache/commons/collections/splitmap/TransformedMap.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/proper/collections/branches/collections_jdk5_branch/src/java/org/apache/commons/collections/splitmap/TransformedMap.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Added: commons/proper/collections/branches/collections_jdk5_branch/src/java/org/apache/commons/collections/splitmap/package.html
URL: http://svn.apache.org/viewvc/commons/proper/collections/branches/collections_jdk5_branch/src/java/org/apache/commons/collections/splitmap/package.html?rev=751894&view=auto
==============================================================================
--- commons/proper/collections/branches/collections_jdk5_branch/src/java/org/apache/commons/collections/splitmap/package.html (added)
+++ commons/proper/collections/branches/collections_jdk5_branch/src/java/org/apache/commons/collections/splitmap/package.html Mon Mar  9 22:48:07 2009
@@ -0,0 +1,39 @@
+<!-- $Id$ -->
+ <!--
+   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.
+  -->
+<BODY>
+<p>The "split map" concept is that of an object that implements
+the {@link org.apache.commons.collections.Put Put} and
+{@link org.apache.commons.collections.Get Get} interfaces,
+with <i>differing</i> generic types. This is like a pre-generics
+{@link java.util.Map Map} whose input key/value constraints are
+different than its output key/value constraints.  While it would
+be possible to declare a "split map" with matching input/output
+key/value constraints, this would be a {@link java.util.Map Map}
+and would therefore make little sense (any Commons Collections
+{@link java.util.Map Map} implementation will also implement
+{@link org.apache.commons.collections.Put Put} and
+{@link org.apache.commons.collections.Get Get} with matching
+generic parameters).
+
+<p>
+The following decorators are provided:
+<ul>
+<li>Transformed - transforms each element added
+</ul>
+</pre>
+</BODY>

Propchange: commons/proper/collections/branches/collections_jdk5_branch/src/java/org/apache/commons/collections/splitmap/package.html
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: commons/proper/collections/branches/collections_jdk5_branch/src/test/org/apache/commons/collections/TestAllPackages.java
URL: http://svn.apache.org/viewvc/commons/proper/collections/branches/collections_jdk5_branch/src/test/org/apache/commons/collections/TestAllPackages.java?rev=751894&r1=751893&r2=751894&view=diff
==============================================================================
--- commons/proper/collections/branches/collections_jdk5_branch/src/test/org/apache/commons/collections/TestAllPackages.java (original)
+++ commons/proper/collections/branches/collections_jdk5_branch/src/test/org/apache/commons/collections/TestAllPackages.java Mon Mar  9 22:48:07 2009
@@ -41,7 +41,8 @@
     org.apache.commons.collections.keyvalue.TestAll.class,
     org.apache.commons.collections.list.TestAll.class,
     org.apache.commons.collections.map.TestAll.class,
-    org.apache.commons.collections.set.TestAll.class
+    org.apache.commons.collections.set.TestAll.class,
+    org.apache.commons.collections.splitmap.TestAll.class
 })
 public class TestAllPackages {
 }

Added: commons/proper/collections/branches/collections_jdk5_branch/src/test/org/apache/commons/collections/splitmap/TestAll.java
URL: http://svn.apache.org/viewvc/commons/proper/collections/branches/collections_jdk5_branch/src/test/org/apache/commons/collections/splitmap/TestAll.java?rev=751894&view=auto
==============================================================================
--- commons/proper/collections/branches/collections_jdk5_branch/src/test/org/apache/commons/collections/splitmap/TestAll.java (added)
+++ commons/proper/collections/branches/collections_jdk5_branch/src/test/org/apache/commons/collections/splitmap/TestAll.java Mon Mar  9 22:48:07 2009
@@ -0,0 +1,42 @@
+/*
+ * 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.collections.splitmap;
+
+import junit.framework.TestCase;
+
+import org.junit.runner.RunWith;
+import org.junit.runners.Suite;
+import org.junit.runners.Suite.SuiteClasses;
+
+/**
+ * Entry point for tests.
+ *
+ * @since Commons Collections 5
+ * @TODO fix version
+ * @version $Revision$ $Date$
+ *
+ * @author Stephen Colebourne
+ * @author Stephen Kestle
+ * @author Matt Benson
+ */
+@RunWith(Suite.class)
+@SuiteClasses({
+    TestSplitMapUtils.class,
+	TestTransformedMap.class
+})
+public class TestAll extends TestCase {
+}

Propchange: commons/proper/collections/branches/collections_jdk5_branch/src/test/org/apache/commons/collections/splitmap/TestAll.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/proper/collections/branches/collections_jdk5_branch/src/test/org/apache/commons/collections/splitmap/TestAll.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Added: commons/proper/collections/branches/collections_jdk5_branch/src/test/org/apache/commons/collections/splitmap/TestSplitMapUtils.java
URL: http://svn.apache.org/viewvc/commons/proper/collections/branches/collections_jdk5_branch/src/test/org/apache/commons/collections/splitmap/TestSplitMapUtils.java?rev=751894&view=auto
==============================================================================
--- commons/proper/collections/branches/collections_jdk5_branch/src/test/org/apache/commons/collections/splitmap/TestSplitMapUtils.java (added)
+++ commons/proper/collections/branches/collections_jdk5_branch/src/test/org/apache/commons/collections/splitmap/TestSplitMapUtils.java Mon Mar  9 22:48:07 2009
@@ -0,0 +1,241 @@
+/*
+ * 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.collections.splitmap;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+import org.apache.commons.collections.BulkTest;
+import org.apache.commons.collections.IterableMap;
+import org.apache.commons.collections.MapIterator;
+import org.apache.commons.collections.Put;
+import org.apache.commons.collections.Transformer;
+import org.apache.commons.collections.Unmodifiable;
+import org.apache.commons.collections.functors.NOPTransformer;
+import org.apache.commons.collections.map.HashedMap;
+
+/**
+ * Tests for {@link TransformedMap}
+ *
+ * @since Commons Collections 5
+ * @TODO fix version
+ * @version $Revision$ $Date$
+ *
+ * @author Stephen Colebourne
+ * @author Matt Benson
+ */
+public class TestSplitMapUtils extends BulkTest {
+    private Map<String, Integer> backingMap;
+    private TransformedMap<String, String, String, Integer> transformedMap;
+
+    private Transformer<String, Integer> stringToInt = new Transformer<String, Integer>() {
+        public Integer transform(String input) {
+            return Integer.valueOf(input);
+        }
+    };
+
+    public TestSplitMapUtils(String testName) {
+        super(testName);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        backingMap = new HashMap<String, Integer>();
+        transformedMap = TransformedMap.decorate(backingMap, NOPTransformer.<String> getInstance(),
+                stringToInt);
+        for (int i = 0; i < 10; i++) {
+            transformedMap.put(String.valueOf(i), String.valueOf(i));
+        }
+    }
+
+    public static Test suite() {
+        return new TestSuite(TestSplitMapUtils.class);
+    }
+
+    public static void main(String args[]) {
+        String[] testCaseName = { TestSplitMapUtils.class.getName() };
+        junit.textui.TestRunner.main(testCaseName);
+    }
+
+    // -----------------------------------------------------------------------
+
+    public void testReadableMap() {
+        final IterableMap<String, Integer> map = SplitMapUtils.readableMap(transformedMap);
+
+        // basic
+        for (int i = 0; i < 10; i++) {
+            assertFalse(map.containsValue(String.valueOf(i)));
+            assertEquals(i, map.get(String.valueOf(i)).intValue());
+        }
+
+        // mapIterator
+        MapIterator<String, Integer> it = map.mapIterator();
+        while (it.hasNext()) {
+            String k = it.next();
+            assertEquals(k, it.getKey());
+            assertEquals(Integer.valueOf(k), it.getValue());
+        }
+
+        // unmodifiable
+        assertTrue(map instanceof Unmodifiable);
+
+        // check individual operations
+        int sz = map.size();
+
+        attemptPutOperation(new Runnable() {
+            public void run() {
+                map.clear();
+            }
+        });
+
+        assertEquals(sz, map.size());
+
+        attemptPutOperation(new Runnable() {
+            public void run() {
+                map.put("foo", 100);
+            }
+        });
+
+        final HashMap<String, Integer> m = new HashMap<String, Integer>();
+        m.put("foo", 100);
+        m.put("bar", 200);
+        m.put("baz", 300);
+        attemptPutOperation(new Runnable() {
+            public void run() {
+                map.putAll(m);
+            }
+        });
+
+        // equals, hashcode
+        IterableMap<String, Integer> other = SplitMapUtils.readableMap(transformedMap);
+        assertEquals(other, map);
+        assertEquals(other.hashCode(), map.hashCode());
+
+        // remove
+        for (int i = 0; i < 10; i++) {
+            assertEquals(i, map.remove(String.valueOf(i)).intValue());
+            assertEquals(--sz, map.size());
+        }
+        assertTrue(map.isEmpty());
+        assertSame(map, SplitMapUtils.readableMap(map));
+    }
+
+    public void testAlreadyReadableMap() {
+        HashedMap<String, Integer> hashedMap = new HashedMap<String, Integer>();
+        assertSame(hashedMap, SplitMapUtils.readableMap(hashedMap));
+    }
+
+    @SuppressWarnings("unchecked")
+    public void testWritableMap() {
+        final Map<String, String> map = SplitMapUtils.writableMap(transformedMap);
+        attemptGetOperation(new Runnable() {
+            public void run() {
+                map.get(null);
+            }
+        });
+        attemptGetOperation(new Runnable() {
+            public void run() {
+                map.entrySet();
+            }
+        });
+        attemptGetOperation(new Runnable() {
+            public void run() {
+                map.keySet();
+            }
+        });
+        attemptGetOperation(new Runnable() {
+            public void run() {
+                map.values();
+            }
+        });
+        attemptGetOperation(new Runnable() {
+            public void run() {
+                map.size();
+            }
+        });
+        attemptGetOperation(new Runnable() {
+            public void run() {
+                map.isEmpty();
+            }
+        });
+        attemptGetOperation(new Runnable() {
+            public void run() {
+                map.containsKey(null);
+            }
+        });
+        attemptGetOperation(new Runnable() {
+            public void run() {
+                map.containsValue(null);
+            }
+        });
+        attemptGetOperation(new Runnable() {
+            public void run() {
+                map.remove(null);
+            }
+        });
+
+        // equals, hashcode
+        Map<String, String> other = SplitMapUtils.writableMap(transformedMap);
+        assertEquals(other, map);
+        assertEquals(other.hashCode(), map.hashCode());
+
+        // put
+        int sz = backingMap.size();
+        assertFalse(backingMap.containsKey("foo"));
+        map.put("new", "66");
+        assertEquals(++sz, backingMap.size());
+
+        // putall
+        Map<String, String> more = new HashMap<String, String>();
+        more.put("foo", "77");
+        more.put("bar", "88");
+        more.put("baz", "99");
+        map.putAll(more);
+        assertEquals(sz + more.size(), backingMap.size());
+
+        // clear
+        map.clear();
+        assertTrue(backingMap.isEmpty());
+        assertSame(map, SplitMapUtils.writableMap((Put<String, String>) map));
+    }
+
+    public void testAlreadyWritableMap() {
+        HashedMap<String, String> hashedMap = new HashedMap<String, String>();
+        assertSame(hashedMap, SplitMapUtils.writableMap(hashedMap));
+    }
+
+    private void attemptGetOperation(Runnable r) {
+        attemptMapOperation("Put exposed as writable Map must not allow Get operations", r);
+    }
+
+    private void attemptPutOperation(Runnable r) {
+        attemptMapOperation("Get exposed as writable Map must not allow Put operations", r);
+    }
+
+    private void attemptMapOperation(String s, Runnable r) {
+        try {
+            r.run();
+            fail(s);
+        } catch (UnsupportedOperationException e) {
+        }
+    }
+
+}

Propchange: commons/proper/collections/branches/collections_jdk5_branch/src/test/org/apache/commons/collections/splitmap/TestSplitMapUtils.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/proper/collections/branches/collections_jdk5_branch/src/test/org/apache/commons/collections/splitmap/TestSplitMapUtils.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Added: commons/proper/collections/branches/collections_jdk5_branch/src/test/org/apache/commons/collections/splitmap/TestTransformedMap.java
URL: http://svn.apache.org/viewvc/commons/proper/collections/branches/collections_jdk5_branch/src/test/org/apache/commons/collections/splitmap/TestTransformedMap.java?rev=751894&view=auto
==============================================================================
--- commons/proper/collections/branches/collections_jdk5_branch/src/test/org/apache/commons/collections/splitmap/TestTransformedMap.java (added)
+++ commons/proper/collections/branches/collections_jdk5_branch/src/test/org/apache/commons/collections/splitmap/TestTransformedMap.java Mon Mar  9 22:48:07 2009
@@ -0,0 +1,134 @@
+/*
+ * 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.collections.splitmap;
+
+import java.math.BigInteger;
+import java.util.HashMap;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+import org.apache.commons.collections.BulkTest;
+import org.apache.commons.collections.MapIterator;
+import org.apache.commons.collections.Transformer;
+import org.apache.commons.collections.functors.NOPTransformer;
+
+/**
+ * Tests for {@link TransformedMap}
+ *
+ * @since Commons Collections 5
+ * @TODO fix version, add Serialization tests
+ * @version $Revision$ $Date$
+ *
+ * @author Stephen Colebourne
+ * @author Matt Benson
+ */
+public class TestTransformedMap extends BulkTest {
+
+    private Transformer<Integer, String> intToString = new Transformer<Integer, String>() {
+        public String transform(Integer input) {
+            return String.valueOf(input);
+        };
+    };
+
+    private Transformer<Object, Class<?>> objectToClass = new Transformer<Object, Class<?>>() {
+        public java.lang.Class<?> transform(Object input) {
+            return input == null ? null : input.getClass();
+        }
+    };
+
+    private Transformer<String, Integer> stringToInt = new Transformer<String, Integer>() {
+        public Integer transform(String input) {
+            return Integer.valueOf(input);
+        }
+    };
+
+    public TestTransformedMap(String testName) {
+        super(testName);
+    }
+
+    public static Test suite() {
+        return new TestSuite(TestTransformedMap.class);
+    }
+
+    public static void main(String args[]) {
+        String[] testCaseName = { TestTransformedMap.class.getName() };
+        junit.textui.TestRunner.main(testCaseName);
+    }
+
+    // -----------------------------------------------------------------------
+    @SuppressWarnings("unchecked")
+    public void testTransformedMap() {
+        TransformedMap<Integer, String, Object, Class<?>> map = TransformedMap.decorate(
+                new HashMap<String, Class<?>>(), intToString, objectToClass);
+
+        Integer[] k = new Integer[] { 0, 1, 2, 3, 4, 5, 6 };
+        Object[] v = new Object[] { "", new Object(), new HashMap(), 0, BigInteger.TEN, null,
+                new Object[0] };
+
+        assertEquals(0, map.size());
+        for (int i = 0; i < k.length; i++) {
+            map.put(k[i], v[i]);
+            assertEquals(i + 1, map.size());
+            assertTrue(map.containsKey(intToString.transform(k[i])));
+            assertFalse(map.containsKey(k[i]));
+            assertTrue(map.containsValue(objectToClass.transform(v[i])));
+            assertTrue(objectToClass.transform(v[i]) != v[i] ^ map.containsValue(v[i]));
+            assertEquals(objectToClass.transform(v[i]), map.get(intToString.transform(k[i])));
+        }
+
+        int sz = map.size();
+        assertEquals(null, map.remove(k[0]));
+        assertEquals(sz, map.size());
+        assertEquals(objectToClass.transform(v[0]), map.remove(intToString.transform(k[0])));
+        assertEquals(--sz, map.size());
+
+        TransformedMap<String, String, String, Integer> map2 = TransformedMap.decorate(
+                new HashMap<String, Integer>(), NOPTransformer.<String> getInstance(), stringToInt);
+        assertEquals(0, map2.size());
+        for (int i = 0; i < 6; i++) {
+            map2.put(String.valueOf(i), String.valueOf(i));
+            assertEquals(i + 1, map2.size());
+            assertTrue(map2.containsValue(i));
+            assertFalse(map2.containsValue(String.valueOf(i)));
+            assertTrue(map2.containsKey(String.valueOf(i)));
+            assertEquals(i, map2.get(String.valueOf(i)).intValue());
+        }
+
+        int sz2 = map2.size();
+        assertEquals(Integer.valueOf(0), map2.remove("0"));
+        assertEquals(--sz2, map2.size());
+    }
+
+    // -----------------------------------------------------------------------
+
+    public void testMapIterator() {
+        TransformedMap<String, String, String, Integer> map = TransformedMap.decorate(
+                new HashMap<String, Integer>(), NOPTransformer.<String> getInstance(), stringToInt);
+        assertEquals(0, map.size());
+        for (int i = 0; i < 6; i++) {
+            map.put(String.valueOf(i), String.valueOf(i));
+        }
+
+        for (MapIterator<String, Integer> it = map.mapIterator(); it.hasNext();) {
+            String k = it.next();
+            assertEquals(k, it.getKey());
+            assertEquals(map.get(k), it.getValue());
+        }
+    }
+
+}

Propchange: commons/proper/collections/branches/collections_jdk5_branch/src/test/org/apache/commons/collections/splitmap/TestTransformedMap.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/proper/collections/branches/collections_jdk5_branch/src/test/org/apache/commons/collections/splitmap/TestTransformedMap.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL