package ddth.dasp.framework.cache;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.concurrent.ConcurrentMap;
import org.osgi.framework.BundleContext;
import org.springframework.osgi.context.BundleContextAware;
import com.google.common.collect.MapMaker;
import ddth.dasp.common.DaspGlobal;
import ddth.dasp.common.id.IdGenerator;
public abstract class AbstractCacheManager implements ICacheManager, BundleContextAware {
public final static String CACHE_PROP_CAPACITY = "cache.capacity";
public final static String CACHE_PROP_EXPIRE_AFTER_WRITE = "cache.expireAfterWrite";
public final static String CACHE_PROP_EXPIRE_AFTER_ACCESS = "cache.expireAfterAccess";
private long defaultCacheCapacity = ICacheManager.DEFAULT_CACHE_CAPACITY;
private long defaultExpireAfterAccess = ICacheManager.DEFAULT_EXPIRE_AFTER_ACCESS;
private long defaultExpireAfterWrite = ICacheManager.DEFAULT_EXPIRE_AFTER_WRITE;
private ConcurrentMap<String, ICache> caches;
private Map<String, Properties> cacheProperties;
private String cacheNamePrefix;
private String ID = IdGenerator.getInstance(IdGenerator.getMacAddr()).generateId64Hex();
private BundleContext bundleContext;
/**
* {@inheritDoc}
*/
@SuppressWarnings("unchecked")
@Override
public void init() {
int numProcessores = Runtime.getRuntime().availableProcessors();
MapMaker mm = new MapMaker();
mm.concurrencyLevel(numProcessores);
caches = mm.makeMap();
synchronized (ICacheManager.class) {
Object temp = DaspGlobal.getGlobalVar(ICacheManager.GLOBAL_KEY);
if (!(temp instanceof Map)) {
temp = new HashMap<String, ICacheManager>();
DaspGlobal.setGlobalVar(ICacheManager.GLOBAL_KEY, temp);
}
Map<String, ICacheManager> allCacheManagers = (Map<String, ICacheManager>) temp;
allCacheManagers.put(ID, this);
}
}
/**
* {@inheritDoc}
*/
@SuppressWarnings("unchecked")
@Override
public void destroy() {
synchronized (ICacheManager.class) {
Object temp = DaspGlobal.getGlobalVar(ICacheManager.GLOBAL_KEY);
if (!(temp instanceof Map)) {
temp = new HashMap<String, ICacheManager>();
DaspGlobal.setGlobalVar(ICacheManager.GLOBAL_KEY, temp);
}
Map<String, ICacheManager> allCacheManagers = (Map<String, ICacheManager>) temp;
allCacheManagers.remove(ID);
}
if (caches != null) {
try {
Iterator<Entry<String, ICache>> it = caches.entrySet().iterator();
while (it.hasNext()) {
Entry<String, ICache> entry = it.next();
try {
entry.getValue().destroy();
} catch (Exception e) {
// EMPTY
}
}
} finally {
caches.clear();
caches = null;
}
}
}
protected String buildCacheName(String cacheName) {
return cacheNamePrefix != null ? cacheNamePrefix + cacheName : cacheName;
}
public String getCacheNamePrefix() {
return cacheNamePrefix;
}
public void setCacheNamePrefix(String cacheNamePrefix) {
this.cacheNamePrefix = cacheNamePrefix;
}
public long getDefaultCacheCapacity() {
return defaultCacheCapacity;
}
public void setDefaultCacheCapacity(long defaultCacheCapacity) {
this.defaultCacheCapacity = defaultCacheCapacity;
}
public long getDefaultExpireAfterAccess() {
return defaultExpireAfterAccess;
}
public void setDefaultExpireAfterAccess(long defaultExpireAfterAccess) {
this.defaultExpireAfterAccess = defaultExpireAfterAccess;
}
public long getDefaultExpireAfterWrite() {
return defaultExpireAfterWrite;
}
public void setDefaultExpireAfterWrite(long defaultExpireAfterWrite) {
this.defaultExpireAfterWrite = defaultExpireAfterWrite;
}
public void setCacheProperties(Map<String, Properties> cacheProperties) {
this.cacheProperties = cacheProperties;
}
/**
* Gets a cache's properties
*
* @param name
* @return
*/
protected Properties getCacheProperties(String name) {
return cacheProperties != null ? cacheProperties.get(name) : null;
}
/**
* {@inheritDoc}
*/
@Override
public ICache getCache(String name) {
return caches.get(buildCacheName(name));
}
/**
* {@inheritDoc}
*/
@Override
synchronized public ICache[] getCaches() {
List<ICache> result = new ArrayList<ICache>();
for (Entry<String, ICache> entry : caches.entrySet()) {
result.add(entry.getValue());
}
Collections.sort(result, new Comparator<ICache>() {
@Override
public int compare(ICache o1, ICache o2) {
return o1.getName().compareTo(o2.getName());
}
});
return result.toArray(new ICache[0]);
}
/**
* {@inheritDoc}
*/
@Override
public void removeCache(String name) {
String cacheName = buildCacheName(name);
ICache cache = caches.get(cacheName);
if (cache != null) {
try {
cache.destroy();
} finally {
caches.remove(cacheName);
}
}
}
/**
* {@inheritDoc}
*/
@Override
synchronized public ICache createCache(String name) {
return createCache(name, defaultCacheCapacity, defaultExpireAfterWrite,
defaultExpireAfterAccess);
}
/**
* {@inheritDoc}
*/
@Override
synchronized public ICache createCache(String name, long capacity) {
return createCache(name, capacity, defaultExpireAfterWrite, defaultExpireAfterAccess);
}
@Override
synchronized public ICache createCache(String name, long capacity, long expireAfterWrite,
long expireAfterAccess) {
String cacheName = buildCacheName(name);
ICache cache = caches.get(cacheName);
if (cache == null) {
// check if custom cache settings exist
long cacheCapacity = capacity;
long cacheExpireAfterWrite = expireAfterWrite;
long cacheExpireAfterAccess = expireAfterAccess;
// yup, use "name" here (not "cacheName) is correct and intended!
Properties cacheProps = getCacheProperties(name);
if (cacheProps != null) {
try {
cacheCapacity = Long.parseLong(cacheProps.getProperty(CACHE_PROP_CAPACITY));
} catch (Exception e) {
cacheCapacity = capacity;
}
try {
cacheExpireAfterWrite = Long.parseLong(cacheProps
.getProperty(CACHE_PROP_EXPIRE_AFTER_WRITE));
} catch (Exception e) {
cacheExpireAfterWrite = expireAfterWrite;
}
try {
cacheExpireAfterAccess = Long.parseLong(cacheProps
.getProperty(CACHE_PROP_EXPIRE_AFTER_ACCESS));
} catch (Exception e) {
cacheExpireAfterAccess = expireAfterAccess;
}
}
cache = createCacheInternal(cacheName, cacheCapacity, cacheExpireAfterWrite,
cacheExpireAfterAccess);
caches.put(cacheName, cache);
}
return cache;
}
/**
* Creates a new cache instance. Convenient for sub-class to override.
*
* @param name
* @param capacity
* @param expireAfterWrite
* @param expireAfterAccess
* @return
*/
protected abstract ICache createCacheInternal(String name, long capacity,
long expireAfterWrite, long expireAfterAccess);
/**
* {@inheritDoc}
*/
@Override
public void setBundleContext(BundleContext bundleContext) {
this.bundleContext = bundleContext;
}
protected BundleContext getBundleContext() {
return bundleContext;
}
}