001: /*
002: * *****************************************************************************
003: * Copyright (C) 2006, International Business Machines Corporation and others.
004: * All Rights Reserved.
005: * *****************************************************************************
006: */
007: package com.ibm.icu.impl;
008:
009: import java.lang.ref.ReferenceQueue;
010: import java.lang.ref.SoftReference;
011:
012: /**
013: * LRU hash map using softly-referenced values
014: */
015: public class SoftCache {
016: private final LRUMap map;
017: private final ReferenceQueue queue = new ReferenceQueue();
018:
019: /**
020: * Construct a SoftCache with default cache size
021: */
022: public SoftCache() {
023: map = new LRUMap();
024: }
025:
026: /**
027: * Construct a SoftCache with sepcified initial/max size
028: *
029: * @param initialSize the initial cache size
030: * @param maxSize the maximum cache size
031: */
032: public SoftCache(int initialSize, int maxSize) {
033: map = new LRUMap(initialSize, maxSize);
034: }
035:
036: /**
037: * Put an object to the cache
038: * @param key key object
039: * @param value value object
040: * @return the value previously put, null when not matching key is found.
041: */
042: public synchronized Object put(Object key, Object value) {
043: if (key == null || value == null) {
044: throw new IllegalArgumentException(
045: "Key and value must not be null");
046: }
047: ProcessQueue();
048: Object obj = map.put(key, new SoftMapEntry(key, value, queue));
049: return obj;
050: }
051:
052: /**
053: * Get an object from the cache
054: * @param key key object
055: * @return the cached value, null when the value is not found.
056: */
057: public synchronized Object get(Object key) {
058: ProcessQueue();
059: Object obj = null;
060: SoftMapEntry entry = (SoftMapEntry) map.get(key);
061: if (entry != null) {
062: obj = entry.get();
063: if (obj == null) {
064: // It is unlikely to enter into this block, because
065: // ProcessQueue() should already remove a map entrie
066: // whose value was deleted by the garbage collactor.
067: map.remove(key);
068: }
069: }
070: return obj;
071: }
072:
073: /**
074: * Remove a cache entry from the cache
075: * @param key key object
076: * @return the value of cache entry which is removed from this cache,
077: * or null when no entry for the key was no found.
078: */
079: public synchronized Object remove(Object key) {
080: return map.remove(key);
081: }
082:
083: /**
084: * Clear the cache contents
085: */
086: public synchronized void clear() {
087: ProcessQueue();
088: map.clear();
089: }
090:
091: /**
092: * Remove map entries which no longer have value
093: */
094: private void ProcessQueue() {
095: while (true) {
096: SoftMapEntry entry = (SoftMapEntry) queue.poll();
097: if (entry == null) {
098: break;
099: }
100: map.remove(entry.getKey());
101: }
102: }
103:
104: /**
105: * A class for map entry with soft-referenced value
106: */
107: private static class SoftMapEntry extends SoftReference {
108: private final Object key;
109:
110: private SoftMapEntry(Object key, Object value,
111: ReferenceQueue queue) {
112: super (value, queue);
113: this .key = key;
114: }
115:
116: private Object getKey() {
117: return key;
118: }
119: }
120: }
|