package org.hypergraphdb.util; import java.util.Collection; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.atomic.AtomicInteger; /** * * <p> * A variation on a map where values are managed like resources: a put * increments a reference count on an existing key-value entry and a remove * actually delete the entry when the reference count goes to zero. This * was implemented to help with the transactions framework. * </p> * * @author Borislav Iordanov * * @param <K> * @param <V> */ public class RefCountedMap<K, V> implements Map<K, V> { Map<K, Pair<V, AtomicInteger>> implementation = null; @SuppressWarnings("unchecked") public RefCountedMap(Map implementation) { if (implementation == null) this.implementation = new ConcurrentHashMap<K, Pair<V, AtomicInteger>>(); else this.implementation = (Map<K, Pair<V, AtomicInteger>>)implementation; } public void clear() { implementation.clear(); } public boolean containsKey(Object key) { return implementation.containsKey(key); } public boolean containsValue(Object value) { return implementation.containsValue(value); } public Set<java.util.Map.Entry<K, V>> entrySet() { throw new UnsupportedOperationException(); } public synchronized V get(Object key) { Pair<V, AtomicInteger> p = implementation.get(key); return p == null ? null : p.getFirst(); } public boolean isEmpty() { return implementation.isEmpty(); } public Set<K> keySet() { return implementation.keySet(); } @SuppressWarnings("unchecked") public synchronized V put(K key, V value) { Pair<V, AtomicInteger> p = null; if (implementation instanceof ConcurrentMap) { p = new Pair<V, AtomicInteger>(value, new AtomicInteger(0)); Pair<V, AtomicInteger> existing = (Pair<V, AtomicInteger>) ((ConcurrentMap)implementation).putIfAbsent(key, p); if (existing != null) p = existing; } else synchronized (implementation) { p = implementation.get(key); if (p == null) { p = new Pair<V, AtomicInteger>(value, new AtomicInteger(0)); implementation.put(key, p); } } int current = p.getSecond().incrementAndGet(); return current > 1 ? value : null; } public void putAll(Map<? extends K, ? extends V> m) { for (Map.Entry<? extends K, ? extends V> e : m.entrySet()) put(e.getKey(), e.getValue()); } public synchronized V remove(Object key) { Pair<V, AtomicInteger> p = implementation.get(key); if (p == null) return null; else if (p.getSecond().decrementAndGet() == 0) { implementation.remove(key); } return p.getFirst(); } public int size() { return implementation.size(); } public Collection<V> values() { throw new UnsupportedOperationException(); } public boolean equals(Object o) { return implementation.equals(o); } public int hashCode() { return implementation.hashCode(); } }