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());
+ }
+}