001: /*******************************************************************************
002: * Copyright (c) 2000, 2005 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.jdi.internal;
011:
012: import java.lang.ref.Reference;
013: import java.lang.ref.ReferenceQueue;
014: import java.lang.ref.SoftReference;
015: import java.util.ArrayList;
016: import java.util.Collection;
017: import java.util.Hashtable;
018: import java.util.Iterator;
019: import java.util.List;
020: import java.util.Map;
021:
022: /**
023: * This class is used to cache values.
024: * It uses soft references to store cached values. Once a value is garbage collected by the VM,
025: * the corresponding entry is removed from the cache on the next invocation of put() or get().
026: *
027: * Note that WeakHashMap can't be used for this purpose because in WeakHashMap
028: * soft references are only used for the keys, and values may not have 'strong' references
029: * to keys otherwise they will never be garbage collected.
030: *
031: */
032: public class ValueCache {
033: /**
034: * Map to store <key, Reference> pairs,
035: * where Reference is a soft reference to an Object.
036: */
037: private Map cacheTable = new Hashtable();
038: /**
039: * Map to store <Reference, key> pairs,
040: * to find the cacheTable-key of a garbage collected Reference.
041: */
042: private Map refTable = new Hashtable();
043:
044: /**
045: * The reference-queue that is registered with the soft references.
046: * The garbage collector will enqueue soft references that are garbage collected.
047: */
048: private ReferenceQueue refQueue = new ReferenceQueue();
049:
050: /**
051: * Clean up all entries from the table for which the values were garbage collected.
052: */
053: private void cleanup() {
054: Reference ref;
055: while ((ref = refQueue.poll()) != null) {
056: Object key = refTable.get(ref);
057: if (key != null)
058: cacheTable.remove(key);
059: refTable.remove(ref);
060: }
061: }
062:
063: /**
064: * Put a new entry in the cache under the given key.
065: */
066: public void put(Object key, Object value) {
067: cleanup();
068: SoftReference ref = new SoftReference(value, refQueue);
069: cacheTable.put(key, ref);
070: refTable.put(ref, key);
071: }
072:
073: /**
074: * Get entry from the cache.
075: * @return Returns value that is cached under the given key,
076: * or null of one of the following is true:
077: * - The value has not been cached.
078: * - The value had been cached but is garbage collected.
079: */
080: public Object get(Object key) {
081: cleanup();
082: Object value = null;
083: SoftReference ref = (SoftReference) cacheTable.get(key);
084: if (ref != null) {
085: value = ref.get();
086: }
087: return value;
088: }
089:
090: /**
091: * Returns a Collection view of the values contained in this cache.
092: */
093: public Collection values() {
094: cleanup();
095: List returnValues = new ArrayList();
096: synchronized (cacheTable) {
097: Iterator iter = cacheTable.values().iterator();
098: SoftReference ref;
099: Object value;
100: while (iter.hasNext()) {
101: ref = (SoftReference) iter.next();
102: value = ref.get();
103: if (value != null) {
104: returnValues.add(value);
105: }
106: }
107: }
108: return returnValues;
109: }
110:
111: /**
112: * Returns a Collection view of the values contained in this cache that have the same
113: * runtime class as the given Class.
114: */
115: public Collection valuesWithType(Class type) {
116: cleanup();
117: List returnValues = new ArrayList();
118: synchronized (cacheTable) {
119: Iterator iter = cacheTable.values().iterator();
120: SoftReference ref;
121: Object value;
122: while (iter.hasNext()) {
123: ref = (SoftReference) iter.next();
124: value = ref.get();
125: if (value != null && value.getClass().equals(type)) {
126: returnValues.add(value);
127: }
128: }
129: }
130: return returnValues;
131: }
132:
133: /**
134: * Removes the key and its corresponding value from this cache.
135: * @return Returns The value to which the key had been mapped in this hashtable,
136: * or null if the key did not have a mapping.
137: */
138: public Object remove(Object key) {
139: cleanup();
140: Object value = null;
141: SoftReference ref = (SoftReference) cacheTable.get(key);
142: if (ref != null) {
143: value = ref.get();
144: refTable.remove(ref);
145: }
146: cacheTable.remove(key);
147: return value;
148: }
149: }
|