You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by ra...@apache.org on 2010/05/28 04:35:34 UTC

svn commit: r949076 - in /qpid/trunk/qpid/java: ./ client/src/main/java/org/apache/qpid/client/message/ client/src/main/java/org/apache/qpid/collections/ client/src/main/java/org/apache/qpid/collections/keyvalue/

Author: rajith
Date: Fri May 28 02:35:34 2010
New Revision: 949076

URL: http://svn.apache.org/viewvc?rev=949076&view=rev
Log:
QPID-2629
Removed commons collections from the build deps.
Added the ReferenceMap and supported classes under a subpackage in qpid.
These classes were copied from the Commons Collections release tag 3_2.

Added:
    qpid/trunk/qpid/java/client/src/main/java/org/apache/qpid/collections/
    qpid/trunk/qpid/java/client/src/main/java/org/apache/qpid/collections/KeyValue.java
    qpid/trunk/qpid/java/client/src/main/java/org/apache/qpid/collections/ReferenceMap.java
    qpid/trunk/qpid/java/client/src/main/java/org/apache/qpid/collections/keyvalue/
    qpid/trunk/qpid/java/client/src/main/java/org/apache/qpid/collections/keyvalue/AbstractKeyValue.java
    qpid/trunk/qpid/java/client/src/main/java/org/apache/qpid/collections/keyvalue/AbstractMapEntry.java
    qpid/trunk/qpid/java/client/src/main/java/org/apache/qpid/collections/keyvalue/DefaultMapEntry.java
Modified:
    qpid/trunk/qpid/java/build.deps
    qpid/trunk/qpid/java/client/src/main/java/org/apache/qpid/client/message/AMQMessageDelegate_0_10.java
    qpid/trunk/qpid/java/client/src/main/java/org/apache/qpid/client/message/AMQMessageDelegate_0_8.java

