/*
* Copyright (C) 2004 TiongHiang Lee
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Email: thlee@onemindsoft.org
*/
package org.onemind.commons.java.datastructure;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* A lookup cache implements simple lookup caching algorithm for looking up things. The derived class simply implement the
* produce(Object key) method which is assumed an expensive operation and the results will be cached by the lookup cache
* implementation. There's no public method on lookup cache, the developer should provide application specific lookup interface.
* @author TiongHiang Lee (thlee@onemindsoft.org)
* @version $Id: LookupCache.java,v 1.4 2004/09/30 13:26:26 thlee Exp $ $Name: $
*/
public abstract class LookupCache
{
/** the logger * */
private static final Logger _logger = Logger.getLogger(LookupCache.class.getName());
/** the hit cache * */
private Map _cache = new HashMap();
/** the negative cache * */
private Set _negCache;
/** indicate whether to do negative caching * */
private boolean _doNegCache = true;
/**
* {@inheritDoc}
*/
public LookupCache()
{
this(true);
}
/**
* {@inheritDoc}
* @param doNegCache whether to do negative caching
*/
public LookupCache(boolean doNegCache)
{
setDoNegativeCache(doNegCache);
}
/**
* The main lookup method. The developer should provide another application specific method that call this method to return what
* the application wants
* @param key the key
* @return the object or null
* @todo add synchronization when lookup the same key to avoid double loading
*/
protected final Object lookup(Object key)
{
if (_doNegCache)
{
if (_negCache.contains(key))
{
if (_logger.isLoggable(Level.FINEST))
{
_logger.finest("Returning negative cache hit");
}
return null;
}
}
Object o = _cache.get(key);
if (o == null)
{
//TODO: synchronization for looking up same key
o = produce(key);
if (o != null)
{
if (_logger.isLoggable(Level.FINEST))
{
_logger.finest("Put hit of " + key + " to cache");
}
_cache.put(key, o);
} else
{
if (_doNegCache)
{
_logger.finest("Put negative hit of " + key + " to cache");
_negCache.add(key);
}
}
} else
{
if (_logger.isLoggable(Level.FINEST))
{
_logger.finest("Returning positive cache hit of " + key);
}
}
return o;
}
/**
* Produce the object given the key. This is assumed to be an expensive operation and it will be called by the lookup method.
* The result will be cached by the lookup method and negative result also will be cached to if the doNegCache is turned on.
* @param key the key
* @return the result or null if no result
*/
protected abstract Object produce(Object key);
/**
* Turn on/off the negative cache
* @param b true to turn on the neg cache
*/
protected void setDoNegativeCache(boolean b)
{
_doNegCache = b;
if (b && (_negCache == null))
{
_negCache = new HashSet();
}
}
/**
* Get whether the object is in negative cache
* @param o the object
* @return true if is in negative cache
*/
protected boolean isInNegCache(Object o)
{
return _negCache.contains(o);
}
/**
* Test if the key is in cache
* @param o the object
* @return true if is in cache
*/
protected boolean isInCache(Object o)
{
return _cache.containsKey(o);
}
/**
* Clear all the negative cache
*/
protected void clearNegCache()
{
if (_negCache != null)
{
_negCache.clear();
}
}
}