[jboss-cvs] JBossCache/src-50/org/jboss/cache/pojo ...
Ben Wang
bwang at jboss.com
Tue Jul 11 05:07:40 EDT 2006
User: bwang
Date: 06/07/11 05:07:40
Modified: src-50/org/jboss/cache/pojo ObjectGraphHandler.java
PojoTreeCache.java
Added: src-50/org/jboss/cache/pojo PojoCacheDelegate.java
Removed: src-50/org/jboss/cache/pojo TreeCacheAopDelegate.java
Log:
Renamed TreeCacheAopDelegate.
Revision Changes Path
1.7 +3 -3 JBossCache/src-50/org/jboss/cache/pojo/ObjectGraphHandler.java
(In the diff below, changes in quantity of whitespace are not shown.)
Index: ObjectGraphHandler.java
===================================================================
RCS file: /cvsroot/jboss/JBossCache/src-50/org/jboss/cache/pojo/ObjectGraphHandler.java,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -b -r1.6 -r1.7
--- ObjectGraphHandler.java 7 Jul 2006 10:36:44 -0000 1.6
+++ ObjectGraphHandler.java 11 Jul 2006 09:07:40 -0000 1.7
@@ -24,16 +24,16 @@
*
* @author Ben Wang
* Date: Aug 4, 2005
- * @version $Id: ObjectGraphHandler.java,v 1.6 2006/07/07 10:36:44 bwang Exp $
+ * @version $Id: ObjectGraphHandler.java,v 1.7 2006/07/11 09:07:40 bwang Exp $
*/
class ObjectGraphHandler
{
private PojoTreeCache cache_;
private InternalDelegate internal_;
private final static Log log = LogFactory.getLog(ObjectGraphHandler.class);
- private TreeCacheAopDelegate delegate_;
+ private PojoCacheDelegate delegate_;
- public ObjectGraphHandler(PojoTreeCache cache, InternalDelegate internal, TreeCacheAopDelegate delegate)
+ public ObjectGraphHandler(PojoTreeCache cache, InternalDelegate internal, PojoCacheDelegate delegate)
{
cache_ = cache;
internal_ = internal;
1.7 +2 -13 JBossCache/src-50/org/jboss/cache/pojo/PojoTreeCache.java
(In the diff below, changes in quantity of whitespace are not shown.)
Index: PojoTreeCache.java
===================================================================
RCS file: /cvsroot/jboss/JBossCache/src-50/org/jboss/cache/pojo/PojoTreeCache.java,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -b -r1.6 -r1.7
--- PojoTreeCache.java 8 Jul 2006 17:41:16 -0000 1.6
+++ PojoTreeCache.java 11 Jul 2006 09:07:40 -0000 1.7
@@ -6,34 +6,23 @@
*/
package org.jboss.cache.pojo;
-import org.jboss.aop.InstanceAdvisor;
import org.jboss.cache.CacheException;
import org.jboss.cache.DataNode;
import org.jboss.cache.Fqn;
-import org.jboss.cache.NodeImpl;
import org.jboss.cache.RegionNotEmptyException;
import org.jboss.cache.TreeCache;
-import org.jboss.cache.lock.UpgradeException;
import org.jboss.cache.marshall.ObjectSerializationFactory;
import org.jboss.cache.marshall.Region;
import org.jboss.cache.marshall.RegionNameConflictException;
import org.jboss.cache.pojo.eviction.AopEvictionPolicy;
import org.jboss.cache.pojo.util.ObjectUtil;
import org.jboss.cache.pojo.observable.Observer;
-import org.jboss.cache.transaction.BatchModeTransactionManager;
import org.jboss.cache.xml.XmlHelper;
import org.jgroups.JChannel;
import org.w3c.dom.Element;
-import javax.transaction.RollbackException;
-import javax.transaction.Status;
-import javax.transaction.SystemException;
import javax.transaction.Transaction;
-import javax.transaction.TransactionManager;
-import java.lang.reflect.Field;
-import java.util.ArrayList;
import java.util.Iterator;
-import java.util.List;
import java.util.Map;
import java.util.WeakHashMap;
@@ -42,7 +31,7 @@
// Class -> CachedType
// use WeakHashMap to allow class reloading
private Map cachedTypes = new WeakHashMap();
- private TreeCacheAopDelegate delegate_;
+ private PojoCacheDelegate delegate_;
private Element config_ = null;
// boolean detachPojoWhenEvicted_ = false;
private boolean marshallNonSerializable_ = false;
@@ -77,7 +66,7 @@
private void init()
{
- delegate_ = new TreeCacheAopDelegate(this, observer_);
+ delegate_ = new PojoCacheDelegate(this, observer_);
}
@Override
1.1 date: 2006/07/11 09:07:40; author: bwang; state: Exp;JBossCache/src-50/org/jboss/cache/pojo/PojoCacheDelegate.java
Index: PojoCacheDelegate.java
===================================================================
/*
* JBoss, the OpenSource J2EE webOS
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package org.jboss.cache.pojo;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jboss.aop.Advised;
import org.jboss.aop.Advisor;
import org.jboss.aop.ClassInstanceAdvisor;
import org.jboss.aop.InstanceAdvisor;
import org.jboss.aop.advice.Interceptor;
import org.jboss.aop.proxy.ClassProxy;
import org.jboss.cache.CacheException;
import org.jboss.cache.Fqn;
import org.jboss.cache.pojo.interceptors.dynamic.AbstractCollectionInterceptor;
import org.jboss.cache.pojo.memory.FieldPersistentReference;
import org.jboss.cache.pojo.util.AopUtil;
import org.jboss.cache.pojo.interceptors.dynamic.BaseInterceptor;
import org.jboss.cache.pojo.interceptors.dynamic.CacheFieldInterceptor;
import org.jboss.cache.pojo.observable.Observer;
import java.lang.reflect.Field;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Delegate class for PojoCache.
*
* @author Ben Wang
*/
class PojoCacheDelegate
{
private PojoTreeCache cache_;
private final static Log log = LogFactory.getLog(PojoCacheDelegate.class);
private InternalDelegate internal_;
private ObjectGraphHandler graphHandler_;
private CollectionClassHandler collectionHandler_;
private SerializableObjectHandler serializableHandler_;
// Use ThreadLocal to hold a boolean isBulkRemove
private ThreadLocal<Boolean> bulkRemove_ = new ThreadLocal<Boolean>();
private final String DETACH = "DETACH";
private PojoUtil util_ = new PojoUtil();
// Observer for field event notification
private Observer observer_;
public PojoCacheDelegate(PojoTreeCache cache, Observer observer)
{
cache_ = cache;
internal_ = new InternalDelegate(cache);
graphHandler_ = new ObjectGraphHandler(cache_, internal_, this);
collectionHandler_ = new CollectionClassHandler(cache_, internal_, graphHandler_);
serializableHandler_ = new SerializableObjectHandler(cache_, internal_);
observer_ = observer;
}
public void setBulkRemove(boolean bulk)
{
bulkRemove_.set(Boolean.valueOf(bulk));
}
private boolean getBulkRemove()
{
return ((Boolean) bulkRemove_.get()).booleanValue();
}
Object _getObject(Fqn fqn) throws CacheException
{
// TODO Must we really to couple with BR? JBCACHE-669
Object pojo = internal_.getPojoWithGravitation(fqn);
if (pojo != null)
{
// we already have an advised instance
return pojo;
}
// OK. So we are here meaning that this is a failover or passivation since the transient
// pojo instance is not around. Let's also make sure the right classloader is used
// as well.
ClassLoader prevCL = Thread.currentThread().getContextClassLoader();
try
{
if (cache_.getRegionManager() != null)
{
cache_.getRegionManager().setUnmarshallingClassLoader(fqn);
}
return _getObjectInternal(fqn);
}
finally
{
Thread.currentThread().setContextClassLoader(prevCL);
}
}
private Object _getObjectInternal(Fqn fqn) throws CacheException
{
// the class attribute is implicitly stored as an immutable read-only attribute
Class clazz = internal_.peekAopClazz(fqn);
// clazz and aopInstance can be not null if this node is the replicated brother node.
if (clazz == null)
return null;
/**
* Reconstruct the managed POJO
*/
CachedType type = cache_.getCachedType(clazz);
Object obj;
// Check for both Advised and Collection classes for object graph.
if ((obj = graphHandler_.objectGraphGet(fqn)) != null)
return obj; // retrieved from internal ref node. We are done.
AOPInstance aopInstance = internal_.getAopInstance(fqn);
if (aopInstance == null)
{
throw new RuntimeException("PojoCacheDelegate._getObject(): null AOPInstance.");
}
if (Advised.class.isAssignableFrom(clazz))
{
try
{
obj = clazz.newInstance();
// TODO Need to populate the object from the cache as well.
}
catch (Exception e)
{
throw new CacheException("failed creating instance of " + clazz.getName(), e);
}
// Insert interceptor at runtime
InstanceAdvisor advisor = ((Advised) obj)._getInstanceAdvisor();
CacheFieldInterceptor interceptor = new CacheFieldInterceptor(cache_, fqn, type);
interceptor.setAopInstance(aopInstance);
util_.attachInterceptor(obj, advisor, interceptor, observer_);
} else
{ // Must be Collection classes. We will use aop.ClassProxy instance instead.
try
{
if ((obj = collectionHandler_.collectionObjectGet(fqn, clazz)) != null)
{
} else
{
// Maybe it is just a serialized object.
obj = serializableHandler_.serializableObjectGet(fqn);
}
}
catch (Exception e)
{
throw new CacheException("failure creating proxy", e);
}
}
InternalDelegate.setPojo(aopInstance, obj);
return obj;
}
/**
* Note that caller of this method will take care of synchronization within the <code>fqn</code> sub-tree.
*
* @param fqn
* @param obj
* @return
* @throws CacheException
*/
Object _putObject(Fqn fqn, Object obj) throws CacheException
{
if (!cache_.isMarshallNonSerializable())
AopUtil.checkObjectType(obj);
if (obj == null)
{
return cache_._removeObject(fqn, true);
}
// Skip some un-necessary update if obj is the same class as the old one
Object oldValue = internal_.getPojo(fqn);
if (oldValue == obj) return obj; // value already in cache. return right away.
if (oldValue != null)
{
// Trigger bulk remove here for performance
setBulkRemove(true);
cache_._removeObject(fqn, true); // remove old value before overwriting it.
}
// Remember not to print obj here since it will trigger the CacheFieldInterceptor.
if (log.isDebugEnabled())
{
log.debug("putObject(): fqn: " + fqn);
}
// store object in cache
if (obj instanceof Advised)
{
CachedType type = cache_.getCachedType(obj.getClass());
// add interceptor
InstanceAdvisor advisor = ((Advised) obj)._getInstanceAdvisor();
if (advisor == null)
throw new RuntimeException("_putObject(): InstanceAdvisor is null for: " + obj);
// Step Check for cross references
Interceptor interceptor = AopUtil.findCacheInterceptor(advisor);
if (interceptor != null && graphHandler_.objectGraphPut(fqn, interceptor, type))
{ // found cross references
return oldValue;
}
// We have a clean slate then.
_regularPutObject(fqn, obj, advisor, type);
/**
* Handling collection classes here.
* First check if obj has been aspectized? That is, if it is a ClassProxy or not.
* If not, we will need to create a proxy first for the Collection classes
*/
} else if (collectionHandler_.collectionObjectPut(fqn, obj))
{
//
} else if (serializableHandler_.serializableObjectPut(fqn, obj))
{
// must be Serializable, including primitive types
} else
{
// I really don't know what this is.
throw new RuntimeException("putObject(): obj: " + obj + " type is not recognizable.");
}
return oldValue;
}
/**
* Based on the pojo to perform a bulk remove recursively if there is no object graph
* relationship for performance optimization.
*/
private boolean bulkRemove(Fqn fqn, Object obj) throws CacheException
{
// Check for cross-reference. If there is, we can't do bulk remove
// map contains (pojo, cacheinterceptor) pair that needs to undo the the removal.
// return false;
Map undoMap = new HashMap();
if (pojoGraphMultipleReferenced(obj, undoMap))
{
undoInterceptorDetach(undoMap);
return false;
} else
{
cache_.remove(fqn); // interceptor has been removed so it is safe to do bulk remove now.
}
return true;
}
private void detachInterceptor(InstanceAdvisor advisor, Interceptor interceptor,
boolean detachOnly, Map undoMap)
{
if (!detachOnly)
{
util_.detachInterceptor(advisor, interceptor, observer_);
undoMap.put(advisor, interceptor);
} else
{
undoMap.put(DETACH, interceptor);
}
}
private static void undoInterceptorDetach(Map undoMap)
{
for (Iterator it = undoMap.keySet().iterator(); it.hasNext();)
{
Object obj = it.next();
if (obj instanceof InstanceAdvisor)
{
InstanceAdvisor advisor = (InstanceAdvisor) obj;
BaseInterceptor interceptor = (BaseInterceptor) undoMap.get(advisor);
if (interceptor == null)
{
throw new IllegalStateException("PojoCacheDelegate.undoInterceptorDetach(): null interceptor");
}
advisor.appendInterceptor(interceptor);
} else
{
BaseInterceptor interceptor = (BaseInterceptor) undoMap.get(obj);
boolean copyToCache = false;
((AbstractCollectionInterceptor) interceptor).attach(null, copyToCache);
}
}
}
/**
* Check recursively if the pojo and its graph is multiple referenced. If it is, we can't
* do a bulk remove.
*/
private boolean pojoGraphMultipleReferenced(Object obj, Map undoMap) throws CacheException
{
// store object in cache
if (obj instanceof Advised)
{
CachedType type = cache_.getCachedType(obj.getClass());
// add interceptor
InstanceAdvisor advisor = ((Advised) obj)._getInstanceAdvisor();
if (advisor == null)
throw new RuntimeException("pojoGraphMultipleReferenced(): InstanceAdvisor is null for: " + obj);
BaseInterceptor interceptor = (BaseInterceptor) AopUtil.findCacheInterceptor(advisor);
// just in case
if (interceptor == null)
{
return false;
}
AOPInstance aopInstance = interceptor.getAopInstance();
// Check if there is cross referenced.
if (aopInstance.getRefCount() != 0) return true; // I have been referenced
if (aopInstance.getRefFqn() != null) return true; // I am referencing others
boolean hasFieldAnnotation = hasAnnotation(obj.getClass(), ((Advised) obj)._getAdvisor(), type);
// Check the fields
for (Iterator i = type.getFields().iterator(); i.hasNext();)
{
Field field = (Field) (((FieldPersistentReference) i.next())).get();
Object value = null;
try
{
value = field.get(obj);
}
catch (IllegalAccessException e)
{
throw new CacheException("field access failed", e);
}
CachedType fieldType = cache_.getCachedType(field.getType());
// we simply treat field that has @Serializable as a primitive type.
if (fieldType.isImmediate() ||
(hasFieldAnnotation &&
CachedType.hasSerializableAnnotation(field, ((Advised) obj)._getAdvisor())))
{
continue;
}
// check for non-replicatable types
if (CachedType.isPrimitiveNonReplicatable(field))
{
continue;
}
if (!hasFieldAnnotation)
{
if (CachedType.hasTransientAnnotation(field, ((Advised) obj)._getAdvisor()))
{
continue;
}
}
// Need to do a getObject just in case this is a failover removeObject.
if (value == null)
value = _getObject(new Fqn(interceptor.getFqn(), field.getName()));
if (value == null) continue; // this is no brainer.
if (pojoGraphMultipleReferenced(value, undoMap)) return true;
}
boolean detachOnly = false;
detachInterceptor(advisor, interceptor, detachOnly, undoMap);
} else if (obj instanceof Map || obj instanceof List || obj instanceof Set)
{
// TODO Is this really necessary?
if (!(obj instanceof ClassProxy)) return false;
InstanceAdvisor advisor = ((ClassProxy) obj)._getInstanceAdvisor();
BaseInterceptor interceptor = (BaseInterceptor) AopUtil.findCollectionInterceptor(advisor);
AOPInstance aopInstance = interceptor.getAopInstance();
if (aopInstance == null) return false; // safeguard
// Check if there is cross referenced.
if (aopInstance.getRefCount() != 0) return true; // I have been referenced
if (aopInstance.getRefFqn() != null) return true; // I am referencing others
// iterate thru the keys
if (obj instanceof Map)
{
for (Iterator it = ((Map) obj).keySet().iterator(); it.hasNext();)
{
Object subObj = ((Map) obj).get(it.next());
if (pojoGraphMultipleReferenced(subObj, undoMap)) return true;
}
} else if (obj instanceof List || obj instanceof Set)
{
for (Iterator it = ((Collection) obj).iterator(); it.hasNext();)
{
Object subObj = it.next();
if (pojoGraphMultipleReferenced(subObj, undoMap)) return true;
}
}
// Don't remove now.
boolean removeFromCache = false;
((AbstractCollectionInterceptor) interceptor).detach(removeFromCache); // detach the interceptor. This will trigger a copy and remove.
boolean detachOnly = true;
detachInterceptor(advisor, interceptor, detachOnly, undoMap);
}
return false;
}
private void _regularPutObject(Fqn fqn, Object obj, InstanceAdvisor advisor, CachedType type) throws CacheException
{
// TODO workaround for deserialiased objects
if (advisor == null)
{
advisor = new ClassInstanceAdvisor(obj);
((Advised) obj)._setInstanceAdvisor(advisor);
}
// Let's do batch update via Map instead
Map map = new HashMap();
// Always initialize the ref count so we can mark this as an AopNode.
AOPInstance aopInstance = InternalDelegate.initializeAopInstance();
// Insert interceptor at runtime
CacheFieldInterceptor interceptor = new CacheFieldInterceptor(cache_, fqn, type);
interceptor.setAopInstance(aopInstance);
util_.attachInterceptor(obj, advisor, interceptor, observer_);
map.put(AOPInstance.KEY, aopInstance);
// This is put into map first.
InternalDelegate.putAopClazz(type.getType(), map);
// we will do it recursively.
// Map of sub-objects that are non-primitive
Map subPojoMap = new HashMap();
boolean hasFieldAnnotation = hasAnnotation(obj.getClass(), ((Advised) obj)._getAdvisor(), type);
for (Iterator i = type.getFields().iterator(); i.hasNext();)
{
Field field = (Field) (((FieldPersistentReference) i.next())).get();
Object value = null;
try
{
value = field.get(obj);
}
catch (IllegalAccessException e)
{
throw new CacheException("field access failed", e);
}
CachedType fieldType = cache_.getCachedType(field.getType());
// check for non-replicatable types
if (CachedType.isPrimitiveNonReplicatable(field))
{
continue;
}
if (hasFieldAnnotation)
{
if (CachedType.hasTransientAnnotation(field, ((Advised) obj)._getAdvisor()))
{
continue;
}
}
// we simply treat field that has @Serializable as a primitive type.
if (fieldType.isImmediate() ||
(hasFieldAnnotation &&
CachedType.hasSerializableAnnotation(field, ((Advised) obj)._getAdvisor())))
{
// switched using batch update
map.put(field.getName(), value);
} else
{
subPojoMap.put(field, value);
}
}
// Use option to skip locking since we have parent lock already.
cache_.put(fqn, map, internal_.getLockOption());
// This is in-memory operation only
InternalDelegate.setPojo(aopInstance, obj);
for (Object o : subPojoMap.keySet())
{
Field field = (Field) o;
Object value = subPojoMap.get(field);
Fqn tmpFqn = new Fqn(fqn, field.getName());
_putObject(tmpFqn, value);
// If it is Collection classes, we replace it with dynamic proxy.
// But we will have to ignore it if value is null
if (value instanceof Map || value instanceof List || value instanceof Set)
{
Object newValue = cache_.getObject(tmpFqn);
util_.collectionReplaceWithProxy(obj, value, field, newValue);
}
}
// Need to make sure this is behind put such that obj.toString is done correctly.
if (log.isDebugEnabled())
{
log.debug("_regularPutObject(): inserting with fqn: " + fqn);
}
}
private static boolean hasAnnotation(Class clazz, Advisor advisor, CachedType type)
{
return CachedType.hasAnnotation(clazz, advisor, type);
}
/**
* Note that caller of this method will take care of synchronization within the <code>fqn</code> sub-tree.
*
* @param fqn
* @param removeCacheInterceptor
* @param evict
* @return
* @throws CacheException
*/
public Object _removeObject(Fqn fqn, boolean removeCacheInterceptor, boolean evict)
throws CacheException
{
Class clazz = internal_.peekAopClazz(fqn);
if (clazz == null)
{
if (log.isTraceEnabled())
{
log.trace("_removeObject(): clasz is null. fqn: " + fqn + " No need to remove.");
}
return null;
}
if (log.isDebugEnabled())
{
log.debug("_removeObject(): removing object from fqn: " + fqn);
}
Object result = cache_.getObject(fqn);
if (result == null)
{
// This is not a *Pojo*. Must be regular cache stuffs
if (cache_.exists(fqn))
{
// TODO What do we do here. It can still have children pojo though.
if (!evict)
{
cache_.remove(fqn);
} else
{
cache_._evict(fqn);
}
}
return null;
}
// can check if we need to do any bulk remove. E.g., if there is no object graph.
if (getBulkRemove())
{
if (bulkRemove(fqn, result))
{
// Remember not to print obj here since it will trigger the CacheFieldInterceptor.
if (log.isDebugEnabled())
{
log.debug("_removeObject(): fqn: " + fqn + "removing exisiting object in bulk.");
}
return result;
}
setBulkRemove(false);
}
if (graphHandler_.objectGraphRemove(fqn, removeCacheInterceptor, result, evict))
{
return result;
}
// Not multi-referenced
if (Advised.class.isAssignableFrom(clazz))
{
_regularRemoveObject(fqn, removeCacheInterceptor, result, clazz, evict);
} else if (collectionHandler_.collectionObjectRemove(fqn))
{
} else
{ // Just Serializable objects. Do a brute force remove is ok.
serializableHandler_.serializableObjectRemove();
}
internal_.cleanUp(fqn, evict);
// remove the interceptor as well.
return result;
}
private void _regularRemoveObject(Fqn fqn, boolean removeCacheInterceptor, Object result, Class clazz,
boolean evict) throws CacheException
{
InstanceAdvisor advisor = ((Advised) result)._getInstanceAdvisor();
CachedType type = cache_.getCachedType(clazz);
for (Iterator i = type.getFields().iterator(); i.hasNext();)
{
Field field = (Field) (((FieldPersistentReference) i.next())).get();
CachedType fieldType = cache_.getCachedType(field.getType());
if (!fieldType.isImmediate())
{
_removeObject(new Fqn(fqn, field.getName()), removeCacheInterceptor, evict);
}
}
// batch remove
cache_.removeData(fqn);
// Determine if we want to keep the interceptor for later use.
if (removeCacheInterceptor)
{
CacheFieldInterceptor interceptor = (CacheFieldInterceptor) AopUtil.findCacheInterceptor(advisor);
// Remember to remove the interceptor from in-memory object but make sure it belongs to me first.
if (interceptor != null)
{
if (log.isDebugEnabled())
{
log.debug("regularRemoveObject(): removed cache interceptor fqn: " + fqn + " interceptor: " + interceptor);
}
util_.detachInterceptor(advisor, interceptor, observer_);
}
}
}
boolean isAopNode(Fqn fqn)
{
try
{
return (internal_.isAopNode(fqn));
} catch (Exception e)
{
log.warn("isAopNode(): cache get operation generated exception " + e);
return false;
}
}
Map _findObjects(Fqn fqn) throws CacheException
{
// Traverse from fqn to do getObject, if it return a pojo we then stop.
Map map = new HashMap();
Object pojo = _getObject(fqn);
if (pojo != null)
{
map.put(fqn, pojo); // we are done!
return map;
}
findChildObjects(fqn, map);
if (log.isDebugEnabled())
{
log.debug("_findObjects(): Fqn: " + fqn + " size of pojos found: " + map.size());
}
return map;
}
private void findChildObjects(Fqn fqn, Map map) throws CacheException
{
// We need to traverse then
Set set = cache_.getChildrenNames(fqn);
if (set == null) return; // We stop here.
for (Object aSet : set)
{
String obj = (String) aSet;
Fqn newFqn = new Fqn(fqn, obj);
Object pojo = _getObject(newFqn);
if (pojo != null)
{
map.put(newFqn, pojo);
} else
{
findChildObjects(newFqn, map);
}
}
}
}
More information about the jboss-cvs-commits
mailing list