001: package de.schlund.pfixxml.util;
002:
003: import java.util.Collection;
004: import java.util.HashMap;
005: import java.util.HashSet;
006: import java.util.Iterator;
007: import java.util.LinkedHashMap;
008: import java.util.Map;
009: import java.util.Set;
010:
011: import org.apache.log4j.Logger;
012:
013: /**
014: * Created: Tue Jul 4 10:35:21 2006
015: *
016: * @author <a href="mailto:jtl@schlund.de">Jens Lautenbacher</a>
017: * @version 1.0
018: */
019:
020: public class CacheValueLRU<K, V> implements Map<K, V> {
021: private static Logger LOG = Logger.getLogger(CacheValueLRU.class);
022: CacheValueLRUStack valuestack;
023: HashMap<K, V> keytovalue;
024: HashMap<V, HashSet<K>> valuetokeys;
025:
026: public CacheValueLRU(int maxsize) {
027: keytovalue = new HashMap<K, V>();
028: valuetokeys = new HashMap<V, HashSet<K>>();
029: valuestack = new CacheValueLRUStack(maxsize);
030: }
031:
032: public synchronized int size() {
033: return keytovalue.size();
034: }
035:
036: public synchronized int sizeOfKeyEntriesForValue(V value) {
037: HashSet<K> keys = valuetokeys.get(value);
038: if (keys != null) {
039: return keys.size();
040: } else {
041: return -1;
042: }
043: }
044:
045: public synchronized int sizeOfUniqueValueEntries() {
046: assert (valuetokeys.size() == valuestack.size());
047: return valuetokeys.size();
048: }
049:
050: public synchronized boolean containsKey(Object key) {
051: return keytovalue.containsKey(key);
052: }
053:
054: public synchronized V get(Object key) {
055: V value = keytovalue.get(key);
056: if (value != null) {
057: // This is done to update the linked list order of the
058: // valuestack map.
059: valuestack.get(value);
060: }
061: LOG
062: .debug("\nLRU: getting for key: " + key
063: + "\n===================> LRU contains:\n"
064: + valuestack);
065: return value;
066: }
067:
068: public synchronized V put(K key, V value) {
069: HashSet<K> other_keys = null;
070: V old = keytovalue.put(key, value);
071: // we are only interested in the key for an LRU Stack
072: valuestack.put(value, null);
073: if (old != null) {
074: other_keys = valuetokeys.get(old);
075: other_keys.remove(key);
076: if (other_keys.isEmpty()) {
077: valuetokeys.remove(old);
078: valuestack.remove(old);
079: }
080: }
081:
082: HashSet<K> keyset = valuetokeys.get(value);
083: if (keyset == null) {
084: keyset = new HashSet<K>();
085: }
086: keyset.add(key);
087: valuetokeys.put(value, keyset);
088: LOG
089: .debug("\nLRU: putting for key: " + key
090: + "\n===================> LRU contains:\n"
091: + valuestack);
092: return old;
093: }
094:
095: public synchronized V remove(Object key) {
096: V value = keytovalue.get(key);
097: HashSet<K> keyset = valuetokeys.get(value);
098: if (keyset != null) {
099: keyset.remove(key);
100: if (keyset.isEmpty()) {
101: valuetokeys.remove(value);
102: valuestack.remove(value);
103: }
104: }
105: LOG
106: .debug("\nLRU: removing for key: " + key
107: + "\n===================> LRU contains:\n"
108: + valuestack);
109: return keytovalue.remove(key);
110: }
111:
112: public String toString() {
113: return valuestack.toString();
114: }
115:
116: private class CacheValueLRUStack extends LinkedHashMap<V, Object> {
117: private int maxsize = 1;
118:
119: public CacheValueLRUStack(int maxsize) {
120: super (5, 0.75f, true);
121: if (maxsize > 0)
122: this .maxsize = maxsize;
123: }
124:
125: @Override
126: protected boolean removeEldestEntry(Entry<V, Object> eldest) {
127: if (size() > maxsize) {
128: V value = eldest.getKey();
129: HashSet<K> keys = valuetokeys.get(value);
130: for (Iterator<K> iter = keys.iterator(); iter.hasNext();) {
131: K key = iter.next();
132: keytovalue.remove(key);
133: }
134: valuetokeys.remove(value);
135: return true;
136: }
137: return false;
138: }
139:
140: public String toString() {
141: StringBuffer buf = new StringBuffer();
142:
143: for (Iterator<Entry<V, Object>> iter = entrySet()
144: .iterator(); iter.hasNext();) {
145: Entry<V, Object> entry = iter.next();
146: V value = entry.getKey();
147: HashSet<K> keys = valuetokeys.get(value);
148: buf.append(value.hashCode() + " [");
149: if (keys != null) {
150: for (Iterator<K> iterator = keys.iterator(); iterator
151: .hasNext();) {
152: K key = iterator.next();
153: buf.append(key + " ");
154: }
155: }
156: buf.append("]\n");
157: }
158: return buf.toString();
159: }
160: }
161:
162: public synchronized void clear() {
163: keytovalue.clear();
164: valuetokeys.clear();
165: valuestack.clear();
166: }
167:
168: public boolean containsValue(Object value) {
169: return (valuetokeys.get(value) != null);
170: }
171:
172: public Set<java.util.Map.Entry<K, V>> entrySet() {
173: throw new IllegalStateException("Method not implemented");
174: }
175:
176: public boolean isEmpty() {
177: return keytovalue.isEmpty();
178: }
179:
180: public Set<K> keySet() {
181: return keytovalue.keySet();
182: }
183:
184: public void putAll(Map<? extends K, ? extends V> t) {
185: throw new IllegalStateException("Method not implemented");
186: }
187:
188: public Collection<V> values() {
189: return keytovalue.values();
190: }
191: }
|