All Downloads are FREE. Search and download functionalities are using the official Maven repository.

clime.messadmin.providers.SoftHashMap Maven / Gradle / Ivy

Go to download

Notification system and Session administration for J2EE Web Applications

There is a newer version: 4.1.1
Show newest version
/**
 * Based on JDK 1.3.1 WeakHashMap
 */
package clime.messadmin.providers;

import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;

import java.util.AbstractMap;
import java.util.AbstractSet;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;

/**
 * A hashtable-based Map implementation with soft keys.
 * An entry in a SoftHashMap will automatically be removed when
 * its key is no longer in ordinary use.  More precisely, the presence of a
 * mapping for a given key will not prevent the key from being discarded by the
 * garbage collector, that is, made finalizable, finalized, and then reclaimed.
 * When a key has been discarded its entry is effectively removed from the map,
 * so this class behaves somewhat differently than other Map
 * implementations.
 *
 * 

Both null values and the null key are supported. This class has * performance characteristics similar to those of the HashMap * class, and has the same efficiency parameters of initial capacity * and load factor. * *

Like most collection classes, this class is not synchronized. A * synchronized SoftHashMap may be constructed using the * Collections.synchronizedMap method. * *

This class is intended primarily for use with key objects whose * equals methods test for object identity using the * == operator. Once such a key is discarded it can never be * recreated, so it is impossible to do a lookup of that key in a * SoftHashMap at some later time and be surprised that its entry * has been removed. This class will work perfectly well with key objects * whose equals methods are not based upon object identity, such * as String instances. With such recreatable key objects, * however, the automatic removal of SoftHashMap entries whose * keys have been discarded may prove to be confusing. * *

The behavior of the SoftHashMap class depends in part upon * the actions of the garbage collector, so several familiar (though not * required) Map invariants do not hold for this class. Because * the garbage collector may discard keys at any time, a * SoftHashMap may behave as though an unknown thread is silently * removing entries. In particular, even if you synchronize on a * SoftHashMap instance and invoke none of its mutator methods, it * is possible for the size method to return smaller values over * time, for the isEmpty method to return false and * then true, for the containsKey method to return * true and later false for a given key, for the * get method to return a value for a given key but later return * null, for the put method to return * null and the remove method to return * false for a key that previously appeared to be in the map, and * for successive examinations of the key set, the value set, and the entry set * to yield successively smaller numbers of elements. * *

Each key object in a SoftHashMap is stored indirectly as * the referent of a soft reference. Therefore a key will automatically be * removed only after the soft references to it, both inside and outside of the * map, have been cleared by the garbage collector. * *

Implementation note: The value objects in a * SoftHashMap are held by ordinary strong references. Thus care * should be taken to ensure that value objects do not strongly refer to their * own keys, either directly or indirectly, since that will prevent the keys * from being discarded. Note that a value object may refer indirectly to its * key via the SoftHashMap itself; that is, a value object may * strongly refer to some other key object whose associated value object, in * turn, strongly refers to the key of the first value object. One way * to deal with this is to wrap values themselves within * SoftReferences before * inserting, as in: m.put(key, new SoftReference(value)), * and then unwrapping upon each get. * * @version 1.13, 02/06/02 * @author Mark Reinhold, Cédrik LIME * @see java.util.HashMap * @see java.lang.ref.SoftReference */ class SoftHashMap extends AbstractMap implements Map { /* * A SoftHashMap is implemented as a HashMap that maps SoftKeys to values. * Because we don't have access to the innards of the HashMap, the various * query methods must create a temporary SoftKey every time a lookup is * done. Fortunately these are small, short-lived objects, so the added * allocation overhead is tolerable. */ static private class SoftKey extends SoftReference { /* * Hashcode of key, stored here since the key may be tossed by the GC */ private int hash; private SoftKey(Object k) { super(k); hash = k.hashCode(); } protected /*private*/ static SoftKey create(Object k) { if (k == null) return null; else return new SoftKey(k); } private SoftKey(Object k, ReferenceQueue q) { super(k, q); hash = k.hashCode(); } protected /*private*/ static SoftKey create(Object k, ReferenceQueue q) { if (k == null) return null; else return new SoftKey(k, q); } /* * A SoftKey is equal to another SoftKey iff they both refer to objects * that are, in turn, equal according to their own equals methods */ public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof SoftKey)) return false; Object t = this.get(); Object u = ((SoftKey) o).get(); if ((t == null) || (u == null)) return false; if (t == u) return true; return t.equals(u); } public int hashCode() { return hash; } } /* Hash table mapping SoftKeys to values */ protected /*private*/ Map hash; /* Reference queue for cleared SoftKeys */ private ReferenceQueue queue = new ReferenceQueue(); /* * Remove all invalidated entries from the map, that is, remove all entries * whose keys have been discarded. This method should be invoked once by * each public mutator in this class. We don't invoke this method in public * accessors because that can lead to surprising * ConcurrentModificationExceptions. */ protected /*private*/ void processQueue() { SoftKey sk; while ((sk = (SoftKey) queue.poll()) != null) { hash.remove(sk); } } /* -- Constructors -- */ /** * Constructs a new, empty SoftHashMap with the given * initial capacity and the given load factor. * * @param initialCapacity * The initial capacity of the SoftHashMap * * @param loadFactor * The load factor of the SoftHashMap * * @throws IllegalArgumentException * If the initial capacity is less than zero, or if the load * factor is nonpositive */ public SoftHashMap(int initialCapacity, float loadFactor) { hash = new HashMap(initialCapacity, loadFactor); } /** * Constructs a new, empty SoftHashMap with the given initial * capacity and the default load factor, which is 0.75. * * @param initialCapacity * The initial capacity of the SoftHashMap * * @throws IllegalArgumentException * If the initial capacity is less than zero */ public SoftHashMap(int initialCapacity) { hash = new HashMap(initialCapacity); } /** * Constructs a new, empty SoftHashMap with the default * initial capacity and the default load factor, which is 0.75. */ public SoftHashMap() { hash = new HashMap(); } /** * Constructs a new SoftHashMap with the same mappings as the * specified Map. The SoftHashMap is created with an * initial capacity of twice the number of mappings in the specified map * or 11 (whichever is greater), and a default load factor, which is * 0.75. * * @param t * the map whose mappings are to be placed in this map. * @since 1.3 */ public SoftHashMap(Map t) { this(Math.max(2 * t.size(), 11), 0.75f); putAll(t); } /* -- Simple queries -- */ /** * Returns the number of key-value mappings in this map. * Note: In contrast with most implementations of the * Map interface, the time required by this operation is * linear in the size of the map. */ public int size() { return entrySet().size(); } /** * Returns true if this map contains no key-value mappings. */ public boolean isEmpty() { return entrySet().isEmpty(); } /** * Returns true if this map contains a mapping for the * specified key. * * @param key * The key whose presence in this map is to be tested */ public boolean containsKey(Object key) { return hash.containsKey(SoftKey.create(key)); } /* -- Lookup and modification operations -- */ /** * Returns the value to which this map maps the specified key. * If this map does not contain a value for this key, then return * null. * * @param key * The key whose associated value, if any, is to be returned */ public Object get(Object key) { return hash.get(SoftKey.create(key)); } /** * Updates this map so that the given key maps to the given * value. If the map previously contained a mapping for * key then that mapping is replaced and the previous value * is returned. * * @param key * The key that is to be mapped to the given value * @param value * The value to which the given key is to be * mapped * * @return The previous value to which this key was mapped, or * null if if there was no mapping for the key */ public Object put(Object key, Object value) { processQueue(); return hash.put(SoftKey.create(key, queue), value); } /** * Removes the mapping for the given key from this map, if * present. * * @param key * The key whose mapping is to be removed * * @return The value to which this key was mapped, or null if * there was no mapping for the key */ public Object remove(Object key) { processQueue(); return hash.remove(SoftKey.create(key)); } /** * Removes all mappings from this map. */ public void clear() { processQueue(); hash.clear(); } /* -- Views -- */ /* Internal class for entries */ static private class Entry implements Map.Entry { private Map.Entry ent; /* * Strong reference to key, so that the GC will * leave it alone as long as this Entry exists */ private Object key; Entry(Map.Entry ent, Object key) { this.ent = ent; this.key = key; } public Object getKey() { return key; } public Object getValue() { return ent.getValue(); } public Object setValue(Object value) { return ent.setValue(value); } private static boolean valEquals(Object o1, Object o2) { return (o1 == null) ? (o2 == null) : o1.equals(o2); } public boolean equals(Object o) { if (!(o instanceof Map.Entry)) return false; Map.Entry e = (Map.Entry) o; return valEquals(key, e.getKey()) && valEquals(getValue(), e.getValue()); } public int hashCode() { Object v; return (((key == null) ? 0 : key.hashCode()) ^ (((v = getValue()) == null) ? 0 : v.hashCode())); } } /* Internal class for entry sets */ private class EntrySet extends AbstractSet { Set hashEntrySet = hash.entrySet(); public Iterator iterator() { return new Iterator() { Iterator hashIterator = hashEntrySet.iterator(); Entry next = null; public boolean hasNext() { while (hashIterator.hasNext()) { Map.Entry ent = (Map.Entry) hashIterator.next(); SoftKey sk = (SoftKey) ent.getKey(); Object k = null; if ((sk != null) && ((k = sk.get()) == null)) { /* Soft key has been cleared by GC */ continue; } next = new Entry(ent, k); return true; } return false; } public Object next() { if ((next == null) && !hasNext()) throw new NoSuchElementException(); Entry e = next; next = null; return e; } public void remove() { hashIterator.remove(); } }; } public boolean isEmpty() { return !(iterator().hasNext()); } public int size() { int j = 0; for (Iterator i = iterator(); i.hasNext(); i.next()) ++j; return j; } public boolean remove(Object o) { processQueue(); if (!(o instanceof Map.Entry)) return false; Map.Entry e = (Map.Entry) o; Object ev = e.getValue(); SoftKey wk = SoftKey.create(e.getKey()); Object hv = hash.get(wk); if ((hv == null) ? ((ev == null) && hash.containsKey(wk)) : hv.equals(ev)) { hash.remove(wk); return true; } return false; } public int hashCode() { int h = 0; for (Iterator i = hashEntrySet.iterator(); i.hasNext();) { Map.Entry ent = (Map.Entry) i.next(); SoftKey wk = (SoftKey) ent.getKey(); Object v; if (wk == null) continue; h += (wk.hashCode() ^ (((v = ent.getValue()) == null) ? 0 : v.hashCode())); } return h; } } private Set entrySet = null; /** * Returns a Set view of the mappings in this map. */ public Set entrySet() { if (entrySet == null) entrySet = new EntrySet(); return entrySet; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy