001: /* Copyright 2001 The JA-SIG Collaborative. All rights reserved.
002: * See license distributed with this file and
003: * available online at http://www.uportal.org/license.html
004: */
005:
006: package org.jasig.portal.utils;
007:
008: import java.lang.ref.ReferenceQueue;
009: import java.lang.ref.SoftReference;
010: import java.util.AbstractMap;
011: import java.util.LinkedList;
012: import java.util.Set;
013:
014: import edu.emory.mathcs.backport.java.util.concurrent.ConcurrentHashMap;
015:
016: /**
017: * A HashMap implementation that uses soft references,
018: * leaving memory management up to the gc.
019: *
020: * @author Peter Kharchenko (thanks to Dr. Kabutz on whose article the code is based)
021: * @version $Revision: 36157 $
022: */
023: public class SoftHashMap extends AbstractMap {
024:
025: private final ConcurrentHashMap map = new ConcurrentHashMap();
026: private final LinkedList fifo = new LinkedList();
027: private final ReferenceQueue removeQueue = new ReferenceQueue();
028:
029: private int minSize;
030:
031: /**
032: * Construct a SoftHashMap
033: * @param minSize minimum number of objects to keep (approximate)
034: */
035: public SoftHashMap(int minSize) {
036: this .minSize = minSize;
037: }
038:
039: public SoftHashMap() {
040: this (10);
041: }
042:
043: public Object put(Object key, Object value) {
044: cleanMap();
045: if (key == null) {
046: return (null);
047: }
048: KeyReferencePair pair = new KeyReferencePair(value, key,
049: removeQueue);
050: // place the object into fifo
051: addToFIFO(value);
052: return map.put(key, pair);
053: }
054:
055: public Object get(Object key) {
056: if (key == null) {
057: return (null);
058: }
059: SoftReference soft_ref = (SoftReference) map.get(key);
060: if (soft_ref != null) {
061: Object obj = soft_ref.get();
062: if (obj == null) {
063: // object has been consumed by gc
064: map.remove(key);
065: } else {
066: // place the object into fifo
067: addToFIFO(obj);
068: }
069: return obj;
070: }
071: return null;
072: }
073:
074: public Object remove(Object key) {
075: cleanMap();
076: if (key == null) {
077: return (null);
078: }
079: SoftReference soft_ref = (SoftReference) map.remove(key);
080: if (soft_ref != null) {
081: return soft_ref.get();
082: } else {
083: return null;
084: }
085: }
086:
087: public int size() {
088: cleanMap();
089: return map.size();
090: }
091:
092: public void clear() {
093: synchronized (fifo) {
094: fifo.clear();
095: }
096: map.clear();
097: }
098:
099: public Set entrySet() {
100: throw new UnsupportedOperationException();
101: }
102:
103: /**
104: * An extension of a SoftReference that contains a key
105: * by which it was mapped.
106: */
107: private final static class KeyReferencePair extends SoftReference {
108: private final Object key;
109:
110: public KeyReferencePair(Object value, Object key,
111: ReferenceQueue queue) {
112: super (value, queue);
113: this .key = key;
114: }
115: }
116:
117: private void addToFIFO(Object o) {
118: synchronized (fifo) {
119: fifo.addFirst(o);
120: if (fifo.size() > minSize) {
121: fifo.removeLast();
122: }
123: }
124: }
125:
126: private void cleanMap() {
127: KeyReferencePair pair;
128: while ((pair = (KeyReferencePair) removeQueue.poll()) != null) {
129: map.remove(pair.key);
130: }
131: }
132: }
|