Search TypeDescriptor cache first in meta(repId)
diff --git a/yoko-rmi-impl/src/main/java/org/apache/yoko/rmi/impl/TypeDescriptor.java b/yoko-rmi-impl/src/main/java/org/apache/yoko/rmi/impl/TypeDescriptor.java
index 16eef83..43d6b0b 100755
--- a/yoko-rmi-impl/src/main/java/org/apache/yoko/rmi/impl/TypeDescriptor.java
+++ b/yoko-rmi-impl/src/main/java/org/apache/yoko/rmi/impl/TypeDescriptor.java
@@ -39,6 +39,13 @@
         return _java_class;
     }
 
+    @Override
+    public String toString() {
+        return String.format("%s{class=\"%s\",repId=\"%s\",arrRepId=\"%s\"}",
+                this.getClass().getName(), getJavaClass(),
+                getRepositoryID(), getRepositoryIDForArray());
+    }
+
     protected TypeDescriptor(Class type, TypeRepository repository) {
         _java_class = type;
         String typeName = type.getName(); 
diff --git a/yoko-rmi-impl/src/main/java/org/apache/yoko/rmi/impl/TypeRepository.java b/yoko-rmi-impl/src/main/java/org/apache/yoko/rmi/impl/TypeRepository.java
index e146b85..38567e3 100755
--- a/yoko-rmi-impl/src/main/java/org/apache/yoko/rmi/impl/TypeRepository.java
+++ b/yoko-rmi-impl/src/main/java/org/apache/yoko/rmi/impl/TypeRepository.java
@@ -20,6 +20,8 @@
 
 import java.io.Externalizable;
 import java.io.Serializable;
+import java.lang.ref.Reference;
+import java.lang.ref.ReferenceQueue;
 import java.lang.ref.WeakReference;
 import java.lang.reflect.Method;
 import java.rmi.Remote;
@@ -27,9 +29,9 @@
 import java.sql.Date;
 import java.util.Arrays;
 import java.util.Collections;
+import java.util.HashSet;
 import java.util.List;
-import java.util.Map;
-import java.util.WeakHashMap;
+import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 import java.util.logging.Level;
@@ -45,31 +47,41 @@
 import org.omg.SendingContext.CodeBase;
 import org.omg.SendingContext.CodeBaseHelper;
 import org.omg.SendingContext.RunTime;
-
+import org.apache.yoko.rmi.util.SearchKey;
+import org.apache.yoko.rmi.util.WeakKey;
 
 public class TypeRepository {
-    static final Logger logger = Logger.getLogger(TypeRepository.class
-            .getName());
+    static final Logger logger = Logger.getLogger(TypeRepository.class.getName());
 
     org.omg.CORBA.ORB orb;
 
-    private static final class RepIdWeakMap {
-        private final Map<String, WeakReference<TypeDescriptor>> map = 
-                Collections.synchronizedMap(new WeakHashMap<String,WeakReference<TypeDescriptor>>());
+    private static final class TypeDescriptorCache {
+        private final ConcurrentMap<WeakKey<String>, WeakReference<TypeDescriptor>> map = new ConcurrentHashMap<>();
+        private final ReferenceQueue<String> staleKeys = new ReferenceQueue<>();
 
-        void put(String repId, TypeDescriptor desc) {
-            map.put(repId, new WeakReference<TypeDescriptor>(desc));
+        public TypeDescriptor get(String repId) {
+            cleanStaleKeys();
+            WeakReference<TypeDescriptor> ref = map.get(new SearchKey<String>(repId));
+            return (null == ref) ? null : ref.get();
         }
 
-        TypeDescriptor get(String repId) {
-            WeakReference<TypeDescriptor> value = map.get(repId);
-            return (value == null) ? null : value.get();
+        public void put(TypeDescriptor typeDesc) {
+            cleanStaleKeys();
+            final WeakReference<TypeDescriptor> value = new WeakReference<>(typeDesc);
+            map.putIfAbsent(new WeakKey<String>(typeDesc.getRepositoryID(), staleKeys), value);
+            map.putIfAbsent(new WeakKey<String>(typeDesc.getRepositoryIDForArray(), staleKeys), value);
+        }
+
+        private void cleanStaleKeys() {
+            for (Reference<? extends String> staleKey = staleKeys.poll(); staleKey != null; staleKey = staleKeys.poll()) {
+                map.remove(staleKey);
+            }
         }
     }
 
     private static final class LocalDescriptors extends ClassValue<TypeDescriptor> {
         private static final class Raw extends ClassValue<TypeDescriptor> {
-            private static final List<Class<?>> staticAnyTypes = 
+            private static final List<Class<?>> staticAnyTypes =
                     Collections.unmodifiableList(
                             Arrays.asList(Object.class, Externalizable.class, Serializable.class, Remote.class));
 
@@ -178,9 +190,9 @@
         }
 
         private final Raw rawValues;
-        private final RepIdWeakMap repIdDescriptors;
+        private final TypeDescriptorCache repIdDescriptors;
 
-        LocalDescriptors(TypeRepository repo, RepIdWeakMap repIdDescriptors) {
+        LocalDescriptors(TypeRepository repo, TypeDescriptorCache repIdDescriptors) {
             rawValues = new Raw(repo);
             this.repIdDescriptors = repIdDescriptors;
         }
@@ -188,7 +200,7 @@
         protected TypeDescriptor computeValue(Class<?> type) {
             final TypeDescriptor desc = rawValues.get(type);
             desc.init();
-            repIdDescriptors.put(desc.getRepositoryID(), desc);
+            repIdDescriptors.put(desc);
             return desc;
         }
 
@@ -199,24 +211,31 @@
         @Override
         protected ConcurrentMap<String,ValueDescriptor> computeValue(
                 Class<?> type) {
-            return new ConcurrentHashMap<String,ValueDescriptor>();
+            return new ConcurrentHashMap<String,ValueDescriptor>(1);
         }
     }
 
-    private final RepIdWeakMap repIdDescriptors;
+    private final TypeDescriptorCache repIdDescriptors;
     private final LocalDescriptors localDescriptors;
     private final FvdRepIdDescriptorMaps fvdDescMaps = new FvdRepIdDescriptorMaps();
     private final ConcurrentMap<String,ValueDescriptor> noTypeDescMap = new ConcurrentHashMap<String,ValueDescriptor>();
 
+    private static final Set<Class<?>> initTypes;
+
+    static {
+        initTypes = createClassSet(Object.class, String.class, ClassDesc.class, Date.class,
+                Externalizable.class, Serializable.class, Remote.class);
+    }
+
+    private static Set<Class<?>> createClassSet(Class<?>...types) {
+        return Collections.unmodifiableSet(new HashSet<>(Arrays.asList(types)));
+    }
+
     public TypeRepository(org.omg.CORBA.ORB orb) {
         this.orb = orb;
-        repIdDescriptors = new RepIdWeakMap();
+        repIdDescriptors = new TypeDescriptorCache();
         localDescriptors = new LocalDescriptors(this, repIdDescriptors);
 
-        Class<?>[] initTypes = {
-                Object.class, String.class, ClassDesc.class, Date.class, 
-                Externalizable.class, Serializable.class, Remote.class };
-
         for (Class<?> type: initTypes) {
             localDescriptors.get(type);
         }
@@ -260,9 +279,20 @@
     }
 
     public TypeDescriptor getDescriptor(Class<?> type) {
-        logger.fine("Requesting type descriptor for class " + type.getName());
+        if (logger.isLoggable(Level.FINE))
+            logger.fine(String.format("Requesting type descriptor for class \"%s\"", type.getName()));
         final TypeDescriptor desc = localDescriptors.get(type);
-        logger.fine("Class " + type.getName() + " resolves to " + desc.getClass().getName());
+        if (logger.isLoggable(Level.FINE))
+            logger.fine(String.format("Class \"%s\" resolves to %s", type.getName(), desc));
+        return desc;
+    }
+
+    public TypeDescriptor getDescriptor(String repId) {
+        if (logger.isLoggable(Level.FINE))
+            logger.fine(String.format("Requesting type descriptor for repId \"%s\"", repId));
+        final TypeDescriptor desc = repIdDescriptors.get(repId);
+        if (logger.isLoggable(Level.FINE))
+            logger.fine(String.format("RepId \"%s\" resolves to %s", repId, desc));
         return desc;
     }
 
@@ -320,10 +350,10 @@
 
         ValueDescriptor newDesc = new FVDValueDescriptor(fvd, clz, this, repid, super_desc);
         ConcurrentMap<String, ValueDescriptor> remoteDescMap = (clz == null) ? noTypeDescMap : fvdDescMaps.get(clz);
-        clzdesc = remoteDescMap.putIfAbsent(repid, newDesc);
+        clzdesc = remoteDescMap.putIfAbsent(newDesc.getRepositoryID(), newDesc);
         if (clzdesc == null) {
             clzdesc = newDesc;
-            repIdDescriptors.put(repid, clzdesc);
+            repIdDescriptors.put(clzdesc);
         }
 
         return clzdesc;
@@ -409,14 +439,14 @@
             int len = current.length();
             match = false;
 
-            for (ByteString reservedPostfixe : reservedPostfixes) {
-                if (current.endsWith(reservedPostfixe)) {
+            for (ByteString reservedPostfix : reservedPostfixes) {
+                if (current.endsWith(reservedPostfix)) {
                     ByteBuffer buf = new ByteBuffer();
                     buf.append('_');
                     buf.append(result);
                     result = buf.toByteString();
 
-                    int resultLen = reservedPostfixe.length();
+                    int resultLen = reservedPostfix.length();
                     if (len > resultLen)
                         current = current.substring(0, len - resultLen);
                     else
@@ -432,16 +462,12 @@
         return name;
     }
 
-    static final java.util.Set<ByteString> keyWords = new java.util.HashSet<ByteString>();
-
-    static final ByteString[] reservedPostfixes = new ByteString[] {
-        new ByteString("Helper"), new ByteString("Holder"),
-        new ByteString("Operations"), new ByteString("POA"),
-        new ByteString("POATie"), new ByteString("Package"),
-        new ByteString("ValueFactory") };
+    private static final Set<ByteString> keyWords;
+    private static final Set<ByteString> reservedPostfixes;
 
     static {
-        String[] words = { "abstract", "boolean", "break", "byte", "case",
+        keyWords = createByteStringSet(
+                "abstract", "boolean", "break", "byte", "case",
                 "catch", "char", "class", "clone", "const", "continue",
                 "default", "do", "double", "else", "equals", "extends",
                 "false", "final", "finalize", "finally", "float", "for",
@@ -451,11 +477,17 @@
                 "protected", "public", "return", "short", "static", "super",
                 "switch", "synchronized", "this", "throw", "throws",
                 "toString", "transient", "true", "try", "void", "volatile",
-                "wait", "while" };
+                "wait", "while");
+        reservedPostfixes = createByteStringSet(
+                "Helper", "Holder", "Operations", "POA", "POATie", "Package", "ValueFactory");
+    }
 
+    private static Set<ByteString> createByteStringSet(String...words) {
+        final Set<ByteString> set = new HashSet<>(words.length);
         for (String word : words) {
-            keyWords.add(new ByteString(word));
+            set.add(new ByteString(word));
         }
+        return Collections.unmodifiableSet(set);
     }
 
 }
diff --git a/yoko-rmi-impl/src/main/java/org/apache/yoko/rmi/impl/ValueHandlerImpl.java b/yoko-rmi-impl/src/main/java/org/apache/yoko/rmi/impl/ValueHandlerImpl.java
index 01189c9..01f70fe 100755
--- a/yoko-rmi-impl/src/main/java/org/apache/yoko/rmi/impl/ValueHandlerImpl.java
+++ b/yoko-rmi-impl/src/main/java/org/apache/yoko/rmi/impl/ValueHandlerImpl.java
@@ -50,6 +50,10 @@
         return (ValueDescriptor) getRepository().getDescriptor(clz);
     }
 
+    private ValueDescriptor desc(String repId) {
+        return (ValueDescriptor)getRepository().getDescriptor(repId);
+    }
+
     private ValueDescriptor desc(Class clz, String repid, RunTime runtime) {
         try {
             return (ValueDescriptor) getRepository().getDescriptor(clz, repid,
@@ -263,25 +267,23 @@
         return result;
     }
 
-    FullValueDescription meta(String id) {
+    FullValueDescription meta(String repId) {
+        if (logger.isLoggable(Level.FINER))
+            logger.finer(String.format("meta \"%s\"", repId));
         try {
-            // System.out.println ("ValueHandlerImpl::meta "+id);
+            ValueDescriptor desc = desc(repId);
+            if (null == desc) {
+                Class clz = getClassFromRepositoryID(repId);
 
-            Class clz = getClassFromRepositoryID(id);
+                if (clz == null) {
+                    logger.warning("class not found: " + repId);
+                    throw new org.omg.CORBA.MARSHAL(0x4f4d0001,
+                            CompletionStatus.COMPLETED_MAYBE);
+                }
 
-            if (clz == null) {
-                logger.warning("class not found: " + id);
-                throw new org.omg.CORBA.MARSHAL(0x4f4d0001,
-                        CompletionStatus.COMPLETED_MAYBE);
+                desc = desc(clz);
             }
 
-            if (logger.isLoggable(Level.FINER)) {
-                logger.finer("meta " + id);
-            }
-
-            ValueDescriptor desc = (ValueDescriptor) getRepository()
-                    .getDescriptor(clz);
-
             return desc.getFullValueDescription();
         } catch (Throwable ex) {
             logger.log(Level.WARNING, "exception in meta", ex);
diff --git a/yoko-rmi-impl/src/main/java/org/apache/yoko/rmi/util/DynamicHashMap.java b/yoko-rmi-impl/src/main/java/org/apache/yoko/rmi/util/DynamicHashMap.java
deleted file mode 100755
index 945fe73..0000000
--- a/yoko-rmi-impl/src/main/java/org/apache/yoko/rmi/util/DynamicHashMap.java
+++ /dev/null
@@ -1,261 +0,0 @@
-/**
-*
-* Licensed to the Apache Software Foundation (ASF) under one or more
-*  contributor license agreements.  See the NOTICE file distributed with
-*  this work for additional information regarding copyright ownership.
-*  The ASF licenses this file to You under the Apache License, Version 2.0
-*  (the "License"); you may not use this file except in compliance with
-*  the License.  You may obtain a copy of the License at
-*
-*     http://www.apache.org/licenses/LICENSE-2.0
-*
-*  Unless required by applicable law or agreed to in writing, software
-*  distributed under the License is distributed on an "AS IS" BASIS,
-*  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-*  See the License for the specific language governing permissions and
-*  limitations under the License.
-*/ 
-
-package org.apache.yoko.rmi.util;
-
-import java.util.Iterator;
-import java.util.Map;
-import java.util.NoSuchElementException;
-
-/**
- * Class <code>DynamicHashMap</code> is a generic dynamic hash map.
- */
-public class DynamicHashMap extends GenericMap implements Map {
-    class Entry extends GenericMap.Entry {
-        Entry next;
-
-        int hash;
-
-        Object key;
-
-        Object value;
-
-        Entry(int hash, Object key, Object value, Entry next) {
-            this.hash = hash;
-            this.key = key;
-            this.value = value;
-            this.next = next;
-        }
-
-        public Object getKey() {
-            return key;
-        }
-
-        public Object getValue() {
-            return value;
-        }
-
-        public Object setValue(Object value) {
-            Object result = this.value;
-            this.value = value;
-            return result;
-        }
-
-        boolean sameKey(int hash, Object key) {
-            return this.hash == hash && keyEquals(this.key, key);
-        }
-    }
-
-    /** the hash index */
-    private Entry[] table;
-
-    /** the current range for table. */
-    private int range;
-
-    private float ratio;
-
-    /** translate hash code bucket to index */
-    private int index(int hash) {
-        return (hash & 0x7ffffff) % range;
-    }
-
-    /** the default and only constructor */
-    public DynamicHashMap() {
-        clear();
-    }
-
-    public void clear() {
-        range = 3;
-        size = 0;
-        ratio = 0.75F;
-        table = new Entry[range];
-    }
-
-    /** return the element with the given key */
-    public Object get(Object key) {
-        int hash = keyHash(key);
-        return get(hash, key);
-    }
-
-    public Object get(int hash, Object key) {
-        int idx = index(hash);
-
-        for (Entry ent = table[idx]; ent != null; ent = ent.next) {
-            if (ent.sameKey(hash, key))
-                return ent.value;
-        }
-
-        return null;
-    }
-
-    /** return the element with the given key */
-    public boolean containsKey(Object key) {
-        int hash = keyHash(key);
-        return containsKey(hash, key);
-    }
-
-    public boolean containsKey(int hash, Object key) {
-        int idx = index(hash);
-
-        for (Entry ent = table[idx]; ent != null; ent = ent.next) {
-            if (ent.sameKey(hash, key))
-                return true;
-        }
-
-        return false;
-    }
-
-    public Object put(Object key, Object value) {
-        int hash = keyHash(key);
-        return put(hash, key, value);
-    }
-
-    public Object put(int hash, Object key, Object value) {
-        int idx = index(hash);
-
-        for (Entry ent = table[idx]; ent != null; ent = ent.next) {
-            if (ent.sameKey(hash, key)) {
-                return ent.setValue(value);
-            }
-        }
-
-        if (1.0F * size / range > ratio) {
-            grow();
-            idx = index(hash);
-        }
-
-        table[idx] = new Entry(hash, key, value, table[idx]);
-
-        size += 1;
-
-        return null;
-    }
-
-    public Object remove(Object key) {
-        int hash = keyHash(key);
-        return remove(hash, key);
-    }
-
-    public Object remove(int hash, Object key) {
-        int idx = index(hash);
-
-        Entry entry = table[idx];
-        if (entry != null) {
-
-            if (entry.sameKey(hash, key)) {
-                table[idx] = entry.next;
-                size -= 1;
-                return entry.getValue();
-
-            } else {
-                Entry ahead = entry.next;
-
-                while (ahead != null) {
-                    if (ahead.sameKey(hash, key)) {
-                        entry.next = ahead.next;
-                        size -= 1;
-                        return ahead.getValue();
-                    }
-
-                    entry = ahead;
-                    ahead = ahead.next;
-                }
-            }
-        }
-
-        // it was not found at all!
-        return null;
-    }
-
-    private void grow() {
-        int old_range = range;
-        Entry[] old_table = table;
-
-        range = old_range * 2 + 1;
-        table = new Entry[range];
-
-        for (int i = 0; i < old_range; i++) {
-            Entry entry = old_table[i];
-
-            while (entry != null) {
-                Entry ahead = entry.next;
-                int idx = index(entry.hash);
-                entry.next = table[idx];
-                table[idx] = entry;
-                entry = ahead;
-            }
-        }
-    }
-
-    final class EntryIterator implements Iterator {
-        int idx;
-
-        Entry entry;
-
-        EntryIterator() {
-            idx = 0;
-            entry = table[0];
-            locateNext();
-        }
-
-        private void locateNext() {
-            // we reached the end of a list
-            while (entry == null) {
-                // goto next bucket
-                idx += 1;
-                if (idx == range) {
-                    // we reached the end
-                    return;
-                }
-
-                // entry is the first element of this bucket
-                entry = table[idx];
-            }
-        }
-
-        public boolean hasNext() {
-            return (entry != null);
-        }
-
-        public Object next() {
-            Object result = entry;
-
-            if (result == null) {
-                throw new NoSuchElementException();
-            } else {
-                entry = entry.next;
-                locateNext();
-                return result;
-            }
-        }
-
-        public void remove() {
-            Entry remove = entry;
-
-            entry = entry.next;
-            locateNext();
-
-            DynamicHashMap.this.remove(remove.key);
-        }
-    }
-
-    protected Iterator entryIterator() {
-        return new EntryIterator();
-    }
-
-}
diff --git a/yoko-rmi-impl/src/main/java/org/apache/yoko/rmi/util/GenericMap.java b/yoko-rmi-impl/src/main/java/org/apache/yoko/rmi/util/GenericMap.java
deleted file mode 100755
index b97648b..0000000
--- a/yoko-rmi-impl/src/main/java/org/apache/yoko/rmi/util/GenericMap.java
+++ /dev/null
@@ -1,257 +0,0 @@
-/**
-*
-* Licensed to the Apache Software Foundation (ASF) under one or more
-*  contributor license agreements.  See the NOTICE file distributed with
-*  this work for additional information regarding copyright ownership.
-*  The ASF licenses this file to You under the Apache License, Version 2.0
-*  (the "License"); you may not use this file except in compliance with
-*  the License.  You may obtain a copy of the License at
-*
-*     http://www.apache.org/licenses/LICENSE-2.0
-*
-*  Unless required by applicable law or agreed to in writing, software
-*  distributed under the License is distributed on an "AS IS" BASIS,
-*  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-*  See the License for the specific language governing permissions and
-*  limitations under the License.
-*/ 
-
-package org.apache.yoko.rmi.util;
-
-import java.util.AbstractCollection;
-import java.util.AbstractSet;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Set;
-
-abstract class GenericMap implements Map {
-    protected int size;
-
-    public int size() {
-        return size;
-    }
-
-    public boolean isEmpty() {
-        return size() == 0;
-    }
-
-    protected int keyHash(Object key) {
-        if (key == null)
-            return 0;
-        else
-            return key.hashCode();
-    }
-
-    protected boolean keyEquals(Object key1, Object key2) {
-        if (key1 == null)
-            return key2 == null;
-        else
-            return key1.equals(key2);
-    }
-
-    protected int valueHash(Object value) {
-        if (value == null)
-            return 0;
-        else
-            return value.hashCode();
-    }
-
-    protected boolean valueEquals(Object value1, Object value2) {
-        if (value1 == null)
-            return value2 == null;
-        else
-            return value1.equals(value2);
-    }
-
-    abstract class Entry implements Map.Entry {
-        public int hashCode() {
-            return keyHash(getKey()) ^ valueHash(getValue());
-        }
-
-        public boolean equals(Object other) {
-            if (other instanceof Map.Entry) {
-                Map.Entry ent = (Map.Entry) other;
-                return keyEquals(getKey(), ent.getKey())
-                        && valueEquals(getValue(), ent.getValue());
-            } else {
-                return false;
-            }
-        }
-
-    }
-
-    public void putAll(Map other) {
-        if (other == this)
-            return;
-
-        Iterator it = other.entrySet().iterator();
-        while (it.hasNext()) {
-            Map.Entry entry = (Map.Entry) it.next();
-            put(entry.getKey(), entry.getValue());
-        }
-    }
-
-    protected abstract Iterator entryIterator();
-
-    protected Iterator keyIterator() {
-        return new KeyIterator();
-    }
-
-    protected Iterator valueIterator() {
-        return new ValueIterator();
-    }
-
-    abstract class KeyOrValueIterator implements Iterator {
-        Iterator iter = entryIterator();
-
-        public boolean hasNext() {
-            return iter.hasNext();
-        }
-
-        protected Map.Entry nextEntry() {
-            return (Map.Entry) iter.next();
-        }
-
-        public void remove() {
-            throw new UnsupportedOperationException();
-        }
-
-    }
-
-    class KeyIterator extends KeyOrValueIterator {
-        public Object next() {
-            return nextEntry().getKey();
-        }
-    }
-
-    class ValueIterator extends KeyOrValueIterator {
-        public Object next() {
-            return nextEntry().getValue();
-        }
-    }
-
-    /**
-     * I don't quite understand why we need to replace this method from
-     * AbstractCollection, but it has been observed that toArray returns the
-     * *reverse* order of elements. --Kresten
-     */
-
-    private static Object[] toArray(Object[] arr, int size, Iterator it) {
-        Object[] out = null;
-
-        if (arr != null && arr.length >= size) {
-            out = arr;
-        } else if (arr == null) {
-            out = new Object[size];
-        } else {
-            out = (Object[]) java.lang.reflect.Array.newInstance(arr.getClass()
-                    .getComponentType(), size);
-        }
-
-        for (int i = 0; i < size; i++) {
-            out[i] = it.next();
-        }
-
-        if (out.length > size)
-            out[size] = null;
-
-        return out;
-    }
-
-    public Collection values() {
-        return new AbstractCollection() {
-            public Iterator iterator() {
-                return valueIterator();
-            }
-
-            public int size() {
-                return GenericMap.this.size();
-            }
-
-            public Object[] toArray(Object[] arr) {
-                return GenericMap.toArray(arr, size(), iterator());
-            }
-        };
-    }
-
-    public Set keySet() {
-        return new AbstractSet() {
-            public Iterator iterator() {
-                return keyIterator();
-            }
-
-            public int size() {
-                return GenericMap.this.size();
-            }
-
-            public Object[] toArray(Object[] arr) {
-                return GenericMap.toArray(arr, size(), iterator());
-            }
-        };
-    }
-
-    public int hashCode() {
-        int code = 0;
-        Iterator it = entryIterator();
-        while (it.hasNext()) {
-            code += it.next().hashCode();
-        }
-        return code;
-    }
-
-    public boolean equals(Object other) {
-        if (other instanceof Map) {
-            Map map = (Map) other;
-
-            if (map.size() != size())
-                return false;
-
-            Iterator it = entryIterator();
-            while (it.hasNext()) {
-                Entry ent = (Entry) it.next();
-                Object key = ent.getKey();
-                Object val = ent.getValue();
-
-                if (map.containsKey(key)) {
-                    Object otherVal = map.get(key);
-                    if (!valueEquals(val, otherVal))
-                        return false;
-                }
-            }
-            return true;
-        }
-        return false;
-    }
-
-    public Set entrySet() {
-        return new AbstractSet() {
-            public Iterator iterator() {
-                return entryIterator();
-            }
-
-            public int size() {
-                return size;
-            }
-
-            public Object[] toArray(Object[] arr) {
-                return GenericMap.toArray(arr, size(), iterator());
-            }
-        };
-    }
-
-    /** return the element with the given key */
-    public boolean containsValue(Object value) {
-        Iterator it = valueIterator();
-        while (it.hasNext()) {
-            if (valueEquals(value, it.next()))
-                return true;
-        }
-        return false;
-    }
-
-    public boolean containsKey(Object key) {
-        return get(key) != null;
-    }
-
-}
diff --git a/yoko-rmi-impl/src/main/java/org/apache/yoko/rmi/util/Key.java b/yoko-rmi-impl/src/main/java/org/apache/yoko/rmi/util/Key.java
new file mode 100644
index 0000000..456e9b0
--- /dev/null
+++ b/yoko-rmi-impl/src/main/java/org/apache/yoko/rmi/util/Key.java
@@ -0,0 +1,5 @@
+package org.apache.yoko.rmi.util;
+
+interface Key<T> {
+    T get();
+}
diff --git a/yoko-rmi-impl/src/main/java/org/apache/yoko/rmi/util/SearchKey.java b/yoko-rmi-impl/src/main/java/org/apache/yoko/rmi/util/SearchKey.java
new file mode 100644
index 0000000..1661182
--- /dev/null
+++ b/yoko-rmi-impl/src/main/java/org/apache/yoko/rmi/util/SearchKey.java
@@ -0,0 +1,28 @@
+package org.apache.yoko.rmi.util;
+
+public class SearchKey<T> implements Key<T> {
+    private final T value;
+    private final int hash;
+
+    public SearchKey(T value) {
+        this.value = value;
+        hash = value.hashCode();
+    }
+
+    @Override
+    public T get() {
+        return value;
+    }
+
+    @Override
+    public int hashCode() {
+        return hash;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (!!!(o instanceof Key)) return false;
+        return value.equals(((Key)o).get());
+    }
+}
diff --git a/yoko-rmi-impl/src/main/java/org/apache/yoko/rmi/util/WeakKey.java b/yoko-rmi-impl/src/main/java/org/apache/yoko/rmi/util/WeakKey.java
new file mode 100644
index 0000000..07f66bd
--- /dev/null
+++ b/yoko-rmi-impl/src/main/java/org/apache/yoko/rmi/util/WeakKey.java
@@ -0,0 +1,27 @@
+package org.apache.yoko.rmi.util;
+
+import java.lang.ref.ReferenceQueue;
+import java.lang.ref.WeakReference;
+
+public class WeakKey<T> extends WeakReference<T> implements Key<T> {
+    private final int hash;
+
+    public WeakKey(T r, ReferenceQueue<T> q) {
+        super(r, q);
+        hash = r.hashCode();
+    }
+
+    @Override
+    public int hashCode() {
+        return hash;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (!!!(o instanceof Key)) return false;
+        final Object otherKey = ((Key<?>)o).get();
+        if (null == otherKey) return false;
+        return otherKey.equals(get());
+    }
+}