package org.jactr.core.utils;
/*
* default logging
*/
import java.lang.ref.SoftReference;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* default impl of IAdaptable that will handle the object's class heirarchhy,
* plus supports the addition of IAdaptableFactory(s) with hard, soft, and no
* caching (create on each call) supported.
*
* @author harrison
*/
public class DefaultAdaptable implements IAdaptable
{
/**
* Logger definition
*/
static private final transient Log LOGGER = LogFactory
.getLog(DefaultAdaptable.class);
final private Map<Class<?>, IAdaptableFactory> _adapters = new HashMap<Class<?>, IAdaptableFactory>();
private Map<Class<?>, Object> _hardCache; // =
// new
// HashMap<Class<?>,
// Object>();
private Map<Class<?>, SoftReference<?>> _softCache; // =
// new
// HashMap<Class<?>,
// SoftReference<?>>();
@SuppressWarnings("unchecked")
public <T> T getAdapter(Class<T> adapterClass)
{
if (adapterClass.isAssignableFrom(getClass())) return (T) this;
// check our hard cache
Object adapter = null;
if (_hardCache != null) adapter = _hardCache.get(adapterClass);
if (adapter == null)
{
SoftReference<?> reference = null;
if (_softCache != null) reference = _softCache.get(adapterClass);
if (reference != null) adapter = reference.get();
}
/*
* nothing was cached, let's dig deeper.
*/
IAdaptableFactory factory = _adapters.get(adapterClass);
if (adapter == null && factory != null)
{
adapter = factory.adapt(this);
if (LOGGER.isDebugEnabled())
LOGGER.debug(String.format("Created %s for %s from %s", adapter,
adapterClass.getSimpleName(), factory.getClass().getSimpleName()));
if (factory.shouldCache())
{
if (_hardCache == null) _hardCache = new HashMap<Class<?>, Object>();
_hardCache.put(adapterClass, adapter);
}
else if (factory.shouldSoftCache())
{
if (_softCache == null)
_softCache = new HashMap<Class<?>, SoftReference<?>>();
_softCache.put(adapterClass, new SoftReference<Object>(adapter));
}
}
if (LOGGER.isDebugEnabled())
LOGGER.debug(String.format("Returning %s.%d for %s adaptation of %s.%d",
adapter, adapter != null ? adapter.hashCode() : 0,
adapterClass.getSimpleName(), this, hashCode()));
return (T) adapter;
}
/**
* replaces the this adapters and caches with those from adaptable. This is
* used during representation merging. i.e., a merged chunk would adopt the
* master's adaptable contents
*
* @param adaptable
*/
protected void adopt(DefaultAdaptable adaptable)
{
if (LOGGER.isDebugEnabled())
LOGGER.debug(String.format("%s.%d Adopting adaptables from %s.%d", this,
hashCode(), adaptable, adaptable.hashCode()));
_adapters.clear();
if (_hardCache != null) _hardCache.clear();
if (_softCache != null) _softCache.clear();
_adapters.putAll(adaptable._adapters);
if (adaptable._hardCache != null)
{
if (_hardCache == null) _hardCache = new HashMap<Class<?>, Object>();
_hardCache.putAll(adaptable._hardCache);
}
if (adaptable._softCache != null)
{
if (_softCache == null)
_softCache = new HashMap<Class<?>, SoftReference<?>>();
_softCache.putAll(adaptable._softCache);
}
}
public void addAdapterFactory(IAdaptableFactory factory, Class<?>[] forClasses)
{
for (Class<?> c : forClasses)
{
IAdaptableFactory prior = _adapters.put(c, factory);
if (prior != factory)
LOGGER.debug(String.format("Replacing factory for %s [%s] with [%s]",
c, prior, factory));
}
}
public void removeAdapterFactory(IAdaptableFactory factory,
Class<?>[] forClasses)
{
for (Class<?> c : forClasses)
{
IAdaptableFactory prior = _adapters.remove(c);
if (prior != factory)
LOGGER.debug(String.format(
"Removed factory for %s [%s] was not the expected [%s]", c, prior,
factory));
}
}
}