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("");
}
}
}
}