*/
package eu.etaxonomy.taxeditor.remoting.cache;
-import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collection;
-import java.util.HashSet;
-import java.util.Iterator;
import java.util.List;
import java.util.Map;
-import java.util.Set;
-import javassist.util.proxy.ProxyFactory;
import net.sf.ehcache.Cache;
import net.sf.ehcache.Element;
import net.sf.ehcache.config.CacheConfiguration;
import net.sf.ehcache.store.MemoryStoreEvictionPolicy;
import org.apache.log4j.Logger;
-import org.hibernate.collection.spi.PersistentCollection;
-import org.hibernate.proxy.HibernateProxy;
-import org.hibernate.proxy.LazyInitializer;
-import org.springframework.util.ReflectionUtils;
import eu.etaxonomy.cdm.api.cache.CdmServiceCacher;
+import eu.etaxonomy.cdm.model.ICdmCacher;
import eu.etaxonomy.cdm.model.common.CdmBase;
import eu.etaxonomy.taxeditor.session.ICdmEntitySessionManager;
*
*/
-public class CdmTransientEntityCacher {
+public class CdmTransientEntityCacher implements ICdmCacher {
private static final Logger logger = Logger.getLogger(CdmTransientEntityCacher.class);
- private ICdmEntitySessionManager cdmEntitySessionManager;
+ private final ICdmEntitySessionManager cdmEntitySessionManager;
private static CdmServiceCacher cdmServiceCacher;
- private String cacheId;
+ private final String cacheId;
- private Cache cache;
+ private final Cache cache;
+
+ private final CacheLoader cacheLoader;
- private Cache cdmlibModelCache;
- private static boolean isRecursiveEnabled = true;
public static enum CollectionType {
SET,
}
}
- private CdmTransientEntityCacher() {
-
- }
public CdmTransientEntityCacher(String cacheId, ICdmEntitySessionManager cdmEntitySessionManager) {
this.cacheId = cacheId;
cache = new Cache(getEntityCacheConfiguration(cacheId));
- cdmServiceCacher.getDefaultCacheManager().addCache(cache);
+ CdmRemoteCacheManager.getInstance().getDefaultCacheManager().addCache(cache);
- cdmlibModelCache = CdmRemoteCacheManager.getInstance().getCdmModelGetMethodsCache();
+ cacheLoader = new CacheLoader(this);
this.cdmEntitySessionManager = cdmEntitySessionManager;
* @return
*/
private Cache getCache() {
- return cdmServiceCacher.getDefaultCacheManager().getCache(cacheId);
+ return CdmRemoteCacheManager.getInstance().getDefaultCacheManager().getCache(cacheId);
}
- @SuppressWarnings("unchecked")
public <T extends Object> T load(T obj, boolean recursive) {
- if(obj == null) {
- return null;
- }
- if(obj instanceof CdmBase) {
- return (T) load((CdmBase)obj, recursive);
- } else if (obj instanceof Map) {
- 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 == null) {
- return null;
- }
- if(obj instanceof CdmBase) {
- return (T) loadRecursive((CdmBase)obj, alreadyVisitedEntities);
- } else if (obj instanceof Map) {
- 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;
+ return cacheLoader.load(obj, recursive);
}
public <T extends Object> Map<T,T> load(Map<T,T> map, boolean recursive){
- if(map == null) {
- return null;
- }
-
- if(isRecursiveEnabled && recursive) {
- logger.info("---- starting recursive load for cdm entity map");
- Set<CdmBase> alreadyVisitedEntities = new HashSet<CdmBase>();
- Map<T,T> cachedMap = load(map, alreadyVisitedEntities);
- alreadyVisitedEntities.clear();
- logger.info("---- ending recursive load for cdm entity map \n");
- return cachedMap;
- } else {
- return load(map, null);
- }
- }
-
-
- private <T extends Object> Map<T,T> load(Map<T,T> map, Set<CdmBase> alreadyVisitedEntities){
- if(map == null || map.isEmpty()) {
- return map;
- }
-
- int originalMapSize = map.size();
- Object[] result = new Object[ map.size() * 2 ];
- Iterator<Map.Entry<T,T>> iter = map.entrySet().iterator();
- int i=0;
- while ( iter.hasNext() ) {
- Map.Entry<T,T> e = iter.next();
- result[i++] = e.getKey();
- result[i++] = e.getValue();
- }
-
- for(i=0; i<result.length;i++) {
- if(alreadyVisitedEntities == null) {
- result[i] = load(result[i], false);
- } else {
- result[i] = loadRecursive(result[i], alreadyVisitedEntities);
- }
- }
- map.clear();
- for(i = 0; i < originalMapSize; i+=2 ) {
- map.put(
- (T)result[i],
- (T)result[i+1]
- );
- }
- return map;
+ return cacheLoader.load(map, recursive);
}
public <T extends Object> Collection<T> load(Collection<T> collection, boolean recursive){
- if(collection == null) {
- return null;
- }
-
- Collection<T> loadedCollection;
- if(isRecursiveEnabled && recursive) {
- logger.info("---- starting recursive load for cdm entity collection");
- Set<CdmBase> alreadyVisitedEntities = new HashSet<CdmBase>();
- Collection<T> cachedCollection = load(collection, alreadyVisitedEntities);
- alreadyVisitedEntities.clear();
- logger.info("---- ending recursive load for cdm entity collection \n");
- 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();
- Object[] result = new Object[length];
- Iterator<T> collectionItr = collection.iterator();
- int count = 0;
- while(collectionItr.hasNext()) {
- Object obj = collectionItr.next();
- if(alreadyVisitedEntities == null) {
- result[count] = load(obj, false);
- } else {
- result[count] = loadRecursive(obj, alreadyVisitedEntities);
- }
-
- count++;
- }
-
- collection.clear();
-
- for ( int i = 0; i < length; i++ ) {
- collection.add((T)result[i]);
- }
-
- return collection;
+ return cacheLoader.load(collection, recursive);
}
-
- /**
- * 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 cacheId
- * @param uuid
- * @param cdmEntity
- */
public CdmBase load(CdmBase cdmEntity, boolean recursive) {
- if(cdmEntity == null) {
- return null;
- }
-
-
- // 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
- logger.info(" - object of type " + cdmEntity.getClass().getName() + " with id " + cdmEntity.getId() + " already exists");
- // .. return if the cached and input objects are identical, else (this is a newly loaded object so) continue
- if(cachedCdmEntity == cdmEntity) {
- return cachedCdmEntity;
- }
- }
-
- CdmBase loadedCdmBase;
- if(isRecursiveEnabled && recursive) {
- logger.info("---- starting recursive load for cdm entity " + cdmEntity.getClass().getName() + " with id " + cdmEntity.getId());
- Set<CdmBase> alreadyVisitedEntities = new HashSet<CdmBase>();
- CdmBase cb = loadRecursive(cdmEntity, alreadyVisitedEntities);
- alreadyVisitedEntities.clear();
- logger.info("---- ending recursive load for cdm entity " + cdmEntity.getClass().getName() + " with id " + cdmEntity.getId() + "\n");
- 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
- getCache().put(new Element(generateKey(cdmEntity), cdmEntity));
- logger.info(" - object of type " + cdmEntity.getClass().getName() + " with id " + cdmEntity.getId() + " put in cache");
- return cdmEntity;
- }
+ return cacheLoader.load(cdmEntity, recursive);
}
- 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 or deleted objects in the cdmEntity sub-graph
-
- // start by getting the fields from the cdm entity
- String className = cdmEntity.getClass().getName();
- CdmModelFieldPropertyFromClass cmgmfc = getFromCdmlibModelCache(className);
- if(cmgmfc != null) {
- alreadyVisitedEntities.add(cdmEntity);
- List<String> fields = cmgmfc.getFields();
- for(String field : fields) {
- // retrieve the actual object corresponding to the field.
- // this object will be either a CdmBase or a Collection / Map
- // with CdmBase as the generic type
-
- CdmBase cdmEntityInSubGraph = getCdmBaseTypeFieldValue(cdmEntity, cachedCdmEntity, field, alreadyVisitedEntities);
- if(cdmEntityInSubGraph != null) {
- if(!alreadyVisitedEntities.contains(cdmEntityInSubGraph)) {
- logger.info("recursive loading object of type " + cdmEntityInSubGraph.getClass().getName() + " with id " + cdmEntityInSubGraph.getId());
- loadRecursive(cdmEntityInSubGraph, alreadyVisitedEntities);
- } else {
- logger.info("object of type " + cdmEntityInSubGraph.getClass().getName() + " with id " + cdmEntityInSubGraph.getId() + " already visited");
- }
- }
- }
- } else {
- throw new CdmClientCacheException("CdmEntity with class " + cdmEntity.getClass().getName() + " is not found in the cdmlib model cache. " +
- "The cache may be corrupted or not in sync with the latest model version" );
- }
- return cachedCdmEntity;
+ public CdmModelFieldPropertyFromClass getFromCdmlibModelCache(String className) {
+ return cacheLoader.getFromCdmlibModelCache(className);
}
- private CdmBase getCdmBaseTypeFieldValue(CdmBase cdmEntity,
- CdmBase cachedCdmEntity,
- String fieldName,
- Set<CdmBase> alreadyVisitedEntities) {
-
- // this method attempts to make sure that for any two objects found in
- // the object graph, if they are equal then they should also be the same,
- // which is crucial for the merge to work
- 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
- // the super classes until it finds the field
- Field field = ReflectionUtils.findField(clazz, fieldName);
-
- if(field == null) {
- throw new CdmClientCacheException("Field '" + fieldName
- + "' not found when searching in class '" + clazz.getName() + "' and its supercalsses");
- }
- field.setAccessible(true);
- Object o = field.get(cdmEntity);
-
- if(o != null && o instanceof HibernateProxy) {
- LazyInitializer hli = ((HibernateProxy)o).getHibernateLazyInitializer();
- if(!hli.isUninitialized()) {
- o = ((HibernateProxy) o).getHibernateLazyInitializer().getImplementation();
- field.set(cdmEntity, o);
- }
- }
-
- if(o != null && o instanceof PersistentCollection) {
- PersistentCollection pc = ((PersistentCollection)o);
- if(pc.wasInitialized()) {
- o = ProxyUtils.getObject(pc);
- field.set(cdmEntity, o);
- }
- }
-
- //field.set(cdmEntity, o);
- CdmBase cdmEntityInSubGraph = null;
- 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);
- // making sure that the field in cached cdm entity is always
- // up-to-date by setting to the value of the cdm entity being loaded
- // the only execption to this is found below
- field.set(cachedCdmEntity, o);
-
- // the only exception to updating the field to the latest value
- // is the case where the field has been already initialised, cached and
- // is not the same as the one in the cache, in which case we set the value
- // of the field to the one found in the cache
- if(cachedCdmEntityInSubGraph != null) {
- if(cachedCdmEntityInSubGraph != cdmEntityInSubGraph) {
- logger.info("setting cached + real value to '" + fieldName + "' in object of type " + clazz.getName() + " with id " + cdmEntity.getId());
- field.set(cachedCdmEntity, cachedCdmEntityInSubGraph);
- }
- }
- } else if(o instanceof Map) {
- loadRecursive((Map)o, alreadyVisitedEntities);
- } 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
- return cdmEntityInSubGraph;
- } catch (SecurityException e) {
- throw new CdmClientCacheException(e);
- } catch (IllegalArgumentException e) {
- throw new CdmClientCacheException(e);
- } catch (IllegalAccessException e) {
- throw new CdmClientCacheException(e);
- }
- }
+ @Override
public void put(CdmBase cdmEntity) {
CdmEntityCacheKey id = new CdmEntityCacheKey(cdmEntity);
- Element cachedCdmEntityElement = getCacheElement(id);
-
- if(cachedCdmEntityElement == null) {
- cachedCdmEntityElement = cdmServiceCacher.getCacheElement(cdmEntity.getUuid());
- if(cachedCdmEntityElement != null) {
- logger.info("Cdm Entity with id : " + cdmEntity.getId() + " already exists in permanent cache. Ignoring put.");
- return;
- }
+ Element cachedCdmEntityElement = cdmServiceCacher.getCacheElement(cdmEntity.getUuid());
+ if(cachedCdmEntityElement != null) {
+ logger.info("Cdm Entity with id : " + cdmEntity.getId() + " already exists in permanent cache. Ignoring put.");
+ return;
}
-
getCache().put(new Element(id, cdmEntity));
}
return getCache().get(key);
}
- public CdmModelFieldPropertyFromClass getFromCdmlibModelCache(String className) {
- Element e = cdmlibModelCache.get(className);
- if (e == null) {
- return null;
- } else {
- return (CdmModelFieldPropertyFromClass) e.getObjectValue();
- }
- }
public CdmBase getFromCache(CdmEntityCacheKey id) {
Element e = getCacheElement(id);
return getFromCache(cacheId);
}
+ @Override
public CdmBase getFromCache(CdmBase cdmBase) {
CdmEntityCacheKey cacheId = generateKey(cdmBase);
public void dispose() {
cache.removeAll();
cache.flush();
- cdmServiceCacher.getDefaultCacheManager().removeCache(cacheId);
+ CdmRemoteCacheManager.getInstance().getDefaultCacheManager().removeCache(cacheId);
}
return new CdmEntityCacheKey(entityClass, id);
}
- public static boolean isRecursiveEnabled() {
- return isRecursiveEnabled;
- }
-
- public static void setRecursiveEnabled(boolean ire) {
- isRecursiveEnabled = ire;
- }
-
}