package com.technofovea.hllib; import java.lang.ref.WeakReference; import java.util.HashMap; /** * A class to manage the caching of Java objects via references which do not * prevent garbage collection from occurring. * * The main purpose is to provide a consistent set of objects which wrap JNA * constructs such as Pointers, since JNA, undisturbed, tends to allocate a new * object every time rather than reusing old ones. * * This class is not thread-safe. * @author Darien Hager */ public abstract class WeakReferenceCache<K,V> { protected HashMap<K,WeakReference<V>> map = new HashMap<K,WeakReference<V>>(); /** * Determines the key used to avoid duplicates of the item. * * @param item The item to inspect * @return A key used to prevent duplicates */ public abstract K getKey(V item); /** * Removes the entry in the cache which corresponds to the given object, * even if the two are not technically the same instance. * * @param item The item to remove or a similar one. * @return True if something was removed, false otherwise. */ public boolean remove(V item){ K key = getKey(item); if(map.containsKey(key)){ map.remove(key); return true; } return false; } /** * Find a cached copy that matches the given object and returns it. If the * cache is empty, the given object is stored and returned. * @param item The item to try to store * @return The item which was previous cached or just-now cached. */ public V getOrPut(V item){ K key = getKey(item); V stored = getByKey(key); if(stored != null){ return stored; }else{ store(item); return item; } } /** * Attempts to store the given item into the cache. Will return false * if another item is already present for the asme key. * @param candidate Item to store * @return True if it was stored successfully. */ public boolean store(V candidate){ K key = getKey(candidate); V stored = getByKey(key); if(stored != null){ return false; }else{ map.put(key, new WeakReference<V>(candidate)); return true; } } /** * Looks to see if the given object would correspond to an item in the cache. * If such an item exists, it is retrieved and returned. * @param candidate * @return The cached object, or null if nothing found. */ public V get(V candidate){ V stored = getByKey(getKey(candidate)); if(stored != null){ return stored; }else{ return null; } } /** * Attempts to retrieve a cached copy for the given key. Will return null * if nothing could be found or the object was garbage-collected. * @param key Key to search for * @return The stored object or null if none found. */ public V getByKey(K key){ if(!map.containsKey(key)){ return null; } WeakReference<V> ref = map.get(key); V stored = ref.get(); if(stored == null){ map.remove(key); return null; } return stored; } /** * Removes all entries where the reference is no longer valid. */ public void clean(){ for(K key: map.keySet()){ if(map.get(key).get() == null){ map.remove(key); } } } }