package com.idega.util.caching; import java.util.HashMap; import java.util.Iterator; import java.util.Map; /** *<p> *This class is to be used as a java.util.Map as a convenient way of caching objects. *The maximum number of cached objects can be set and increased an decreased (default number is 100) *The Map removes the least used objects in favour of newly inserted ones and keeps the most accessed objects.<br/> *This Cache Map is deprecated as of platform 3.1 as now is more recommended to use IWCacheManager2.getCache() *<p> * @author <a href="tryggvi@idega.is">Tryggvi Larusson</a> * @version 0.5 */ public class CacheMap extends HashMap implements Map { private static final long serialVersionUID = -2566778836998184283L; private int maxNumberOfObjectsInMap = 100; private Map accesses; /** * Constructs a CacheMap with maximum 100 stored objects **/ public CacheMap() { this(100); } /** * Constructs a CacheMap setting the maximum number stored objects that will reside in cache. * @param maxNumberOfStoredObjects The size that the CacheMap will always be less than or equal to **/ public CacheMap(int maxNumberOfStoredObjects) { setMaxNumberOfObjects(maxNumberOfStoredObjects); } /** * Sets the maximum number of objects to be stored in cache **/ public void setMaxNumberOfObjects(int size) { this.maxNumberOfObjectsInMap = size; } public int getMaxNumberOfObjects() { return this.maxNumberOfObjectsInMap; } private Map getAcesses() { if (this.accesses == null) { this.accesses = new HashMap(); } return this.accesses; } protected synchronized void reduce(int byCount) { for (int i = 0; i < byCount; i++) { removeLeastUsedObjectFromMemory(); } } public Object put(Object key, Object value) { int difference = super.size() - this.getMaxNumberOfObjects(); if (difference >= 0) { reduce(difference + 1); } incrementAccessesForKey(key); return super.put(key, value); } public Object get(Object key) { Object value = super.get(key); if (value == null) { this.removeAccessesForKey(key); return value; } else { incrementAccessesForKey(key); return value; } } public synchronized Object remove(Object key) { removeAccessesForKey(key); return super.remove(key); } protected synchronized void removeLeastUsedObjectFromMemory() { Object key = getLeastAccessedKey(); //System.out.println("Removing: "+key); onReducementFromMemory(key); } public synchronized void removeLeastUsedObjectFromMap() { Object key = getLeastAccessedKey(); onReducementFromMap(key); } protected synchronized void onReducementFromMap(Object key) { remove(key); } protected synchronized void onReducementFromMemory(Object key) { remove(key); } protected Object getLeastAccessedKey() { return getLeastAccessedKeyInteger(); } protected Object getLeastAccessedKeyInteger() { Iterator keyIter = getAcesses().keySet().iterator(); Object theReturn = null; int lowestIntVal = -1; while (keyIter.hasNext()) { Object key = keyIter.next(); Integer integ = (Integer) this.getAcesses().get(key); int intval = integ.intValue(); if (intval < lowestIntVal || lowestIntVal == -1) { lowestIntVal = intval; theReturn = key; } } return theReturn; } protected void incrementAccessesForKey(Object key){ incrementAccessesForKeyInteger(key); } protected void incrementAccessesForKeyInteger(Object key) { Integer prevValue = (Integer) this.getAcesses().get(key); int prevIntValue; if (prevValue == null) { prevIntValue = 0; } else { prevIntValue = prevValue.intValue(); } Integer newValue = new Integer(prevIntValue+1); getAcesses().put(key, newValue); //System.out.println("Incrementing for key: "+key+" - from "+prevValue+" to "+newValue); } protected void removeAccessesForKey(Object key) { this.getAcesses().remove(key); } public synchronized void clear() { super.clear(); this.accesses.clear(); } protected class AccessCount implements Comparable{ int intValue=0; Object oKey; protected AccessCount(Object key){ this.oKey=key; } public void increment(){ this.intValue++; } public int getCount(){ return this.intValue; } public int compareTo(Object o){ AccessCount c = (AccessCount)o; /*if(getCount()<c.getCount()){ return -1; }*/ return(getCount()-c.getCount()); } public Object getKey(){ return this.oKey; } } /** * Testing method **/ public static void main(String[] args){ CacheMap map = new CacheMap(100); //Map map = new HashMap(); int max = 10000; String key0 = "key0"; map.put(key0,new Integer(0)); for (int i = 1; i < 100; i++) { map.get(key0); } long begin = System.currentTimeMillis(); for (int i = 1; i < max; i++) { Integer test1 = new Integer(i); String key = "key"+i; map.put(key,test1); } long end = System.currentTimeMillis(); long elapsed = end-begin; System.out.println("Put1 for "+map.getClass().getName()+" Took: "+elapsed+" ms."); begin = System.currentTimeMillis(); for (int i = 0; i < max; i++) { map.get(key0); } end = System.currentTimeMillis(); elapsed = end-begin; System.out.println("Get2 for "+map.getClass().getName()+" Took: "+elapsed+" ms."); System.out.println("Map.size():"+map.size()); if(args.length>0){ System.out.println("Contents:"); for (Iterator iter = map.keySet().iterator(); iter.hasNext();) { Object key = iter.next(); Object value = map.get(key); System.out.print("Key "+key+"="+value); if(map != null){ CacheMap cMap = map; System.out.print(" - With accesses: "+cMap.getAcesses().get(key)); } System.out.println(""); } } } }