001: /**
002: * Licensed to the Apache Software Foundation (ASF) under one
003: * or more contributor license agreements. See the NOTICE file
004: * distributed with this work for additional information
005: * regarding copyright ownership. The ASF licenses this file
006: * to you under the Apache License, Version 2.0 (the
007: * "License"); you may not use this file except in compliance
008: * with the License. You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing,
013: * software distributed under the License is distributed on an
014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015: * KIND, either express or implied. See the License for the
016: * specific language governing permissions and limitations
017: * under the License.
018: */package org.apache.cxf.common.util;
019:
020: import java.util.Collection;
021: import java.util.Map;
022: import java.util.Set;
023: import java.util.WeakHashMap;
024:
025: /**
026: * Implements a useful caching map. It weakly references the keys,
027: * but strongly references the data. It works a log like the WeakHashMap,
028: * in that when the keys are garbage collected, the data is removed from
029: * the map.
030: *
031: * The main difference is that keys used for lookups don't have to be "=="
032: * the same to maintain the data in the cache. Basically, lookups in this
033: * map use a ".equals" compare, but the keys are then stored with a "=="
034: * compare so if the original key is garbage collected, the other keys that
035: * may reference the data keep the data in the cache.
036: *
037: * <b>
038: * Note that this implementation is not synchronized.
039: * </b>
040: */
041: public class CacheMap<K, V> implements Map<K, V> {
042: Map<K, V> mainDataMap = new WeakHashMap<K, V>();
043: Map<K, V> extraKeyMap = new WeakIdentityHashMap<K, V>();
044:
045: public void clear() {
046: mainDataMap.clear();
047: extraKeyMap.clear();
048: }
049:
050: private void updateMainDataMap() {
051: //if the singleton in the mainDataMap has been garbage collected,
052: //we'll copy another version of it from the extraKeyMap
053: for (K o : extraKeyMap.keySet()) {
054: if (!mainDataMap.containsKey(o)) {
055: mainDataMap.put(o, extraKeyMap.get(o));
056: }
057: }
058: }
059:
060: public boolean containsKey(Object key) {
061: if (!mainDataMap.containsKey(key)) {
062: updateMainDataMap();
063: return mainDataMap.containsKey(key);
064: }
065: return true;
066: }
067:
068: public boolean containsValue(Object value) {
069: return mainDataMap.containsValue(value)
070: || extraKeyMap.containsValue(value);
071: }
072:
073: public Set<java.util.Map.Entry<K, V>> entrySet() {
074: updateMainDataMap();
075: return mainDataMap.entrySet();
076: }
077:
078: @SuppressWarnings("unchecked")
079: public V get(Object key) {
080: V val = mainDataMap.get(key);
081: if (val == null) {
082: updateMainDataMap();
083: val = mainDataMap.get(val);
084: }
085: if (val != null) {
086: extraKeyMap.put((K) key, val);
087: }
088: return val;
089: }
090:
091: public boolean isEmpty() {
092: return mainDataMap.isEmpty() && extraKeyMap.isEmpty();
093: }
094:
095: public Set<K> keySet() {
096: updateMainDataMap();
097: return mainDataMap.keySet();
098: }
099:
100: public V put(K key, V value) {
101: V v = mainDataMap.put(key, value);
102: V v2 = extraKeyMap.put(key, value);
103: return v == null ? v2 : v;
104: }
105:
106: public void putAll(Map<? extends K, ? extends V> t) {
107: for (Map.Entry<? extends K, ? extends V> ent : t.entrySet()) {
108: put(ent.getKey(), ent.getValue());
109: }
110: }
111:
112: public V remove(Object key) {
113: V v = mainDataMap.remove(key);
114: V v2 = extraKeyMap.remove(key);
115: return v == null ? v2 : v;
116: }
117:
118: public int size() {
119: updateMainDataMap();
120: return mainDataMap.size();
121: }
122:
123: public Collection<V> values() {
124: updateMainDataMap();
125: return mainDataMap.values();
126: }
127:
128: public String toString() {
129: updateMainDataMap();
130: return mainDataMap.toString();
131: }
132: }
|