Modified: qpid/trunk/qpid/java/build.deps
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/java/build.deps?rev=949076&r1=949075&r2=949076&view=diff
==============================================================================
--- qpid/trunk/qpid/java/build.deps (original)
+++ qpid/trunk/qpid/java/build.deps Fri May 28 02:35:34 2010
@@ -79,7 +79,7 @@ commons-configuration.libs = ${commons-b
   ${commons-codec} ${commons-lang} ${commons-collections} ${commons-configuration}
 
 common.libs=${slf4j-api} ${backport-util-concurrent} ${mina-core} ${mina-filter-ssl} 
-client.libs=${geronimo-jms} ${commons-collections}
+client.libs=${geronimo-jms}
 tools.libs=${commons-configuration.libs}
 broker.libs=${commons-cli} ${commons-logging} ${log4j} ${slf4j-log4j} \
     ${xalan} ${felix.libs} ${derby-db} ${commons-configuration.libs}

Modified: qpid/trunk/qpid/java/client/src/main/java/org/apache/qpid/client/message/AMQMessageDelegate_0_10.java
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/java/client/src/main/java/org/apache/qpid/client/message/AMQMessageDelegate_0_10.java?rev=949076&r1=949075&r2=949076&view=diff
==============================================================================
--- qpid/trunk/qpid/java/client/src/main/java/org/apache/qpid/client/message/AMQMessageDelegate_0_10.java (original)
+++ qpid/trunk/qpid/java/client/src/main/java/org/apache/qpid/client/message/AMQMessageDelegate_0_10.java Fri May 28 02:35:34 2010
@@ -35,7 +35,7 @@ import javax.jms.JMSException;
 import javax.jms.MessageFormatException;
 import javax.jms.MessageNotWriteableException;
 
-import org.apache.commons.collections.map.ReferenceMap;
+import org.apache.qpid.collections.ReferenceMap;
 import org.apache.qpid.client.AMQDestination;
 import org.apache.qpid.client.AMQSession;
 import org.apache.qpid.client.CustomJMSXProperty;
@@ -49,8 +49,6 @@ import org.apache.qpid.transport.Message
 import org.apache.qpid.transport.MessageDeliveryPriority;
 import org.apache.qpid.transport.MessageProperties;
 import org.apache.qpid.transport.ReplyTo;
-import org.apache.qpid.transport.codec.BBDecoder;
-import org.apache.qpid.transport.codec.BBEncoder;
 
 /**
  * This extends AbstractAMQMessageDelegate which contains common code between

Modified: qpid/trunk/qpid/java/client/src/main/java/org/apache/qpid/client/message/AMQMessageDelegate_0_8.java
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/java/client/src/main/java/org/apache/qpid/client/message/AMQMessageDelegate_0_8.java?rev=949076&r1=949075&r2=949076&view=diff
==============================================================================
--- qpid/trunk/qpid/java/client/src/main/java/org/apache/qpid/client/message/AMQMessageDelegate_0_8.java (original)
+++ qpid/trunk/qpid/java/client/src/main/java/org/apache/qpid/client/message/AMQMessageDelegate_0_8.java Fri May 28 02:35:34 2010
@@ -21,30 +21,28 @@
 
 package org.apache.qpid.client.message;
 
-import org.apache.commons.collections.map.ReferenceMap;
-import org.apache.mina.common.ByteBuffer;
-import org.apache.qpid.client.AMQSession;
-import org.apache.qpid.client.CustomJMSXProperty;
+import java.net.URISyntaxException;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.Map;
+import java.util.UUID;
+
+import javax.jms.Destination;
+import javax.jms.JMSException;
+import javax.jms.MessageNotWriteableException;
+
 import org.apache.qpid.client.AMQDestination;
 import org.apache.qpid.client.AMQQueue;
+import org.apache.qpid.client.AMQSession;
 import org.apache.qpid.client.AMQTopic;
-import org.apache.qpid.client.AMQUndefinedDestination;
+import org.apache.qpid.client.CustomJMSXProperty;
 import org.apache.qpid.client.JMSAMQException;
-import org.apache.qpid.framing.ContentHeaderProperties;
-import org.apache.qpid.framing.BasicContentHeaderProperties;
+import org.apache.qpid.collections.ReferenceMap;
 import org.apache.qpid.framing.AMQShortString;
-import org.apache.qpid.AMQException;
-import org.apache.qpid.url.BindingURL;
+import org.apache.qpid.framing.BasicContentHeaderProperties;
+import org.apache.qpid.framing.ContentHeaderProperties;
 import org.apache.qpid.url.AMQBindingURL;
-
-import javax.jms.Destination;
-import javax.jms.JMSException;
-import javax.jms.MessageNotWriteableException;
-import java.util.Map;
-import java.util.Collections;
-import java.util.Enumeration;
-import java.util.UUID;
-import java.net.URISyntaxException;
+import org.apache.qpid.url.BindingURL;
 
 public class AMQMessageDelegate_0_8 extends AbstractAMQMessageDelegate
 {

Added: qpid/trunk/qpid/java/client/src/main/java/org/apache/qpid/collections/KeyValue.java
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/java/client/src/main/java/org/apache/qpid/collections/KeyValue.java?rev=949076&view=auto
==============================================================================
--- qpid/trunk/qpid/java/client/src/main/java/org/apache/qpid/collections/KeyValue.java (added)
+++ qpid/trunk/qpid/java/client/src/main/java/org/apache/qpid/collections/KeyValue.java Fri May 28 02:35:34 2010
@@ -0,0 +1,46 @@
+/*
+ *  Copyright 2003-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.
+ */
+package org.apache.qpid.collections;
+
+/**
+ * Defines a simple key value pair.
+ * <p>
+ * A Map Entry has considerable additional semantics over and above a simple
+ * key-value pair. This interface defines the minimum key value, with just the
+ * two get methods.
+ *
+ * @since Commons Collections 3.0
+ * @version $Revision$ $Date$
+ * 
+ * @author Stephen Colebourne
+ */
+public interface KeyValue {
+
+    /**
+     * Gets the key from the pair.
+     *
+     * @return the key 
+     */
+    Object getKey();
+
+    /**
+     * Gets the value from the pair.
+     *
+     * @return the value
+     */
+    Object getValue();
+
+}
\ No newline at end of file

Added: qpid/trunk/qpid/java/client/src/main/java/org/apache/qpid/collections/ReferenceMap.java
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/java/client/src/main/java/org/apache/qpid/collections/ReferenceMap.java?rev=949076&view=auto
==============================================================================
--- qpid/trunk/qpid/java/client/src/main/java/org/apache/qpid/collections/ReferenceMap.java (added)
+++ qpid/trunk/qpid/java/client/src/main/java/org/apache/qpid/collections/ReferenceMap.java Fri May 28 02:35:34 2010
@@ -0,0 +1,957 @@
+/*
+ *  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.
+ */
+package org.apache.qpid.collections;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.lang.ref.Reference;
+import java.lang.ref.ReferenceQueue;
+import java.lang.ref.SoftReference;
+import java.lang.ref.WeakReference;
+import java.util.AbstractCollection;
+import java.util.AbstractMap;
+import java.util.AbstractSet;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.ConcurrentModificationException;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Set;
+
+import org.apache.qpid.collections.keyvalue.DefaultMapEntry;
+
+/**
+ *  Hash-based {@link Map} implementation that allows
+ *  mappings to be removed by the garbage collector.<p>
+ *
+ *  When you construct a <code>ReferenceMap</code>, you can 
+ *  specify what kind of references are used to store the
+ *  map's keys and values.  If non-hard references are 
+ *  used, then the garbage collector can remove mappings
+ *  if a key or value becomes unreachable, or if the 
+ *  JVM's memory is running low.  For information on how
+ *  the different reference types behave, see
+ *  {@link Reference}.<p>
+ *
+ *  Different types of references can be specified for keys
+ *  and values.  The keys can be configured to be weak but
+ *  the values hard, in which case this class will behave
+ *  like a <a href="http://java.sun.com/j2se/1.4/docs/api/java/util/WeakHashMap.html">
+ *  <code>WeakHashMap</code></a>.  However, you
+ *  can also specify hard keys and weak values, or any other
+ *  combination.  The default constructor uses hard keys
+ *  and soft values, providing a memory-sensitive cache.<p>
+ *
+ *  The algorithms used are basically the same as those
+ *  in {@link java.util.HashMap}.  In particular, you 
+ *  can specify a load factor and capacity to suit your
+ *  needs.  All optional {@link Map} operations are 
+ *  supported.<p>
+ *
+ *  However, this {@link Map} implementation does <I>not</I>
+ *  allow null elements.  Attempting to add a null key or
+ *  or a null value to the map will raise a 
+ *  <code>NullPointerException</code>.<p>
+ *
+ *  As usual, this implementation is not synchronized.  You
+ *  can use {@link java.util.Collections#synchronizedMap} to 
+ *  provide synchronized access to a <code>ReferenceMap</code>.
+ *
+ * @see java.lang.ref.Reference
+ * 
+ * @deprecated Moved to map subpackage. Due to be removed in v4.0.
+ * @since Commons Collections 2.1
+ * @version $Revision$ $Date$
+ * 
+ * @author Paul Jack
+ */
+public class ReferenceMap extends AbstractMap {
+
+    /**
+     *  For serialization.
+     */
+    private static final long serialVersionUID = -3370601314380922368L;
+
+
+    /**
+     *  Constant indicating that hard references should be used.
+     */
+    final public static int HARD = 0;
+
+
+    /**
+     *  Constant indicating that soft references should be used.
+     */
+    final public static int SOFT = 1;
+
+
+    /**
+     *  Constant indicating that weak references should be used.
+     */
+    final public static int WEAK = 2;
+
+
+    // --- serialized instance variables:
+
+
+    /**
+     *  The reference type for keys.  Must be HARD, SOFT, WEAK.
+     *  Note: I originally marked this field as final, but then this class
+     *   didn't compile under JDK1.2.2.
+     *  @serial
+     */
+    private int keyType;
+
+
+    /**
+     *  The reference type for values.  Must be HARD, SOFT, WEAK.
+     *  Note: I originally marked this field as final, but then this class
+     *   didn't compile under JDK1.2.2.
+     *  @serial
+     */
+    private int valueType;
+
+
+    /**
+     *  The threshold variable is calculated by multiplying
+     *  table.length and loadFactor.  
+     *  Note: I originally marked this field as final, but then this class
+     *   didn't compile under JDK1.2.2.
+     *  @serial
+     */
+    private float loadFactor;
+    
+    /**
+     * Should the value be automatically purged when the associated key has been collected?
+     */
+    private boolean purgeValues = false;
+
+
+    // -- Non-serialized instance variables
+
+    /**
+     *  ReferenceQueue used to eliminate stale mappings.
+     *  See purge.
+     */
+    private transient ReferenceQueue queue = new ReferenceQueue();
+
+
+    /**
+     *  The hash table.  Its length is always a power of two.  
+     */
+    private transient Entry[] table;
+
+
+    /**
+     *  Number of mappings in this map.
+     */
+    private transient int size;
+
+
+    /**
+     *  When size reaches threshold, the map is resized.  
+     *  See resize().
+     */
+    private transient int threshold;
+
+
+    /**
+     *  Number of times this map has been modified.
+     */
+    private transient volatile int modCount;
+
+
+    /**
+     *  Cached key set.  May be null if key set is never accessed.
+     */
+    private transient Set keySet;
+
+
+    /**
+     *  Cached entry set.  May be null if entry set is never accessed.
+     */
+    private transient Set entrySet;
+
+
+    /**
+     *  Cached values.  May be null if values() is never accessed.
+     */
+    private transient Collection values;
+
+
+    /**
+     *  Constructs a new <code>ReferenceMap</code> that will
+     *  use hard references to keys and soft references to values.
+     */
+    public ReferenceMap() {
+        this(HARD, SOFT);
+    }
+
+    /**
+     *  Constructs a new <code>ReferenceMap</code> that will
+     *  use the specified types of references.
+     *
+     *  @param keyType  the type of reference to use for keys;
+     *   must be {@link #HARD}, {@link #SOFT}, {@link #WEAK}
+     *  @param valueType  the type of reference to use for values;
+     *   must be {@link #HARD}, {@link #SOFT}, {@link #WEAK}
+     *  @param purgeValues should the value be automatically purged when the 
+     *   key is garbage collected 
+     */
+    public ReferenceMap(int keyType, int valueType, boolean purgeValues) {
+        this(keyType, valueType);
+        this.purgeValues = purgeValues;
+    }
+
+    /**
+     *  Constructs a new <code>ReferenceMap</code> that will
+     *  use the specified types of references.
+     *
+     *  @param keyType  the type of reference to use for keys;
+     *   must be {@link #HARD}, {@link #SOFT}, {@link #WEAK}
+     *  @param valueType  the type of reference to use for values;
+     *   must be {@link #HARD}, {@link #SOFT}, {@link #WEAK}
+     */
+    public ReferenceMap(int keyType, int valueType) {
+        this(keyType, valueType, 16, 0.75f);
+    }
+
+    /**
+     *  Constructs a new <code>ReferenceMap</code> with the
+     *  specified reference types, load factor and initial
+     *  capacity.
+     *
+     *  @param keyType  the type of reference to use for keys;
+     *   must be {@link #HARD}, {@link #SOFT}, {@link #WEAK}
+     *  @param valueType  the type of reference to use for values;
+     *   must be {@link #HARD}, {@link #SOFT}, {@link #WEAK}
+     *  @param capacity  the initial capacity for the map
+     *  @param loadFactor  the load factor for the map
+     *  @param purgeValues should the value be automatically purged when the 
+     *   key is garbage collected 
+     */
+    public ReferenceMap(
+                        int keyType, 
+                        int valueType, 
+                        int capacity, 
+                        float loadFactor, 
+                        boolean purgeValues) {
+        this(keyType, valueType, capacity, loadFactor);
+        this.purgeValues = purgeValues;
+    }
+
+    /**
+     *  Constructs a new <code>ReferenceMap</code> with the
+     *  specified reference types, load factor and initial
+     *  capacity.
+     *
+     *  @param keyType  the type of reference to use for keys;
+     *   must be {@link #HARD}, {@link #SOFT}, {@link #WEAK}
+     *  @param valueType  the type of reference to use for values;
+     *   must be {@link #HARD}, {@link #SOFT}, {@link #WEAK}
+     *  @param capacity  the initial capacity for the map
+     *  @param loadFactor  the load factor for the map
+     */
+    public ReferenceMap(int keyType, int valueType, int capacity, float loadFactor) {
+        super();
+
+        verify("keyType", keyType);
+        verify("valueType", valueType);
+
+        if (capacity <= 0) {
+            throw new IllegalArgumentException("capacity must be positive");
+        }
+        if ((loadFactor <= 0.0f) || (loadFactor >= 1.0f)) {
+            throw new IllegalArgumentException("Load factor must be greater than 0 and less than 1.");
+        }
+
+        this.keyType = keyType;
+        this.valueType = valueType;
+
+        int v = 1;
+        while (v < capacity) v *= 2;
+
+        this.table = new Entry[v];
+        this.loadFactor = loadFactor;
+        this.threshold = (int)(v * loadFactor);
+    }
+
+
+    // used by constructor
+    private static void verify(String name, int type) {
+        if ((type < HARD) || (type > WEAK)) {
+            throw new IllegalArgumentException(name + 
+               " must be HARD, SOFT, WEAK.");
+        }
+    }
+
+
+    /**
+     *  Writes this object to the given output stream.
+     *
+     *  @param out  the output stream to write to
+     *  @throws IOException  if the stream raises it
+     */
+    private void writeObject(ObjectOutputStream out) throws IOException {
+        out.defaultWriteObject();
+        out.writeInt(table.length);
+
+        // Have to use null-terminated list because size might shrink
+        // during iteration
+
+        for (Iterator iter = entrySet().iterator(); iter.hasNext();) {
+            Map.Entry entry = (Map.Entry)iter.next();
+            out.writeObject(entry.getKey());
+            out.writeObject(entry.getValue());
+        }
+        out.writeObject(null);
+    }
+
+
+    /**
+     *  Reads the contents of this object from the given input stream.
+     *
+     *  @param inp  the input stream to read from
+     *  @throws IOException  if the stream raises it
+     *  @throws ClassNotFoundException  if the stream raises it
+     */
+    private void readObject(ObjectInputStream inp) throws IOException, ClassNotFoundException {
+        inp.defaultReadObject();
+        table = new Entry[inp.readInt()];
+        threshold = (int)(table.length * loadFactor);
+        queue = new ReferenceQueue();
+        Object key = inp.readObject();
+        while (key != null) {
+            Object value = inp.readObject();
+            put(key, value);
+            key = inp.readObject();
+        }
+    }
+
+
+    /**
+     *  Constructs a reference of the given type to the given 
+     *  referent.  The reference is registered with the queue
+     *  for later purging.
+     *
+     *  @param type  HARD, SOFT or WEAK
+     *  @param referent  the object to refer to
+     *  @param hash  the hash code of the <I>key</I> of the mapping;
+     *    this number might be different from referent.hashCode() if
+     *    the referent represents a value and not a key
+     */
+    private Object toReference(int type, Object referent, int hash) {
+        switch (type) {
+            case HARD: return referent;
+            case SOFT: return new SoftRef(hash, referent, queue);
+            case WEAK: return new WeakRef(hash, referent, queue);
+            default: throw new Error();
+        }
+    }
+
+
+    /**
+     *  Returns the entry associated with the given key.
+     *
+     *  @param key  the key of the entry to look up
+     *  @return  the entry associated with that key, or null
+     *    if the key is not in this map
+     */
+    private Entry getEntry(Object key) {
+        if (key == null) return null;
+        int hash = key.hashCode();
+        int index = indexFor(hash);
+        for (Entry entry = table[index]; entry != null; entry = entry.next) {
+            if ((entry.hash == hash) && key.equals(entry.getKey())) {
+                return entry;
+            }
+        }
+        return null;
+    }
+
+
+    /**
+     *  Converts the given hash code into an index into the
+     *  hash table.
+     */
+    private int indexFor(int hash) {
+        // mix the bits to avoid bucket collisions...
+        hash += ~(hash << 15);
+        hash ^= (hash >>> 10);
+        hash += (hash << 3);
+        hash ^= (hash >>> 6);
+        hash += ~(hash << 11);
+        hash ^= (hash >>> 16);
+        return hash & (table.length - 1);
+    }
+
+
+
+    /**
+     *  Resizes this hash table by doubling its capacity.
+     *  This is an expensive operation, as entries must
+     *  be copied from the old smaller table to the new 
+     *  bigger table.
+     */
+    private void resize() {
+        Entry[] old = table;
+        table = new Entry[old.length * 2];
+
+        for (int i = 0; i < old.length; i++) {
+            Entry next = old[i];
+            while (next != null) {
+                Entry entry = next;
+                next = next.next;
+                int index = indexFor(entry.hash);
+                entry.next = table[index];
+                table[index] = entry;
+            }
+            old[i] = null;
+        }
+        threshold = (int)(table.length * loadFactor);
+    }
+
+
+
+    /**
+     * Purges stale mappings from this map.
+     * <p>
+     * Ordinarily, stale mappings are only removed during
+     * a write operation, although this method is called for both
+     * read and write operations to maintain a consistent state.
+     * <p>
+     * Note that this method is not synchronized!  Special
+     * care must be taken if, for instance, you want stale
+     * mappings to be removed on a periodic basis by some
+     * background thread.
+     */
+    private void purge() {
+        Reference ref = queue.poll();
+        while (ref != null) {
+            purge(ref);
+            ref = queue.poll();
+        }
+    }
+
+
+    private void purge(Reference ref) {
+        // The hashCode of the reference is the hashCode of the
+        // mapping key, even if the reference refers to the 
+        // mapping value...
+        int hash = ref.hashCode();
+        int index = indexFor(hash);
+        Entry previous = null;
+        Entry entry = table[index];
+        while (entry != null) {
+            if (entry.purge(ref)) {
+                if (previous == null) table[index] = entry.next;
+                else previous.next = entry.next;
+                this.size--;
+                return;
+            }
+            previous = entry;
+            entry = entry.next;
+        }
+
+    }
+
+
+    /**
+     *  Returns the size of this map.
+     *
+     *  @return  the size of this map
+     */
+    public int size() {
+        purge();
+        return size;
+    }
+
+
+    /**
+     *  Returns <code>true</code> if this map is empty.
+     *
+     *  @return <code>true</code> if this map is empty
+     */
+    public boolean isEmpty() {
+        purge();
+        return size == 0;
+    }
+
+
+    /**
+     *  Returns <code>true</code> if this map contains the given key.
+     *
+     *  @return true if the given key is in this map
+     */
+    public boolean containsKey(Object key) {
+        purge();
+        Entry entry = getEntry(key);
+        if (entry == null) return false;
+        return entry.getValue() != null;
+    }
+
+
+    /**
+     *  Returns the value associated with the given key, if any.
+     *
+     *  @return the value associated with the given key, or <code>null</code>
+     *   if the key maps to no value
+     */
+    public Object get(Object key) {
+        purge();
+        Entry entry = getEntry(key);
+        if (entry == null) return null;
+        return entry.getValue();
+    }
+
+
+    /**
+     *  Associates the given key with the given value.<p>
+     *  Neither the key nor the value may be null.
+     *
+     *  @param key  the key of the mapping
+     *  @param value  the value of the mapping
+     *  @return  the last value associated with that key, or 
+     *   null if no value was associated with the key
+     *  @throws NullPointerException if either the key or value
+     *   is null
+     */
+    public Object put(Object key, Object value) {
+        if (key == null) throw new NullPointerException("null keys not allowed");
+        if (value == null) throw new NullPointerException("null values not allowed");
+
+        purge();
+        if (size + 1 > threshold) resize();
+
+        int hash = key.hashCode();
+        int index = indexFor(hash);
+        Entry entry = table[index];
+        while (entry != null) {
+            if ((hash == entry.hash) && key.equals(entry.getKey())) {
+                Object result = entry.getValue();
+                entry.setValue(value);
+                return result;
+            }
+            entry = entry.next;
+        }
+        this.size++; 
+        modCount++;
+        key = toReference(keyType, key, hash);
+        value = toReference(valueType, value, hash);
+        table[index] = new Entry(key, hash, value, table[index]);
+        return null;
+    }
+
+
+    /**
+     *  Removes the key and its associated value from this map.
+     *
+     *  @param key  the key to remove
+     *  @return the value associated with that key, or null if
+     *   the key was not in the map
+     */
+    public Object remove(Object key) {
+        if (key == null) return null;
+        purge();
+        int hash = key.hashCode();
+        int index = indexFor(hash);
+        Entry previous = null;
+        Entry entry = table[index];
+        while (entry != null) {
+            if ((hash == entry.hash) && key.equals(entry.getKey())) {
+                if (previous == null) table[index] = entry.next;
+                else previous.next = entry.next;
+                this.size--;
+                modCount++;
+                return entry.getValue();
+            }
+            previous = entry;
+            entry = entry.next;
+        }
+        return null;
+    }
+
+
+    /**
+     *  Clears this map.
+     */
+    public void clear() {
+        Arrays.fill(table, null);
+        size = 0;
+        while (queue.poll() != null); // drain the queue
+    }
+
+
+    /**
+     *  Returns a set view of this map's entries.
+     *
+     *  @return a set view of this map's entries
+     */
+    public Set entrySet() {
+        if (entrySet != null) {
+            return entrySet;
+        } 
+        entrySet = new AbstractSet() {
+            public int size() {
+                return ReferenceMap.this.size();
+            }
+
+            public void clear() {
+                ReferenceMap.this.clear();
+            }
+
+            public boolean contains(Object o) {
+                if (o == null) return false;
+                if (!(o instanceof Map.Entry)) return false;
+                Map.Entry e = (Map.Entry)o;
+                Entry e2 = getEntry(e.getKey());
+                return (e2 != null) && e.equals(e2);
+            }
+
+            public boolean remove(Object o) {
+                boolean r = contains(o);
+                if (r) {
+                    Map.Entry e = (Map.Entry)o;
+                    ReferenceMap.this.remove(e.getKey());
+                }
+                return r;
+            }
+
+            public Iterator iterator() {
+                return new EntryIterator();
+            }
+
+            public Object[] toArray() {
+                return toArray(new Object[0]);
+            }
+
+            public Object[] toArray(Object[] arr) {
+                ArrayList list = new ArrayList();
+                Iterator iterator = iterator();
+                while (iterator.hasNext()) {
+                    Entry e = (Entry)iterator.next();
+                    list.add(new DefaultMapEntry(e.getKey(), e.getValue()));
+                }
+                return list.toArray(arr);
+            }
+        };
+        return entrySet;
+    }
+
+
+    /**
+     *  Returns a set view of this map's keys.
+     *
+     *  @return a set view of this map's keys
+     */
+    public Set keySet() {
+        if (keySet != null) return keySet;
+        keySet = new AbstractSet() {
+            public int size() {
+                return ReferenceMap.this.size();
+            }
+
+            public Iterator iterator() {
+                return new KeyIterator();
+            }
+
+            public boolean contains(Object o) {
+                return containsKey(o);
+            }
+
+
+            public boolean remove(Object o) {
+                Object r = ReferenceMap.this.remove(o);
+                return r != null;
+            }
+
+            public void clear() {
+                ReferenceMap.this.clear();
+            }
+
+            public Object[] toArray() {
+                return toArray(new Object[0]);
+            }
+
+            public Object[] toArray(Object[] array) {
+                Collection c = new ArrayList(size());
+                for (Iterator it = iterator(); it.hasNext(); ) {
+                    c.add(it.next());
+                }
+                return c.toArray(array);
+            }
+        };
+        return keySet;
+    }
+
+
+    /**
+     *  Returns a collection view of this map's values.
+     *
+     *  @return a collection view of this map's values.
+     */
+    public Collection values() {
+        if (values != null) return values;
+        values = new AbstractCollection()  {
+            public int size() {
+                return ReferenceMap.this.size();
+            }
+
+            public void clear() {
+                ReferenceMap.this.clear();
+            }
+
+            public Iterator iterator() {
+                return new ValueIterator();
+            }
+
+            public Object[] toArray() {
+                return toArray(new Object[0]);
+            }
+
+            public Object[] toArray(Object[] array) {
+                Collection c = new ArrayList(size());
+                for (Iterator it = iterator(); it.hasNext(); ) {
+                    c.add(it.next());
+                }
+                return c.toArray(array);
+            }
+        };
+        return values;
+    }
+
+
+    // If getKey() or getValue() returns null, it means
+    // the mapping is stale and should be removed.
+    private class Entry implements Map.Entry, KeyValue {
+
+        Object key;
+        Object value;
+        int hash;
+        Entry next;
+
+
+        public Entry(Object key, int hash, Object value, Entry next) {
+            this.key = key;
+            this.hash = hash;
+            this.value = value;
+            this.next = next;
+        }
+
+
+        public Object getKey() {
+            return (keyType > HARD) ? ((Reference)key).get() : key;
+        }
+
+
+        public Object getValue() {
+            return (valueType > HARD) ? ((Reference)value).get() : value;
+        }
+
+
+        public Object setValue(Object object) {
+            Object old = getValue();
+            if (valueType > HARD) ((Reference)value).clear();
+            value = toReference(valueType, object, hash);
+            return old;
+        }
+
+
+        public boolean equals(Object o) {
+            if (o == null) return false;
+            if (o == this) return true;
+            if (!(o instanceof Map.Entry)) return false;
+            
+            Map.Entry entry = (Map.Entry)o;
+            Object key = entry.getKey();
+            Object value = entry.getValue();
+            if ((key == null) || (value == null)) return false;
+            return key.equals(getKey()) && value.equals(getValue());
+        }
+
+
+        public int hashCode() {
+            Object v = getValue();
+            return hash ^ ((v == null) ? 0 : v.hashCode());
+        }
+
+
+        public String toString() {
+            return getKey() + "=" + getValue();
+        }
+
+
+        boolean purge(Reference ref) {
+            boolean r = (keyType > HARD) && (key == ref);
+            r = r || ((valueType > HARD) && (value == ref));
+            if (r) {
+                if (keyType > HARD) ((Reference)key).clear();
+                if (valueType > HARD) {
+                    ((Reference)value).clear();
+                } else if (purgeValues) {
+                    value = null;
+                }
+            }
+            return r;
+        }
+    }
+
+
+    private class EntryIterator implements Iterator {
+        // These fields keep track of where we are in the table.
+        int index;
+        Entry entry;
+        Entry previous;
+
+        // These Object fields provide hard references to the
+        // current and next entry; this assures that if hasNext()
+        // returns true, next() will actually return a valid element.
+        Object nextKey, nextValue;
+        Object currentKey, currentValue;
+
+        int expectedModCount;
+
+
+        public EntryIterator() {
+            index = (size() != 0 ? table.length : 0);
+            // have to do this here!  size() invocation above
+            // may have altered the modCount.
+            expectedModCount = modCount;
+        }
+
+
+        public boolean hasNext() {
+            checkMod();
+            while (nextNull()) {
+                Entry e = entry;
+                int i = index;
+                while ((e == null) && (i > 0)) {
+                    i--;
+                    e = table[i];
+                }
+                entry = e;
+                index = i;
+                if (e == null) {
+                    currentKey = null;
+                    currentValue = null;
+                    return false;
+                }
+                nextKey = e.getKey();
+                nextValue = e.getValue();
+                if (nextNull()) entry = entry.next;
+            }
+            return true;
+        }
+
+
+        private void checkMod() {
+            if (modCount != expectedModCount) {
+                throw new ConcurrentModificationException();
+            }
+        }
+
+
+        private boolean nextNull() {
+            return (nextKey == null) || (nextValue == null);
+        }
+
+        protected Entry nextEntry() {    
+            checkMod();
+            if (nextNull() && !hasNext()) throw new NoSuchElementException();
+            previous = entry;
+            entry = entry.next;
+            currentKey = nextKey;
+            currentValue = nextValue;
+            nextKey = null;
+            nextValue = null;
+            return previous;
+        }
+
+
+        public Object next() {
+            return nextEntry();
+        }
+
+
+        public void remove() {
+            checkMod();
+            if (previous == null) throw new IllegalStateException();
+            ReferenceMap.this.remove(currentKey);
+            previous = null;
+            currentKey = null;
+            currentValue = null;
+            expectedModCount = modCount;
+        }
+
+    }
+
+
+    private class ValueIterator extends EntryIterator {
+        public Object next() {
+            return nextEntry().getValue();
+        }
+    }
+
+
+    private class KeyIterator extends EntryIterator {
+        public Object next() {
+            return nextEntry().getKey();
+        }
+    }
+
+
+
+    // These two classes store the hashCode of the key of
+    // of the mapping, so that after they're dequeued a quick
+    // lookup of the bucket in the table can occur.
+
+
+    private static class SoftRef extends SoftReference {
+        private int hash;
+
+
+        public SoftRef(int hash, Object r, ReferenceQueue q) {
+            super(r, q);
+            this.hash = hash;
+        }
+
+
+        public int hashCode() {
+            return hash;
+        }
+    }
+
+
+    private static class WeakRef extends WeakReference {
+        private int hash;
+
+
+        public WeakRef(int hash, Object r, ReferenceQueue q) {
+            super(r, q);
+            this.hash = hash;
+        }
+
+
+        public int hashCode() {
+            return hash;
+        }
+    }
+
+
+}

Added: qpid/trunk/qpid/java/client/src/main/java/org/apache/qpid/collections/keyvalue/AbstractKeyValue.java
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/java/client/src/main/java/org/apache/qpid/collections/keyvalue/AbstractKeyValue.java?rev=949076&view=auto
==============================================================================
--- qpid/trunk/qpid/java/client/src/main/java/org/apache/qpid/collections/keyvalue/AbstractKeyValue.java (added)
+++ qpid/trunk/qpid/java/client/src/main/java/org/apache/qpid/collections/keyvalue/AbstractKeyValue.java Fri May 28 02:35:34 2010
@@ -0,0 +1,83 @@
+/*
+ *  Copyright 2003-2006 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.
+ */
+package org.apache.qpid.collections.keyvalue;
+
+import org.apache.qpid.collections.KeyValue;
+
+
+/**
+ * Abstract pair class to assist with creating <code>KeyValue</code>
+ * and {@link java.util.Map.Entry Map.Entry} implementations.
+ *
+ * @since Commons Collections 3.0
+ * @version $Revision$ $Date$
+ * 
+ * @author James Strachan
+ * @author Michael A. Smith
+ * @author Neil O'Toole
+ * @author Stephen Colebourne
+ */
+public abstract class AbstractKeyValue implements KeyValue {
+
+    /** The key */
+    protected Object key;
+    /** The value */
+    protected Object value;
+
+    /**
+     * Constructs a new pair with the specified key and given value.
+     *
+     * @param key  the key for the entry, may be null
+     * @param value  the value for the entry, may be null
+     */
+    protected AbstractKeyValue(Object key, Object value) {
+        super();
+        this.key = key;
+        this.value = value;
+    }
+
+    /**
+     * Gets the key from the pair.
+     *
+     * @return the key 
+     */
+    public Object getKey() {
+        return key;
+    }
+
+    /**
+     * Gets the value from the pair.
+     *
+     * @return the value
+     */
+    public Object getValue() {
+        return value;
+    }
+
+    /**
+     * Gets a debugging String view of the pair.
+     * 
+     * @return a String view of the entry
+     */
+    public String toString() {
+        return new StringBuffer()
+            .append(getKey())
+            .append('=')
+            .append(getValue())
+            .toString();
+    }
+
+}

Added: qpid/trunk/qpid/java/client/src/main/java/org/apache/qpid/collections/keyvalue/AbstractMapEntry.java
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/java/client/src/main/java/org/apache/qpid/collections/keyvalue/AbstractMapEntry.java?rev=949076&view=auto
==============================================================================
--- qpid/trunk/qpid/java/client/src/main/java/org/apache/qpid/collections/keyvalue/AbstractMapEntry.java (added)
+++ qpid/trunk/qpid/java/client/src/main/java/org/apache/qpid/collections/keyvalue/AbstractMapEntry.java Fri May 28 02:35:34 2010
@@ -0,0 +1,96 @@
+/*
+ *  Copyright 2003-2006 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.
+ */
+package org.apache.qpid.collections.keyvalue;
+
+import java.util.Map;
+
+import org.apache.qpid.collections.keyvalue.AbstractKeyValue;
+
+/**
+ * Abstract Pair class to assist with creating correct
+ * {@link java.util.Map.Entry Map.Entry} implementations.
+ *
+ * @since Commons Collections 3.0
+ * @version $Revision$ $Date$
+ * 
+ * @author James Strachan
+ * @author Michael A. Smith
+ * @author Neil O'Toole
+ * @author Stephen Colebourne
+ */
+public abstract class AbstractMapEntry extends AbstractKeyValue implements Map.Entry {
+
+    /**
+     * Constructs a new entry with the given key and given value.
+     *
+     * @param key  the key for the entry, may be null
+     * @param value  the value for the entry, may be null
+     */
+    protected AbstractMapEntry(Object key, Object value) {
+        super(key, value);
+    }
+
+    // Map.Entry interface
+    //-------------------------------------------------------------------------
+    /** 
+     * Sets the value stored in this <code>Map.Entry</code>.
+     * <p>
+     * This <code>Map.Entry</code> is not connected to a Map, so only the
+     * local data is changed.
+     *
+     * @param value  the new value
+     * @return the previous value
+     */
+    public Object setValue(Object value) {
+        Object answer = this.value;
+        this.value = value;
+        return answer;
+    }
+
+    /**
+     * Compares this <code>Map.Entry</code> with another <code>Map.Entry</code>.
+     * <p>
+     * Implemented per API documentation of {@link java.util.Map.Entry#equals(Object)}
+     * 
+     * @param obj  the object to compare to
+     * @return true if equal key and value
+     */
+    public boolean equals(Object obj) {
+        if (obj == this) {
+            return true;
+        }
+        if (obj instanceof Map.Entry == false) {
+            return false;
+        }
+        Map.Entry other = (Map.Entry) obj;
+        return
+            (getKey() == null ? other.getKey() == null : getKey().equals(other.getKey())) &&
+            (getValue() == null ? other.getValue() == null : getValue().equals(other.getValue()));
+    }
+
+    /**
+     * Gets a hashCode compatible with the equals method.
+     * <p>
+     * Implemented per API documentation of {@link java.util.Map.Entry#hashCode()}
+     * 
+     * @return a suitable hash code
+     */
+    public int hashCode() {
+        return (getKey() == null ? 0 : getKey().hashCode()) ^
+               (getValue() == null ? 0 : getValue().hashCode()); 
+    }
+
+}
\ No newline at end of file

Added: qpid/trunk/qpid/java/client/src/main/java/org/apache/qpid/collections/keyvalue/DefaultMapEntry.java
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/java/client/src/main/java/org/apache/qpid/collections/keyvalue/DefaultMapEntry.java?rev=949076&view=auto
==============================================================================
--- qpid/trunk/qpid/java/client/src/main/java/org/apache/qpid/collections/keyvalue/DefaultMapEntry.java (added)
+++ qpid/trunk/qpid/java/client/src/main/java/org/apache/qpid/collections/keyvalue/DefaultMapEntry.java Fri May 28 02:35:34 2010
@@ -0,0 +1,67 @@
+/*
+ *  Copyright 2001-2006 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.
+ */
+package org.apache.qpid.collections.keyvalue;
+
+import java.util.Map;
+
+import org.apache.qpid.collections.KeyValue;
+import org.apache.qpid.collections.keyvalue.AbstractMapEntry;
+
+/**
+ * A restricted implementation of {@link java.util.Map.Entry} that prevents
+ * the <code>Map.Entry</code> contract from being broken.
+ *
+ * @since Commons Collections 3.0
+ * @version $Revision$ $Date$
+ * 
+ * @author James Strachan
+ * @author Michael A. Smith
+ * @author Neil O'Toole
+ * @author Stephen Colebourne
+ */
+public final class DefaultMapEntry extends AbstractMapEntry {
+
+    /**
+     * Constructs a new entry with the specified key and given value.
+     *
+     * @param key  the key for the entry, may be null
+     * @param value  the value for the entry, may be null
+     */
+    public DefaultMapEntry(final Object key, final Object value) {
+        super(key, value);
+    }
+
+    /**
+     * Constructs a new entry from the specified <code>KeyValue</code>.
+     *
+     * @param pair  the pair to copy, must not be null
+     * @throws NullPointerException if the entry is null
+     */
+    public DefaultMapEntry(final KeyValue pair) {
+        super(pair.getKey(), pair.getValue());
+    }
+
+    /**
+     * Constructs a new entry from the specified <code>Map.Entry</code>.
+     *
+     * @param entry  the entry to copy, must not be null
+     * @throws NullPointerException if the entry is null
+     */
+    public DefaultMapEntry(final Map.Entry entry) {
+        super(entry.getKey(), entry.getValue());
+    }
+
+}
\ No newline at end of file



---------------------------------------------------------------------
Apache Qpid - AMQP Messaging Implementation
Project:      http://qpid.apache.org
Use/Interact: mailto:commits-subscribe@qpid.apache.org