package org.exist.fluent; import java.lang.ref.WeakReference; import java.util.*; class WeakMultiValueHashMap<K,V> { /** * Number of puts between dead reference sweep requests. */ private static final int SWEEP_COUNT = 100; private final Map<K, Collection<WeakReference<V>>> map = new HashMap<K, Collection<WeakReference<V>>>(); private int putCounter; public synchronized void put(K key, V value) { Collection<WeakReference<V>> list = map.get(key); if (list == null) { list = new LinkedList<WeakReference<V>>(); map.put(key, list); } list.add(new WeakReference<V>(value)); putCounter = (putCounter + 1) % SWEEP_COUNT; if (putCounter == 0) SWEEPER.clean(this); } public synchronized void remove(K key) { map.remove(key); } public synchronized boolean containsKey(K key) { final Collection<WeakReference<V>> list = map.get(key); if (list == null) return false; for (Iterator<WeakReference<V>> it = list.iterator(); it.hasNext(); ) { if (it.next().get() != null) return true; it.remove(); } map.remove(key); return false; } @SuppressWarnings("unchecked") public synchronized Iterable<V> get(final K key) { final Collection<WeakReference<V>> list = map.get(key); if (list == null) return Database.EMPTY_ITERABLE; return new Iterable<V>() { public java.util.Iterator<V> iterator() { return new Iterator<V>() { private final Iterator<WeakReference<V>> it = list.iterator(); private V nextItem; {advance();} private void advance() { synchronized(WeakMultiValueHashMap.this) { while(nextItem == null && it.hasNext()) { nextItem = it.next().get(); if (nextItem == null) it.remove(); } if (!it.hasNext() && list.isEmpty()) map.remove(key); } } public boolean hasNext() { advance(); return nextItem != null; } public V next() { advance(); if (nextItem == null) throw new NoSuchElementException(); V item = nextItem; nextItem = null; return item; } public void remove() { throw new UnsupportedOperationException(); } }; } }; } private static final Sweeper SWEEPER = new Sweeper(); static { Thread thread = new Thread(SWEEPER, "WeakMultiValueHashMap sweeper"); thread.setPriority(Thread.NORM_PRIORITY-3); thread.setDaemon(true); thread.start(); } private static class Sweeper implements Runnable { private final LinkedList<WeakMultiValueHashMap<?,?>> inbox = new LinkedList<WeakMultiValueHashMap<?,?>>(); public synchronized void clean(WeakMultiValueHashMap<?,?> map) { inbox.add(map); notifyAll(); } public void run() { try { while(true) { WeakMultiValueHashMap<?,?> map; synchronized(this) { while(inbox.isEmpty()) wait(); map = inbox.removeFirst(); for (Iterator<WeakMultiValueHashMap<?,?>> it = inbox.iterator(); it.hasNext(); ) { if (it.next() == map) it.remove(); } } if (map != null) { synchronized(map) { for (Iterator<? extends Collection<? extends WeakReference<?>>> it = map.map.values().iterator(); it.hasNext(); ) { Collection<? extends WeakReference<?>> list = it.next(); for (Iterator<? extends WeakReference<?>> it2 = list.iterator(); it2.hasNext(); ) { if (it2.next().get() == null) it2.remove(); } if (list.isEmpty()) it.remove(); } } } } } catch (InterruptedException e) { } } } }