* The contents of this file are subject to the Mozilla Public License Version 1.1
* See LICENSE.TXT at the top of this package for the full license terms.
*/
-package eu.etaxonomy.cdm.api.cache;
+package eu.etaxonomy.taxeditor.remoting.cache;
-import java.io.Serializable;
import java.lang.reflect.Field;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
-import java.util.UUID;
import javassist.util.proxy.ProxyFactory;
-
import net.sf.ehcache.Cache;
import net.sf.ehcache.Element;
import net.sf.ehcache.config.CacheConfiguration;
import org.apache.log4j.Logger;
import org.hibernate.collection.spi.PersistentCollection;
-import org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer;
-import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.ReflectionUtils;
-import eu.etaxonomy.cdm.api.service.ICommonService;
+import eu.etaxonomy.cdm.api.cache.CdmServiceCacher;
import eu.etaxonomy.cdm.model.common.CdmBase;
import eu.etaxonomy.taxeditor.session.ICdmEntitySessionManager;
/**
- *
+ *
* This cache guarantees that
* - all objects put will be ancestors of CdmBase
* - all CdmBase objects in the cache will be already de-proxied
- * - after any CdmBase object is put in the cache,
- * all non-null / non-proxy CdmBase objects in the sub-graph
+ * - after any CdmBase object is put in the cache,
+ * all non-null / non-proxy CdmBase objects in the sub-graph
* will also be present in the cache.
- *
+ *
* @author cmathew
* @date 14 Oct 2014
*
private static final Logger logger = Logger.getLogger(CdmTransientEntityCacher.class);
-
+
private ICdmEntitySessionManager cdmEntitySessionManager;
-
+
private static CdmServiceCacher cdmServiceCacher;
-
+
private String cacheId;
- private Cache cache;
+ private Cache cache;
private Cache cdmlibModelCache;
return this.name().toLowerCase();
}
}
-
+
private CdmTransientEntityCacher() {
-
+
}
-
+
public CdmTransientEntityCacher(String cacheId, ICdmEntitySessionManager cdmEntitySessionManager) {
this.cacheId = cacheId;
- cache = new Cache(getEntityCacheConfiguration(cacheId));
+ cache = new Cache(getEntityCacheConfiguration(cacheId));
cdmServiceCacher.getDefaultCacheManager().addCache(cache);
cdmlibModelCache = CdmRemoteCacheManager.getInstance().getCdmModelGetMethodsCache();
private CacheConfiguration getEntityCacheConfiguration(String cacheId) {
// For a better understanding on how to size caches, refer to
// http://ehcache.org/documentation/configuration/cache-size
- return new CacheConfiguration(cacheId, 500)
+ return new CacheConfiguration(cacheId, 500)
.memoryStoreEvictionPolicy(MemoryStoreEvictionPolicy.LFU)
.eternal(false)
// default ttl and tti set to 2 hours
public static void setDefaultCacher(CdmServiceCacher css) {
cdmServiceCacher = css;
}
-
+
/**
* Returns the cache corresponding to the cache id
*
return (T) load((Map<T,T>)obj, recursive);
} else if (obj instanceof Collection) {
return (T) load((Collection<T>)obj, recursive);
- }
-
+ }
+
return obj;
}
-
+
@SuppressWarnings("unchecked")
private <T extends Object> T loadRecursive(T obj, Set<CdmBase> alreadyVisitedEntities) {
if(obj instanceof CdmBase) {
return (T) load((Map<T,T>)obj, alreadyVisitedEntities);
} else if (obj instanceof Collection) {
return (T) load((Collection<T>)obj, alreadyVisitedEntities);
- }
-
+ }
+
logger.info("No caching yet for type " + obj.getClass().getName());
-
+
return obj;
}
-
+
public <T extends Object> Map<T,T> load(Map<T,T> map, boolean recursive){
if(isRecursiveEnabled && recursive) {
logger.info("---- starting recursive load for cdm entity map");
return load(map, null);
}
}
-
+
private <T extends Object> Map<T,T> load(Map<T,T> map, Set<CdmBase> alreadyVisitedEntities){
if(map == null || map.isEmpty()) {
Iterator<Map.Entry<T,T>> iter = map.entrySet().iterator();
int i=0;
while ( iter.hasNext() ) {
- Map.Entry<T,T> e = (Map.Entry<T,T>) iter.next();
+ Map.Entry<T,T> e = iter.next();
result[i++] = e.getKey();
result[i++] = e.getValue();
}
- for(i=0; i<result.length;i++) {
+ for(i=0; i<result.length;i++) {
if(alreadyVisitedEntities == null) {
result[i] = load(result[i], false);
- } else {
+ } else {
result[i] = loadRecursive(result[i], alreadyVisitedEntities);
}
}
}
return map;
}
-
+
public <T extends Object> Collection<T> load(Collection<T> collection, boolean recursive){
Collection<T> loadedCollection;
if(isRecursiveEnabled && recursive) {
loadedCollection = cachedCollection;
} else {
loadedCollection = load(collection, null);
- }
+ }
return loadedCollection;
}
-
+
@SuppressWarnings("unchecked")
private <T extends Object> Collection<T> load(Collection<T> collection, Set<CdmBase> alreadyVisitedEntities){
int length = collection.size();
while(collectionItr.hasNext()) {
if(alreadyVisitedEntities == null) {
result[count] = load(collectionItr.next(), false);
- } else {
+ } else {
result[count] = loadRecursive(collectionItr.next(), alreadyVisitedEntities);
- }
+ }
count++;
}
-
+
collection.clear();
-
+
for ( int i = 0; i < length; i++ ) {
collection.add((T)result[i]);
}
-
+
return collection;
}
-
+
/**
* Puts the (Key,Value) pair of ({@link java.util.UUID}, {@link eu.etaxonomy.cdm.model.common.CdmBase}),
* in the cache corresponding to the given cache id
* @param uuid
* @param cdmEntity
*/
- public CdmBase load(CdmBase cdmEntity, boolean recursive) {
+ public CdmBase load(CdmBase cdmEntity, boolean recursive) {
CdmBase loadedCdmBase;
if(isRecursiveEnabled && recursive) {
logger.info("---- starting recursive load for cdm entity " + cdmEntity.getClass().getName() + " with id " + cdmEntity.getId());
loadedCdmBase = cb;
} else {
loadedCdmBase = load(cdmEntity);
- }
+ }
return loadedCdmBase;
-
+
}
-
+
private CdmBase load(CdmBase cdmEntity) {
logger.info("loading object of type " + cdmEntity.getClass().getName() + " with id " + cdmEntity.getId());
// start by looking up the cdm entity in the cache
CdmBase cachedCdmEntity = getFromCache(cdmEntity);
-
+
if(cachedCdmEntity != null) {
// if cdm entity was found in cache then return ...
logger.info(" - object of type " + cdmEntity.getClass().getName() + " with id " + cdmEntity.getId() + " already exists");
return cachedCdmEntity;
- } else {
- // ... else save the entity in the cache
+ } else {
+ // ... else save the entity in the cache
getCache().put(new Element(generateKey(cdmEntity), cdmEntity));
logger.info(" - object of type " + cdmEntity.getClass().getName() + " with id " + cdmEntity.getId() + " put in cache");
return cdmEntity;
- }
+ }
}
-
+
private CdmBase loadRecursive(CdmBase cdmEntity, Set<CdmBase> alreadyVisitedEntities) {
CdmBase cachedCdmEntity = load(cdmEntity);
-
+
// we want to recursive through the cdmEntity (and not the cachedCdmEntity)
// since there could be new initialized object in the cdmEntity sub-graph
-
+
// start by getting the fields from the cdm entity
String className = cdmEntity.getClass().getName();
CdmModelFieldPropertyFromClass cmgmfc = getFromCdmlibModelCache(className);
// In the case that the returned is either a Collection or a Map
// the individual objects inside these also need to be loaded
// by calling the corresponding cachify method in the
- // CdmEntityCachingUtils
+ // CdmEntityCachingUtils
CdmBase cdmEntityInSubGraph = getCdmBaseTypeFieldValue(cdmEntity, cachedCdmEntity, field, alreadyVisitedEntities);
if(cdmEntityInSubGraph != null) {
- if(!alreadyVisitedEntities.contains(cdmEntityInSubGraph)) {
+ if(!alreadyVisitedEntities.contains(cdmEntityInSubGraph)) {
logger.info("recursive loading object of type " + cdmEntityInSubGraph.getClass().getName() + " with id " + cdmEntityInSubGraph.getId());
loadRecursive(cdmEntityInSubGraph, alreadyVisitedEntities);
} else {
return cachedCdmEntity;
}
-
- private CdmBase getCdmBaseTypeFieldValue(CdmBase cdmEntity,
- CdmBase cachedCdmEntity,
+
+ private CdmBase getCdmBaseTypeFieldValue(CdmBase cdmEntity,
+ CdmBase cachedCdmEntity,
String fieldName,
Set<CdmBase> alreadyVisitedEntities) {
-
-
+
+
if(cachedCdmEntity == null) {
throw new CdmClientCacheException("When trying to set field value, the cached cdm entity cannot be null");
}
-
+
Class<?> clazz = cdmEntity.getClass();
try {
// this call will search in the provided class as well as
Field field = ReflectionUtils.findField(clazz, fieldName);
if(field == null) {
- throw new CdmClientCacheException("Field '" + fieldName
+ throw new CdmClientCacheException("Field '" + fieldName
+ "' not found when searching in class '" + clazz.getName() + "' and its supercalsses");
}
field.setAccessible(true);
Object o = field.get(cdmEntity);
CdmBase cdmEntityInSubGraph = null;
- if(o != null
- && !ProxyFactory.isProxyClass(o.getClass())
+ if(o != null
+ && !ProxyFactory.isProxyClass(o.getClass())
&& !(o instanceof PersistentCollection) ) {
-
+
if(CdmBase.class.isAssignableFrom(o.getClass())) {
logger.info("found initialised cdm entity '" + fieldName + "' in object of type " + clazz.getName() + " with id " + cdmEntity.getId());
cdmEntityInSubGraph = (CdmBase)o;
CdmBase cachedCdmEntityInSubGraph = getFromCache(cdmEntityInSubGraph);
if(cachedCdmEntityInSubGraph != null) {
- if(cachedCdmEntityInSubGraph != cdmEntityInSubGraph) {
+ if(cachedCdmEntityInSubGraph != cdmEntityInSubGraph) {
field.set(cachedCdmEntity, cachedCdmEntityInSubGraph);
}
} else {
} else if(o instanceof Collection) {
loadRecursive((Collection)o, alreadyVisitedEntities);
}
- }
+ }
// we return the original cdm entity in the sub graph because we
// want to continue to recurse on the input cdm entity graph
// and not the one in the cache
throw new CdmClientCacheException(e);
} catch (IllegalAccessException e) {
throw new CdmClientCacheException(e);
- }
+ }
}
- public void put(CdmBase cdmEntity) {
+ public void put(CdmBase cdmEntity) {
CdmEntityCacheKey id = new CdmEntityCacheKey(cdmEntity);
Element cachedCdmEntityElement = getCacheElement(id);
return;
}
}
-
- getCache().put(new Element(id, cdmEntity));
+
+ getCache().put(new Element(id, cdmEntity));
}
}
public CdmBase getFromCache(CdmBase cdmBase) {
-
+
CdmEntityCacheKey cacheId = generateKey(cdmBase);
CdmBase cachedCdmEntity = getFromCache(cacheId);
if(cachedCdmEntity == null) {
// ... then try the permanent (uuid-based) cache
- cachedCdmEntity = cdmServiceCacher.getFromCache(cdmBase.getUuid());
+ cachedCdmEntity = cdmServiceCacher.getFromCache(cdmBase.getUuid());
}
return cachedCdmEntity;
}
-
+
public CdmBase getFromCache(CdmBase cdmBase, Class<? extends CdmBase> clazz) {
-
- cdmBase = CdmBase.deproxy(cdmBase, clazz);
+
+ cdmBase = CdmBase.deproxy(cdmBase, clazz);
CdmEntityCacheKey cacheId = generateKey(cdmBase);
CdmBase cachedCdmEntity = getFromCache(cacheId);
if(cachedCdmEntity == null) {
// ... then try the permanent (uuid-based) cache
- cachedCdmEntity = cdmServiceCacher.getFromCache(cdmBase.getUuid());
+ cachedCdmEntity = cdmServiceCacher.getFromCache(cdmBase.getUuid());
}
return cachedCdmEntity;
public boolean existsAndIsNotNull(CdmEntityCacheKey id) {
return getFromCache(id) != null;
}
-
+
public void dispose() {
cache.removeAll();
cache.flush();