Author: jason.greene(a)jboss.com
Date: 2008-03-11 00:05:28 -0400 (Tue, 11 Mar 2008)
New Revision: 5410
Added:
pojo/trunk/src/main/java/org/jboss/cache/pojo/collection/CachedArray.java
pojo/trunk/src/main/java/org/jboss/cache/pojo/collection/CachedArrayRegistry.java
pojo/trunk/src/main/java/org/jboss/cache/pojo/collection/CachedObjectArray.java
pojo/trunk/src/main/java/org/jboss/cache/pojo/collection/CachedPrimitiveArray.java
pojo/trunk/src/main/java/org/jboss/cache/pojo/impl/AbstractHandler.java
pojo/trunk/src/main/java/org/jboss/cache/pojo/impl/ArrayHandler.java
pojo/trunk/src/main/java/org/jboss/cache/pojo/interceptors/dynamic/ArrayInterceptor.java
Modified:
pojo/trunk/src/main/java/org/jboss/cache/pojo/impl/AdvisedPojoHandler.java
pojo/trunk/src/main/java/org/jboss/cache/pojo/impl/CachedType.java
pojo/trunk/src/main/java/org/jboss/cache/pojo/impl/CollectionClassHandler.java
pojo/trunk/src/main/java/org/jboss/cache/pojo/impl/ObjectGraphHandler.java
pojo/trunk/src/main/java/org/jboss/cache/pojo/impl/PojoCacheDelegate.java
pojo/trunk/src/main/java/org/jboss/cache/pojo/impl/PojoCacheImpl.java
pojo/trunk/src/main/java/org/jboss/cache/pojo/impl/SerializableObjectHandler.java
pojo/trunk/src/main/java/org/jboss/cache/pojo/interceptors/dynamic/CacheFieldInterceptor.java
pojo/trunk/src/main/java/org/jboss/cache/pojo/util/AopUtil.java
pojo/trunk/src/main/resources/META-INF/pojocache-aop.xml
pojo/trunk/src/test/java/org/jboss/cache/pojo/ArrayTest.java
pojo/trunk/src/test/java/org/jboss/cache/pojo/ReplicatedByteTest.java
pojo/trunk/src/test/java/org/jboss/cache/pojo/test/ArrayObject.java
pojo/trunk/src/test/java/org/jboss/cache/pojo/test/Resource.java
Log:
Add initial support for array interception - PCACHE-13
Cleanup some of the code
Added: pojo/trunk/src/main/java/org/jboss/cache/pojo/collection/CachedArray.java
===================================================================
--- pojo/trunk/src/main/java/org/jboss/cache/pojo/collection/CachedArray.java
(rev 0)
+++ pojo/trunk/src/main/java/org/jboss/cache/pojo/collection/CachedArray.java 2008-03-11
04:05:28 UTC (rev 5410)
@@ -0,0 +1,124 @@
+/*
+* JBoss, Home of Professional Open Source
+* Copyright 2005, JBoss Inc., and individual contributors as indicated
+* by the @authors tag. See the copyright.txt in the distribution for a
+* full listing of individual contributors.
+*
+* This is free software; you can redistribute it and/or modify it
+* under the terms of the GNU Lesser General Public License as
+* published by the Free Software Foundation; either version 2.1 of
+* the License, or (at your option) any later version.
+*
+* This software is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this software; if not, write to the Free
+* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+* 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+*/
+package org.jboss.cache.pojo.collection;
+
+import java.lang.reflect.Array;
+
+import org.jboss.cache.CacheException;
+import org.jboss.cache.Fqn;
+import org.jboss.cache.pojo.impl.CachedType;
+import org.jboss.cache.pojo.impl.PojoCacheImpl;
+
+/**
+ * A CachedArray is the base class for cache backed array access. It replicates the Java
array contract.
+ *
+ * @author Jason T. Greene
+ */
+public abstract class CachedArray
+{
+ private static final String LENGTH = "ARRAY.LENGTH";
+ protected PojoCacheImpl cache;
+ protected Fqn<?> fqn;
+ private int length = -1;
+ private Class<?> type;
+
+ public static CachedArray load(Fqn<?> fqn, PojoCacheImpl cache, Class<?>
type)
+ {
+ boolean primitive = CachedType.isImmediate(type.getComponentType());
+ CachedArray array = primitive ? new CachedPrimitiveArray(fqn, type, cache) : new
CachedObjectArray(fqn, type, cache);
+ return array;
+ }
+
+ public static CachedArray create(Fqn<?> fqn, PojoCacheImpl cache, Object
originalArray)
+ {
+ Class<?> type = originalArray.getClass();
+ assert type.isArray();
+
+ Class<?> component = type.getComponentType();
+ boolean primitive = CachedType.isImmediate(component);
+ CachedArray array = primitive ? new CachedPrimitiveArray(fqn, type, cache) : new
CachedObjectArray(fqn, type, cache);
+
+ int length = Array.getLength(originalArray);
+ for (int c = 0; c < length; c++)
+ array.set(c, Array.get(originalArray, c));
+
+ array.length = length;
+ array.writeInfo();
+
+ return array;
+ }
+
+ protected CachedArray(Fqn<?> fqn, Class<?> type, PojoCacheImpl cache)
+ {
+ this.fqn = fqn;
+ this.type = type;
+ this.cache = cache;
+ }
+
+ public Fqn<?> getFqn()
+ {
+ return fqn;
+ }
+
+ public abstract void set(int index, Object element);
+
+ public abstract Object get(int index);
+
+ protected void writeInfo()
+ {
+ cache.getCache().put(fqn, LENGTH, length);
+ }
+
+ public void destroy()
+ {
+ cache.getCache().removeNode(fqn);
+ length = 0;
+ }
+
+ public int length()
+ {
+ if (length == -1)
+ {
+ Integer i = (Integer)cache.getCache().get(fqn, LENGTH);
+ length = i != null ? i.intValue() : 0;
+ }
+
+ return length;
+ }
+
+ public Object toArray()
+ {
+ try
+ {
+ int len = length();
+ Object array = Array.newInstance(type.getComponentType(), len);
+ for (int i = 0; i < len; i++)
+ Array.set(array, i, get(i));
+
+ return array;
+ }
+ catch (Exception e)
+ {
+ throw new CacheException("Could not construct array " + type);
+ }
+ }
+}
\ No newline at end of file
Added: pojo/trunk/src/main/java/org/jboss/cache/pojo/collection/CachedArrayRegistry.java
===================================================================
--- pojo/trunk/src/main/java/org/jboss/cache/pojo/collection/CachedArrayRegistry.java
(rev 0)
+++
pojo/trunk/src/main/java/org/jboss/cache/pojo/collection/CachedArrayRegistry.java 2008-03-11
04:05:28 UTC (rev 5410)
@@ -0,0 +1,51 @@
+/*
+* JBoss, Home of Professional Open Source
+* Copyright 2005, JBoss Inc., and individual contributors as indicated
+* by the @authors tag. See the copyright.txt in the distribution for a
+* full listing of individual contributors.
+*
+* This is free software; you can redistribute it and/or modify it
+* under the terms of the GNU Lesser General Public License as
+* published by the Free Software Foundation; either version 2.1 of
+* the License, or (at your option) any later version.
+*
+* This software is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this software; if not, write to the Free
+* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+* 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+*/
+package org.jboss.cache.pojo.collection;
+
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+/**
+ * A n internal registry which is responsible for mapping a Java array
+ * instance to a <code>CachedArray</code>.
+ *
+ * @author Jason T. Greene
+ */
+public class CachedArrayRegistry
+{
+ private static ConcurrentMap<Object, CachedArray> map = new
ConcurrentHashMap<Object, CachedArray>();
+
+ public static void register(Object array, CachedArray cached)
+ {
+ map.put(array, cached);
+ }
+
+ public static CachedArray unregister(Object array)
+ {
+ return map.remove(array);
+ }
+
+ public static CachedArray lookup(Object array)
+ {
+ return map.get(array);
+ }
+}
Added: pojo/trunk/src/main/java/org/jboss/cache/pojo/collection/CachedObjectArray.java
===================================================================
--- pojo/trunk/src/main/java/org/jboss/cache/pojo/collection/CachedObjectArray.java
(rev 0)
+++
pojo/trunk/src/main/java/org/jboss/cache/pojo/collection/CachedObjectArray.java 2008-03-11
04:05:28 UTC (rev 5410)
@@ -0,0 +1,64 @@
+/*
+* JBoss, Home of Professional Open Source
+* Copyright 2005, JBoss Inc., and individual contributors as indicated
+* by the @authors tag. See the copyright.txt in the distribution for a
+* full listing of individual contributors.
+*
+* This is free software; you can redistribute it and/or modify it
+* under the terms of the GNU Lesser General Public License as
+* published by the Free Software Foundation; either version 2.1 of
+* the License, or (at your option) any later version.
+*
+* This software is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this software; if not, write to the Free
+* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+* 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+*/
+package org.jboss.cache.pojo.collection;
+
+import org.jboss.cache.Fqn;
+import org.jboss.cache.pojo.impl.PojoCacheImpl;
+import org.jboss.cache.pojo.util.AopUtil;
+import org.jboss.cache.pojo.util.Null;
+
+/**
+ * A CachedObjectArray is used to back arrays with a component type that extends Object.
+ * It currently maps each array element to a cache Node, to support fine-grained
locking.
+ *
+ * @author Jason T. Greene
+ */
+public class CachedObjectArray extends CachedArray
+{
+ protected CachedObjectArray(Fqn<?> fqn, Class<?> type, PojoCacheImpl
cache)
+ {
+ super(fqn, type, cache);
+ }
+
+ public void set(int index, Object element)
+ {
+ Fqn<?> fqn = AopUtil.constructFqn(this.fqn, IntegerCache.toString(index));
+
+ cache.attach(fqn, Null.toNullObject(element));
+ }
+
+ public Object get(int index)
+ {
+ Fqn<?> fqn = AopUtil.constructFqn(this.fqn, IntegerCache.toString(index));
+
+ return Null.toNullValue(cache.find(fqn));
+ }
+
+ public void destroy()
+ {
+ // Detach all children to ensure reference cleanup
+ for (int i = 0; i < length(); i++)
+ cache.detach(AopUtil.constructFqn(this.fqn, IntegerCache.toString(i)));
+
+ super.destroy();
+ }
+}
Added: pojo/trunk/src/main/java/org/jboss/cache/pojo/collection/CachedPrimitiveArray.java
===================================================================
--- pojo/trunk/src/main/java/org/jboss/cache/pojo/collection/CachedPrimitiveArray.java
(rev 0)
+++
pojo/trunk/src/main/java/org/jboss/cache/pojo/collection/CachedPrimitiveArray.java 2008-03-11
04:05:28 UTC (rev 5410)
@@ -0,0 +1,51 @@
+/*
+* JBoss, Home of Professional Open Source
+* Copyright 2005, JBoss Inc., and individual contributors as indicated
+* by the @authors tag. See the copyright.txt in the distribution for a
+* full listing of individual contributors.
+*
+* This is free software; you can redistribute it and/or modify it
+* under the terms of the GNU Lesser General Public License as
+* published by the Free Software Foundation; either version 2.1 of
+* the License, or (at your option) any later version.
+*
+* This software is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this software; if not, write to the Free
+* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+* 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+*/
+package org.jboss.cache.pojo.collection;
+
+import org.jboss.cache.Fqn;
+import org.jboss.cache.pojo.impl.PojoCacheImpl;
+
+/**
+ * A CachedPrimitiveArray is used to back arrays which have primitive
+ * component types. These are currently mapped to attributes on a single node.
+ *
+ * @author Jason T. Greene
+ */
+public class CachedPrimitiveArray extends CachedArray
+{
+ private static final String ELEMENT = "ARRAY.PELEMENT.";
+
+ protected CachedPrimitiveArray(Fqn<?> fqn, Class<?> type, PojoCacheImpl
cache)
+ {
+ super(fqn, type, cache);
+ }
+
+ public void set(int index, Object element)
+ {
+ cache.getCache().put(fqn, ELEMENT + index, element);
+ }
+
+ public Object get(int index)
+ {
+ return cache.getCache().get(fqn, ELEMENT + index);
+ }
+}
\ No newline at end of file
Added: pojo/trunk/src/main/java/org/jboss/cache/pojo/impl/AbstractHandler.java
===================================================================
--- pojo/trunk/src/main/java/org/jboss/cache/pojo/impl/AbstractHandler.java
(rev 0)
+++ pojo/trunk/src/main/java/org/jboss/cache/pojo/impl/AbstractHandler.java 2008-03-11
04:05:28 UTC (rev 5410)
@@ -0,0 +1,43 @@
+/*
+* JBoss, Home of Professional Open Source
+* Copyright 2005, JBoss Inc., and individual contributors as indicated
+* by the @authors tag. See the copyright.txt in the distribution for a
+* full listing of individual contributors.
+*
+* This is free software; you can redistribute it and/or modify it
+* under the terms of the GNU Lesser General Public License as
+* published by the Free Software Foundation; either version 2.1 of
+* the License, or (at your option) any later version.
+*
+* This software is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this software; if not, write to the Free
+* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+* 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+*/
+package org.jboss.cache.pojo.impl;
+
+import org.jboss.cache.Fqn;
+
+abstract class AbstractHandler
+{
+
+ public AbstractHandler()
+ {
+ super();
+ }
+
+ protected abstract boolean handles(Class<?> clazz);
+
+ protected abstract Object remove(Fqn<?> fqn, Fqn<?> referenceingFqn,
Object result);
+
+ protected abstract void put(Fqn<?> fqn, Fqn<?> referencingFqn, Object
obj);
+
+ protected abstract Object get(Fqn<?> fqn, Class<?> clazz, PojoInstance
pojoInstance);
+
+ protected abstract Fqn<?> getFqn(Object obj);
+}
\ No newline at end of file
Modified: pojo/trunk/src/main/java/org/jboss/cache/pojo/impl/AdvisedPojoHandler.java
===================================================================
--- pojo/trunk/src/main/java/org/jboss/cache/pojo/impl/AdvisedPojoHandler.java 2008-03-11
01:48:44 UTC (rev 5409)
+++ pojo/trunk/src/main/java/org/jboss/cache/pojo/impl/AdvisedPojoHandler.java 2008-03-11
04:05:28 UTC (rev 5410)
@@ -1,10 +1,24 @@
/*
- * JBoss, Home of Professional Open Source
- *
- * Distributable under LGPL license.
- * See terms of license at
gnu.org.
- */
-
+* JBoss, Home of Professional Open Source
+* Copyright 2005, JBoss Inc., and individual contributors as indicated
+* by the @authors tag. See the copyright.txt in the distribution for a
+* full listing of individual contributors.
+*
+* This is free software; you can redistribute it and/or modify it
+* under the terms of the GNU Lesser General Public License as
+* published by the Free Software Foundation; either version 2.1 of
+* the License, or (at your option) any later version.
+*
+* This software is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this software; if not, write to the Free
+* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+* 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+*/
package org.jboss.cache.pojo.impl;
import java.lang.reflect.Field;
@@ -22,6 +36,8 @@
import org.jboss.cache.Cache;
import org.jboss.cache.CacheException;
import org.jboss.cache.Fqn;
+import org.jboss.cache.pojo.PojoCacheException;
+import org.jboss.cache.pojo.interceptors.dynamic.BaseInterceptor;
import org.jboss.cache.pojo.interceptors.dynamic.CacheFieldInterceptor;
import org.jboss.cache.pojo.memory.FieldPersistentReference;
import org.jboss.cache.pojo.util.AopUtil;
@@ -35,7 +51,7 @@
* Date: Aug 4, 2005
* @version $Id$
*/
-class AdvisedPojoHandler
+class AdvisedPojoHandler extends AbstractHandler
{
private final Log log = LogFactory.getLog(AdvisedPojoHandler.class);
private Cache<Object, Object> cache_;
@@ -49,8 +65,27 @@
cache_ = pCache_.getCache();
util_ = util;
}
+
+ @Override
+ protected Fqn<?> getFqn(Object obj)
+ {
+ if (obj instanceof Advised)
+ {
+ InstanceAdvisor advisor = ((Advised) obj)._getInstanceAdvisor();
+ if (advisor == null)
+ throw new PojoCacheException("_putObject(): InstanceAdvisor is null for:
" + obj);
+
+ // Step Check for cross references
+ BaseInterceptor interceptor = AopUtil.findCacheInterceptor(advisor);
+ if (interceptor != null)
+ return interceptor.getFqn();
+ }
+
+ return null;
+ }
- public Object get(Fqn<?> fqn, Class<?> clazz, PojoInstance pojoInstance)
throws CacheException
+ @Override
+ protected Object get(Fqn<?> fqn, Class<?> clazz, PojoInstance
pojoInstance) throws CacheException
{
CachedType type = pCache_.getCachedType(clazz);
Object obj = Instantiator.newInstance(clazz);
@@ -84,7 +119,8 @@
return obj;
}
- void put(Fqn<?> fqn, Fqn<?> referencingFqn, Object obj) throws
CacheException
+ @Override
+ protected void put(Fqn<?> fqn, Fqn<?> referencingFqn, Object obj) throws
CacheException
{
CachedType type = pCache_.getCachedType(obj.getClass());
// We have a clean slate then.
@@ -168,9 +204,10 @@
}
}
- Object remove(Fqn<?> fqn, Object result, Class<?> clazz) throws
CacheException
+ @Override
+ protected Object remove(Fqn<?> fqn, Fqn<?> referencingFqn, Object result)
throws CacheException
{
- CachedType type = pCache_.getCachedType(clazz);
+ CachedType type = pCache_.getCachedType(result.getClass());
InstanceAdvisor advisor = ((Advised) result)._getInstanceAdvisor();
for (Iterator i = type.getFields().iterator(); i.hasNext();)
{
@@ -196,8 +233,7 @@
}
}
- // batch remove
- cache_.getRoot().getChild(fqn).clearData();
+ cache_.removeNode(fqn);
// Determine if we want to keep the interceptor for later use.
CacheFieldInterceptor interceptor = (CacheFieldInterceptor)
AopUtil.findCacheInterceptor(advisor);
// Remember to remove the interceptor from in-memory object but make sure it
belongs to me first.
@@ -210,6 +246,12 @@
util_.detachInterceptor(advisor, interceptor);
}
- return null; // Not really null though.
+ return result;
}
+
+ @Override
+ protected boolean handles(Class<?> clazz)
+ {
+ return Advised.class.isAssignableFrom(clazz);
+ }
}
Added: pojo/trunk/src/main/java/org/jboss/cache/pojo/impl/ArrayHandler.java
===================================================================
--- pojo/trunk/src/main/java/org/jboss/cache/pojo/impl/ArrayHandler.java
(rev 0)
+++ pojo/trunk/src/main/java/org/jboss/cache/pojo/impl/ArrayHandler.java 2008-03-11
04:05:28 UTC (rev 5410)
@@ -0,0 +1,88 @@
+/*
+* JBoss, Home of Professional Open Source
+* Copyright 2005, JBoss Inc., and individual contributors as indicated
+* by the @authors tag. See the copyright.txt in the distribution for a
+* full listing of individual contributors.
+*
+* This is free software; you can redistribute it and/or modify it
+* under the terms of the GNU Lesser General Public License as
+* published by the Free Software Foundation; either version 2.1 of
+* the License, or (at your option) any later version.
+*
+* This software is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this software; if not, write to the Free
+* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+* 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+*/
+package org.jboss.cache.pojo.impl;
+
+import org.jboss.cache.Fqn;
+import org.jboss.cache.pojo.collection.CachedArray;
+import org.jboss.cache.pojo.collection.CachedArrayRegistry;
+
+/**
+ * Handles array types.
+ *
+ * @author Jason T. Greene
+ */
+public class ArrayHandler extends AbstractHandler
+{
+ private final PojoCacheImpl cache;
+
+ ArrayHandler(PojoCacheImpl cache)
+ {
+ this.cache = cache;
+ }
+
+ protected Fqn<?> getFqn(Object array)
+ {
+ CachedArray cached = CachedArrayRegistry.lookup(array);
+ return cached != null ? cached.getFqn() : null;
+ }
+
+
+ protected void put(Fqn<?> fqn, Fqn<?> referencingFqn, Object obj)
+ {
+ // Always initialize the ref count so that we can mark this as an AopNode.
+ PojoInstance pojoInstance = InternalHelper.initializeAopInstance(referencingFqn);
+ pojoInstance.set(obj);
+ pojoInstance.setPojoClass(obj.getClass());
+ cache.getCache().put(fqn, PojoInstance.KEY, pojoInstance);
+
+ CachedArray cached = CachedArray.create(fqn, cache, obj);
+ CachedArrayRegistry.register(obj, cached);
+ }
+
+ @Override
+ protected Object get(Fqn<?> fqn, Class<?> clazz, PojoInstance pojo)
+ {
+ CachedArray cached = CachedArray.load(fqn, cache, clazz);
+ Object array = cached.toArray();
+ CachedArrayRegistry.register(array, cached);
+
+ return array;
+ }
+
+ @Override
+ protected Object remove(Fqn<?> fqn, Fqn<?> referencingFqn, Object obj)
+ {
+ CachedArray cached = CachedArrayRegistry.unregister(obj);
+ if (cached != null)
+ cached.destroy();
+
+ return obj;
+ }
+
+ @Override
+ protected boolean handles(Class<?> clazz)
+ {
+ return false;
+ //return clazz.isArray();
+ }
+
+}
Modified: pojo/trunk/src/main/java/org/jboss/cache/pojo/impl/CachedType.java
===================================================================
--- pojo/trunk/src/main/java/org/jboss/cache/pojo/impl/CachedType.java 2008-03-11 01:48:44
UTC (rev 5409)
+++ pojo/trunk/src/main/java/org/jboss/cache/pojo/impl/CachedType.java 2008-03-11 04:05:28
UTC (rev 5410)
@@ -82,7 +82,7 @@
return immediate;
}
- private static boolean isImmediate(Class clazz)
+ public static boolean isImmediate(Class clazz)
{
// Treat enums as a simple type since they serialize to a simple string
return immediates.contains(clazz) || Enum.class.isAssignableFrom(clazz);
Modified: pojo/trunk/src/main/java/org/jboss/cache/pojo/impl/CollectionClassHandler.java
===================================================================
---
pojo/trunk/src/main/java/org/jboss/cache/pojo/impl/CollectionClassHandler.java 2008-03-11
01:48:44 UTC (rev 5409)
+++
pojo/trunk/src/main/java/org/jboss/cache/pojo/impl/CollectionClassHandler.java 2008-03-11
04:05:28 UTC (rev 5410)
@@ -7,24 +7,23 @@
package org.jboss.cache.pojo.impl;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
-import org.jboss.aop.advice.Interceptor;
import org.jboss.aop.proxy.ClassProxy;
import org.jboss.cache.Cache;
import org.jboss.cache.CacheException;
-import org.jboss.cache.CacheSPI;
import org.jboss.cache.Fqn;
import org.jboss.cache.pojo.PojoCacheException;
import org.jboss.cache.pojo.collection.CollectionInterceptorUtil;
import org.jboss.cache.pojo.interceptors.dynamic.AbstractCollectionInterceptor;
import org.jboss.cache.pojo.interceptors.dynamic.BaseInterceptor;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
/**
* Handling the Collection class management. Has no consideration of object graph here.
*
@@ -32,7 +31,7 @@
* Date: Aug 4, 2005
* @version $Id$
*/
-class CollectionClassHandler
+class CollectionClassHandler extends AbstractHandler
{
private final Log log = LogFactory.getLog(CollectionClassHandler.class);
private Cache<Object, Object> cache_;
@@ -45,8 +44,17 @@
cache_ = pCache_.getCache();
internal_ = internal;
}
+
+ protected Fqn<?> getFqn(Object collection)
+ {
+ if (! (collection instanceof ClassProxy))
+ return null;
+
+ BaseInterceptor interceptor = CollectionInterceptorUtil.getInterceptor((ClassProxy)
collection);
+ return interceptor != null ? interceptor.getFqn() : null;
+ }
- Object get(Fqn fqn, Class clazz, PojoInstance pojoInstance)
+ protected Object get(Fqn fqn, Class clazz, PojoInstance pojoInstance)
throws CacheException
{
Object obj = null;
@@ -76,7 +84,7 @@
return obj;
}
- void put(Fqn fqn, Fqn referencingFqn, Object obj) throws CacheException
+ protected void put(Fqn fqn, Fqn referencingFqn, Object obj) throws CacheException
{
boolean isCollection = false;
@@ -260,17 +268,26 @@
}
}
- Object remove(Fqn fqn, Object obj) throws CacheException
+ @Override
+ protected Object remove(Fqn<?> fqn, Fqn<?> referencingFqn, Object obj)
throws CacheException
{
if (!(obj instanceof ClassProxy))
{
throw new
PojoCacheException("CollectionClassHandler.collectionRemoveObject(): object is not a
proxy :" + obj);
}
- Interceptor interceptor = CollectionInterceptorUtil.getInterceptor((ClassProxy)
obj);
- boolean removeFromCache = true;
+ AbstractCollectionInterceptor interceptor = (AbstractCollectionInterceptor)
CollectionInterceptorUtil.getInterceptor((ClassProxy) obj);
// detach the interceptor. This will trigger a copy and remove.
- ((AbstractCollectionInterceptor) interceptor).detach(removeFromCache);
- return ((AbstractCollectionInterceptor) interceptor).getCurrentCopy();
+ interceptor.detach(true);
+ cache_.removeNode(fqn);
+
+ return interceptor.getCurrentCopy();
}
+
+
+ @Override
+ protected boolean handles(Class<?> clazz)
+ {
+ return Collection.class.isAssignableFrom(clazz) ||
Map.class.isAssignableFrom(clazz);
+ }
}
Modified: pojo/trunk/src/main/java/org/jboss/cache/pojo/impl/ObjectGraphHandler.java
===================================================================
--- pojo/trunk/src/main/java/org/jboss/cache/pojo/impl/ObjectGraphHandler.java 2008-03-11
01:48:44 UTC (rev 5409)
+++ pojo/trunk/src/main/java/org/jboss/cache/pojo/impl/ObjectGraphHandler.java 2008-03-11
04:05:28 UTC (rev 5410)
@@ -9,18 +9,9 @@
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
-import org.jboss.aop.Advised;
-import org.jboss.aop.InstanceAdvisor;
-import org.jboss.aop.advice.Interceptor;
-import org.jboss.aop.proxy.ClassProxy;
-import org.jboss.cache.Cache;
import org.jboss.cache.CacheException;
-import org.jboss.cache.CacheSPI;
import org.jboss.cache.Fqn;
import org.jboss.cache.pojo.PojoCacheException;
-import org.jboss.cache.pojo.collection.CollectionInterceptorUtil;
-import org.jboss.cache.pojo.interceptors.dynamic.BaseInterceptor;
-import org.jboss.cache.pojo.util.AopUtil;
/**
* Handle the object graph management.
@@ -29,7 +20,7 @@
* Date: Aug 4, 2005
* @version $Id$
*/
-class ObjectGraphHandler
+class ObjectGraphHandler extends AbstractHandler
{
private PojoCacheImpl cache;
private InternalHelper internal_;
@@ -40,8 +31,19 @@
this.cache = cache;
internal_ = internal;
}
+
+ protected Fqn<?> getFqn(Object obj)
+ {
+ return null;
+ }
+
+ protected boolean handles(Class<?> clazz)
+ {
+ return false;
+ }
- Object get(Fqn fqn, Class clazz, PojoInstance pojoInstance) throws CacheException
+ @Override
+ protected Object get(Fqn<?> fqn, Class<?> clazz, PojoInstance
pojoInstance) throws CacheException
{
// Note this is actually the aliasFqn, not the real fqn!
Object obj;
@@ -54,44 +56,13 @@
return obj; // No need to set the instance under fqn. It is located in refFqn
anyway.
}
- void put(Fqn fqn, Object obj, String field) throws CacheException
+ @Override
+ protected void put(Fqn<?> fqn, Fqn<?> referencingFqn, Object obj) throws
CacheException
{
- CachedType type = cache.getCachedType(obj.getClass());
-
- InstanceAdvisor advisor = null;
- Interceptor interceptor = null;
-
- if (obj instanceof Advised)
- {
- advisor = ((Advised) obj)._getInstanceAdvisor();
- if (advisor == null)
- throw new PojoCacheException("put(): InstanceAdvisor is null for: "
+ obj);
- // Step Check for cross references
- interceptor = AopUtil.findCacheInterceptor(advisor);
- }
- else
- {
- advisor = ((ClassProxy) obj)._getInstanceAdvisor();
- if (advisor == null)
- throw new PojoCacheException("put(): InstanceAdvisor is null for: "
+ obj);
- interceptor = CollectionInterceptorUtil.getInterceptor((ClassProxy) obj);
- }
-
- Fqn originalFqn = null;
-
- // ah, found something. So this will be multiple referenced.
- originalFqn = ((BaseInterceptor) interceptor).getFqn();
-
- // This will increment the ref count, reset, and add ref fqn in the current fqn
node.
- setupRefCounting(fqn, originalFqn);
- // Store a PojoReference in the external fqn node
- PojoReference pojoReference = new PojoReference();
- pojoReference.setFqn(originalFqn);
- pojoReference.setPojoClass(type.getType());
- internal_.putPojoReference(fqn, pojoReference, field);
+ setupRefCounting(fqn, referencingFqn);
}
- boolean isMultipleReferenced(Fqn internalFqn)
+ boolean isMultipleReferenced(Fqn<?> internalFqn)
{
// Note this is actually the aliasFqn, not the real fqn!
PojoInstance pojoInstance = null;
@@ -108,7 +79,8 @@
}
- void remove(Fqn referencingFqn, Fqn internalFqn, Object pojo)
+ @Override
+ protected Object remove(Fqn<?> fqn, Fqn<?> referencingFqn, Object pojo)
throws CacheException
{
if (log.isDebugEnabled())
@@ -116,22 +88,24 @@
log.debug("remove(): removing object fqn: " + referencingFqn
+ " Will just de-reference it.");
}
- removeFromReference(referencingFqn, internalFqn);
+ removeFromReference(fqn, referencingFqn);
+
+ return null;
}
/**
* Remove the object from the the reference fqn, meaning just decrement the ref
counter.
*/
- private void removeFromReference(Fqn referencingFqn, Fqn originalFqn) throws
CacheException
+ private void removeFromReference(Fqn<?> originalFqn, Fqn<?>
referencingFqn) throws CacheException
{
- synchronized (referencingFqn)
+ synchronized (originalFqn)
{ // we lock the internal fqn here so no one else has access.
// Decrement ref counting on the internal node
- if (decrementRefCount(referencingFqn, originalFqn) ==
PojoInstance.INITIAL_COUNTER_VALUE)
+ if (decrementRefCount(originalFqn, referencingFqn) ==
PojoInstance.INITIAL_COUNTER_VALUE)
{
// No one is referring it so it is safe to remove
// TODO we should make sure the parent nodes are also removed they are empty
as well.
- cache.detach(referencingFqn);
+ cache.detach(originalFqn);
}
}
}
@@ -143,26 +117,21 @@
* @param fqn The original fqn node
* @param refFqn The new internal fqn node
*/
- private void setupRefCounting(Fqn fqn, Fqn refFqn) throws CacheException
+ private void setupRefCounting(Fqn<?> fqn, Fqn<?> referencingFqn) throws
CacheException
{
- synchronized (refFqn)
- { // we lock the ref fqn here so no one else has access.
+ synchronized (fqn)
+ {
// increment the reference counting
- incrementRefCount(refFqn, fqn);
- // set the internal fqn in fqn so we can reference it.
- if (log.isTraceEnabled())
- {
- log.trace("setupRefCounting(): current fqn: " + fqn + " set to
point to: " + refFqn);
- }
+ incrementRefCount(fqn, referencingFqn);
}
}
- private int incrementRefCount(Fqn originalFqn, Fqn referencingFqn) throws
CacheException
+ private int incrementRefCount(Fqn<?> originalFqn, Fqn<?> referencingFqn)
throws CacheException
{
return internal_.incrementRefCount(originalFqn, referencingFqn);
}
- private int decrementRefCount(Fqn referencingFqn, Fqn originalFqn) throws
CacheException
+ private int decrementRefCount(Fqn<?> originalFqn, Fqn<?> referencingFqn)
throws CacheException
{
int count = 0;
if ((count = internal_.decrementRefCount(originalFqn, referencingFqn)) ==
(PojoInstance.INITIAL_COUNTER_VALUE + 1))
Modified: pojo/trunk/src/main/java/org/jboss/cache/pojo/impl/PojoCacheDelegate.java
===================================================================
--- pojo/trunk/src/main/java/org/jboss/cache/pojo/impl/PojoCacheDelegate.java 2008-03-11
01:48:44 UTC (rev 5409)
+++ pojo/trunk/src/main/java/org/jboss/cache/pojo/impl/PojoCacheDelegate.java 2008-03-11
04:05:28 UTC (rev 5410)
@@ -48,6 +48,7 @@
private AdvisedPojoHandler advisedHandler_;
private ObjectGraphHandler graphHandler_;
private CollectionClassHandler collectionHandler_;
+ private ArrayHandler arrayHandler;
private SerializableObjectHandler serializableHandler_;
// Use ThreadLocal to hold a boolean isBulkRemove
private ThreadLocal<Boolean> bulkRemove_ = new ThreadLocal<Boolean>();
@@ -63,6 +64,7 @@
collectionHandler_ = new CollectionClassHandler(pojoCache, internal_);
serializableHandler_ = new SerializableObjectHandler(pojoCache, internal_);
advisedHandler_ = new AdvisedPojoHandler(pojoCache, internal_, util_);
+ arrayHandler = new ArrayHandler(pojoCache);
}
public void setBulkRemove(boolean bulk)
@@ -107,29 +109,14 @@
}
}
- public Object putObjectI(Fqn fqn, Object obj, String field) throws CacheException
- {
- // Skip some un-necessary update if obj is the same class as the old one
- Object oldValue = internal_.getPojo(fqn, field);
- if (oldValue == obj && (obj instanceof Advised || obj instanceof
ClassProxy))
- {
- if (log.isDebugEnabled())
- {
- log.debug("putObject(): id: " + fqn + " pojo is already in the
cache. Return right away.");
- }
- return obj;
- }
- return null;
- }
-
/**
* Note that caller of this method will take care of synchronization within the
<code>fqn</code> sub-tree.
*/
- public Object putObjectII(Fqn fqn, Object obj, String field) throws CacheException
+ public Object putObject(Fqn fqn, Object obj, String field) throws CacheException
{
// Skip some un-necessary update if obj is the same class as the old one
Object oldValue = internal_.getPojo(fqn, field);
- if (oldValue == obj)
+ if (oldValue == obj && skipDuplicateAttach(obj))
{
if (log.isDebugEnabled())
{
@@ -143,59 +130,63 @@
pojoCache.detach(fqn, field);
if (obj == null)
- {
return oldValue;// we are done
- }
- // creates the internal node first without going thru the interceptor.
- // This way we don't block on __JBossInternal__ node.
- //createChildNodeFirstWithoutLocking(internalFqn);
-
- if ((obj instanceof Advised || obj instanceof ClassProxy) &&
isMultipleReferencedPut(obj))
+ AbstractHandler handler = getHandler(obj.getClass());
+ Fqn<?> internalFqn = handler.getFqn(obj);
+
+ if (internalFqn != null)
{
- // we pass in the originating fqn intentionaly
- graphHandler_.put(fqn, obj, field);
+ graphHandler_.put(internalFqn, fqn, obj);
}
else
{
- Fqn internalFqn = createInternalFqn(fqn, obj);
- if (log.isDebugEnabled())
- {
- log.debug("putObject(): id: " + fqn + " will store the pojo in
the internal area: "
- + internalFqn);
- }
+ internalFqn = createInternalFqn(fqn, obj);
+ if (log.isDebugEnabled())
+ log.debug("attach(): id: " + fqn + " will store the pojo in
the internal area: " + internalFqn);
+
+ handler.put(internalFqn, fqn, obj);
- if (obj instanceof Advised)
- {
- advisedHandler_.put(internalFqn, fqn, obj);
- }
- else if (isCollection(obj))
- {
- collectionHandler_.put(internalFqn, fqn, obj);
- //
- }
- else
- {
- // must be Serializable, including primitive types
- serializableHandler_.put(internalFqn, obj);
- }
-
// Used by notification sub-system
cache.put(internalFqn, InternalConstant.POJOCACHE_STATUS,
"ATTACHED");
-
- setPojoReference(fqn, obj, field, internalFqn);
}
+
+ setPojoReference(fqn, obj, field, internalFqn);
return oldValue;
}
+
+ private boolean skipDuplicateAttach(Object obj)
+ {
+ return obj == null || getHandler(obj.getClass()) != serializableHandler_;
+ }
+
+ private AbstractHandler getHandler(Class<?> clazz)
+ {
+ if (advisedHandler_.handles(clazz))
+ return advisedHandler_;
+
+ if (collectionHandler_.handles(clazz))
+ return collectionHandler_;
+
+ if (arrayHandler.handles(clazz))
+ return arrayHandler;
+
+ if (serializableHandler_.handles(clazz))
+ return serializableHandler_;
+
+ throw new CacheException("Can not manage object. It must be either
instrumented, a collection, an array, or Serializable: "
+ + clazz.getName());
+ }
+
- Fqn createInternalFqn(Fqn fqn, Object obj) throws CacheException
+ private Fqn createInternalFqn(Fqn fqn, Object obj) throws CacheException
{
// Create an internal Fqn name
return AopUtil.createInternalFqn(fqn, cache);
}
- Fqn setPojoReference(Fqn fqn, Object obj, String field, Fqn internalFqn) throws
CacheException
+ private Fqn setPojoReference(Fqn fqn, Object obj, String field, Fqn internalFqn)
throws CacheException
{
// Create PojoReference
CachedType type = pojoCache.getCachedType(obj.getClass());
@@ -249,8 +240,7 @@
return null;
}
- Class clazz = pojoReference.getPojoClass();
- Fqn internalFqn = pojoReference.getFqn();
+ Fqn<?> internalFqn = pojoReference.getFqn();
if (log.isDebugEnabled())
{
@@ -260,37 +250,20 @@
Object result = pojoCache.getObject(internalFqn);
if (result == null)
- {
return null;
- }
if (graphHandler_.isMultipleReferenced(internalFqn))
{
- graphHandler_.remove(fqn, internalFqn, result);
+ graphHandler_.remove(internalFqn, fqn, result);
}
else
{
cache.put(internalFqn, InternalConstant.POJOCACHE_STATUS,
"DETACHING");
- if (Advised.class.isAssignableFrom(clazz))
- {
- advisedHandler_.remove(internalFqn, result, clazz);
- internal_.cleanUp(internalFqn, null);
- }
- else if (isCollectionGet(clazz))
- {
- // We need to return the original reference
- result = collectionHandler_.remove(internalFqn, result);
- internal_.cleanUp(internalFqn, null);
- }
- else
- {// Just Serializable objects. Do a brute force remove is ok.
- serializableHandler_.remove();
- internal_.cleanUp(internalFqn, null);
- }
+
+ result = getHandler(result.getClass()).remove(internalFqn, fqn, result);
}
internal_.cleanUp(fqn, field);
- // remove the interceptor as well.
return result;
}
@@ -314,9 +287,9 @@
return map;
}
- private Object getObjectInternal(Fqn fqn, String field) throws CacheException
+ private Object getObjectInternal(Fqn<?> fqn, String field) throws
CacheException
{
- Fqn internalFqn = fqn;
+ Fqn<?> internalFqn = fqn;
PojoReference pojoReference = internal_.getPojoReference(fqn, field);
if (pojoReference != null)
{
@@ -341,115 +314,13 @@
return null;
//throw new PojoCacheException("PojoCacheDelegate.getObjectInternal(): null
PojoInstance for fqn: " + internalFqn);
- Class clazz = pojoInstance.getPojoClass();
+ Class<?> clazz = pojoInstance.getPojoClass();
+ obj = getHandler(clazz).get(internalFqn, clazz, pojoInstance);
- // Check for both Advised and Collection classes for object graph.
- // Note: no need to worry about multiple referencing here. If there is a graph, we
won't come this far.
- if (Advised.class.isAssignableFrom(clazz))
- {
- obj = advisedHandler_.get(internalFqn, clazz, pojoInstance);
- }
- else if (isCollectionGet(clazz))
- {// Must be Collection classes. We will use aop.ClassProxy instance instead.
- obj = collectionHandler_.get(internalFqn, clazz, pojoInstance);
- }
- else
- {
- // Maybe it is just a serialized object.
- obj = serializableHandler_.get(internalFqn, clazz, pojoInstance);
- }
-
InternalHelper.setPojo(pojoInstance, obj);
return obj;
}
- private boolean isCollectionGet(Class clazz)
- {
- if (Map.class.isAssignableFrom(clazz) || Collection.class.isAssignableFrom(clazz))
- {
- return true;
- }
-
- return false;
- }
-
-
- private boolean isMultipleReferencedPut(Object obj)
- {
- Interceptor interceptor = null;
- if (obj instanceof Advised)
- {
- InstanceAdvisor advisor = ((Advised) obj)._getInstanceAdvisor();
- if (advisor == null)
- {
- throw new PojoCacheException("_putObject(): InstanceAdvisor is null for:
" + obj);
- }
-
- // Step Check for cross references
- interceptor = AopUtil.findCacheInterceptor(advisor);
- }
- else
- {
- interceptor = CollectionInterceptorUtil.getInterceptor((ClassProxy) obj);
- }
- if (interceptor == null) return false;
-
- Fqn originalFqn = null;
-
- // ah, found something. So this will be multiple referenced.
- originalFqn = ((BaseInterceptor) interceptor).getFqn();
-
- return originalFqn != null;
-
- }
-
- private boolean isCollection(Object obj)
- {
- return obj instanceof Collection || obj instanceof Map;
-
- }
-
- private void detachInterceptor(InstanceAdvisor advisor, Interceptor interceptor,
- boolean detachOnly, Map undoMap)
- {
- if (!detachOnly)
- {
- util_.detachInterceptor(advisor, interceptor);
- 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);
- }
- }
- }
-
private void findChildObjects(Fqn fqn, Map map) throws CacheException
{
// We need to traverse then
Modified: pojo/trunk/src/main/java/org/jboss/cache/pojo/impl/PojoCacheImpl.java
===================================================================
--- pojo/trunk/src/main/java/org/jboss/cache/pojo/impl/PojoCacheImpl.java 2008-03-11
01:48:44 UTC (rev 5409)
+++ pojo/trunk/src/main/java/org/jboss/cache/pojo/impl/PojoCacheImpl.java 2008-03-11
04:05:28 UTC (rev 5410)
@@ -125,17 +125,9 @@
/**
* This public API is called from internal package only.
*/
- public Object putObject(Fqn<?> id, Object pojo, String field)
- throws CacheException
+ public Object putObject(Fqn<?> id, Object pojo, String field) throws
CacheException
{
- Object obj = null;
-
- // Maybe this is the same instance already.
- obj = delegate_.putObjectI(id, pojo, field);
- if (obj != null) return obj;
-
- obj = delegate_.putObjectII(id, pojo, field);
- return obj;
+ return delegate_.putObject(id, pojo, field);
}
public Object detach(String id) throws PojoCacheException
Modified:
pojo/trunk/src/main/java/org/jboss/cache/pojo/impl/SerializableObjectHandler.java
===================================================================
---
pojo/trunk/src/main/java/org/jboss/cache/pojo/impl/SerializableObjectHandler.java 2008-03-11
01:48:44 UTC (rev 5409)
+++
pojo/trunk/src/main/java/org/jboss/cache/pojo/impl/SerializableObjectHandler.java 2008-03-11
04:05:28 UTC (rev 5410)
@@ -7,6 +7,7 @@
package org.jboss.cache.pojo.impl;
+import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
@@ -23,7 +24,7 @@
* @author Ben Wang
* @version $Id$
*/
-class SerializableObjectHandler
+class SerializableObjectHandler extends AbstractHandler
{
private Cache<Object, Object> cache;
private PojoCacheImpl pojoCache;
@@ -36,17 +37,29 @@
this.cache = pojoCache.getCache();
internal_ = internal;
}
+
+ protected Fqn<?> getFqn(Object obj)
+ {
+ // Not supported
+ return null;
+ }
+
+ @Override
+ protected boolean handles(Class<?> clazz)
+ {
+ return Serializable.class.isAssignableFrom(clazz);
+ }
- Object get(Fqn fqn, Class clazz, PojoInstance pojoInstance)
- throws CacheException
+ @Override
+ protected Object get(Fqn fqn, Class clazz, PojoInstance pojoInstance) throws
CacheException
{
Object obj = internal_.get(fqn, InternalConstant.SERIALIZED);
return obj;
}
- boolean put(Fqn fqn, Object obj)
- throws CacheException
+ @Override
+ protected void put(Fqn<?> fqn, Fqn<?> referencingFqn, Object obj) throws
CacheException
{
// Note that JBoss Serialization can serialize any type now.
if (log_.isDebugEnabled())
@@ -56,7 +69,6 @@
}
putIntoCache(fqn, obj);
- return true;
}
private void putIntoCache(Fqn fqn, Object obj)
@@ -74,10 +86,10 @@
internal_.put(fqn, map);
}
- @SuppressWarnings({"CanBeStatic"})
- void remove()
+ @Override
+ protected Object remove(Fqn<?> fqn, Fqn<?> referenceingFqn, Object result)
throws CacheException
{
- // No need to do anything here since we will do clean up afterwards.
+ cache.removeNode(fqn);
+ return result;
}
-
-}
+}
\ No newline at end of file
Added:
pojo/trunk/src/main/java/org/jboss/cache/pojo/interceptors/dynamic/ArrayInterceptor.java
===================================================================
---
pojo/trunk/src/main/java/org/jboss/cache/pojo/interceptors/dynamic/ArrayInterceptor.java
(rev 0)
+++
pojo/trunk/src/main/java/org/jboss/cache/pojo/interceptors/dynamic/ArrayInterceptor.java 2008-03-11
04:05:28 UTC (rev 5410)
@@ -0,0 +1,86 @@
+/*
+* JBoss, Home of Professional Open Source
+* Copyright 2005, JBoss Inc., and individual contributors as indicated
+* by the @authors tag. See the copyright.txt in the distribution for a
+* full listing of individual contributors.
+*
+* This is free software; you can redistribute it and/or modify it
+* under the terms of the GNU Lesser General Public License as
+* published by the Free Software Foundation; either version 2.1 of
+* the License, or (at your option) any later version.
+*
+* This software is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this software; if not, write to the Free
+* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+* 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+*/
+package org.jboss.cache.pojo.interceptors.dynamic;
+
+import org.jboss.aop.advice.Interceptor;
+import org.jboss.aop.array.ArrayElementReadInvocation;
+import org.jboss.aop.array.ArrayElementWriteInvocation;
+import org.jboss.aop.array.ArrayRegistry;
+import org.jboss.aop.joinpoint.Invocation;
+import org.jboss.cache.pojo.collection.CachedArray;
+import org.jboss.cache.pojo.collection.CachedArrayRegistry;
+
+/**
+ * AOP interceptor which delegates to POJO Cache
+ *
+ * @author Jason T. Greene
+ */
+public class ArrayInterceptor implements Interceptor
+{
+
+ /* (non-Javadoc)
+ * @see org.jboss.aop.advice.Interceptor#getName()
+ */
+ public String getName()
+ {
+ // TODO Auto-generated method stub
+ return this.getClass().getName();
+ }
+
+ /* (non-Javadoc)
+ * @see org.jboss.aop.advice.Interceptor#invoke(org.jboss.aop.joinpoint.Invocation)
+ */
+ public Object invoke(Invocation invocation) throws Throwable
+ {
+ if (invocation instanceof ArrayElementReadInvocation)
+ {
+ ArrayElementReadInvocation read = (ArrayElementReadInvocation)invocation;
+ Object array = read.getTargetObject();
+ CachedArray cached = CachedArrayRegistry.lookup(array);
+ if (cached != null)
+ {
+ int index = read.getIndex();
+ Object element = cached.get(index);
+
+ // AOP only registers on write, work around for now
+ if (element != null && element.getClass().isArray())
+ ArrayRegistry.getInstance().addElementReference(array, index, element);
+
+ return element;
+ }
+ }
+ else if (invocation instanceof ArrayElementWriteInvocation)
+ {
+ ArrayElementWriteInvocation write = (ArrayElementWriteInvocation) invocation;
+ Object array = write.getTargetObject();
+ CachedArray cached = CachedArrayRegistry.lookup(array);
+ if (cached != null)
+ {
+ cached.set(write.getIndex(), write.getValue());
+ return null;
+ }
+ }
+
+ return invocation.invokeNext();
+ }
+
+}
Modified:
pojo/trunk/src/main/java/org/jboss/cache/pojo/interceptors/dynamic/CacheFieldInterceptor.java
===================================================================
---
pojo/trunk/src/main/java/org/jboss/cache/pojo/interceptors/dynamic/CacheFieldInterceptor.java 2008-03-11
01:48:44 UTC (rev 5409)
+++
pojo/trunk/src/main/java/org/jboss/cache/pojo/interceptors/dynamic/CacheFieldInterceptor.java 2008-03-11
04:05:28 UTC (rev 5410)
@@ -12,6 +12,7 @@
import org.apache.commons.logging.LogFactory;
import org.jboss.aop.Advisor;
import org.jboss.aop.advice.Interceptor;
+import org.jboss.aop.array.ArrayRegistry;
import org.jboss.aop.joinpoint.FieldInvocation;
import org.jboss.aop.joinpoint.FieldReadInvocation;
import org.jboss.aop.joinpoint.FieldWriteInvocation;
@@ -20,6 +21,8 @@
import org.jboss.cache.Cache;
import org.jboss.cache.Fqn;
import org.jboss.cache.pojo.PojoCacheAlreadyDetachedException;
+import org.jboss.cache.pojo.collection.CachedArray;
+import org.jboss.cache.pojo.collection.CachedArrayRegistry;
import org.jboss.cache.pojo.impl.CachedType;
import org.jboss.cache.pojo.impl.PojoCacheImpl;
import org.jboss.cache.pojo.impl.PojoInstance;
@@ -93,10 +96,10 @@
// Kind of ad hoc now. MethodInvocation should not invoke this.
if (invocation instanceof MethodInvocation)
return invocation.invokeNext();
-
-
+
if (invocation instanceof FieldWriteInvocation)
{
+ Object target = invocation.getTargetObject();
FieldInvocation fieldInvocation =
(FieldInvocation) invocation;
@@ -107,7 +110,7 @@
log_.trace("invoke(): field write interception for fqn: " + fqn_ +
" and field: " + field);
}
- verifyAttached(invocation.getTargetObject());
+ verifyAttached(target);
// Only if this field is replicatable. static, transient and final are not.
CachedType fieldType = pCache_.getCachedType(field.getType());
@@ -124,11 +127,11 @@
}
}
- Object obj = fieldInvocation.getTargetObject();
- util_.inMemorySubstitution(obj, field, value);
+ util_.inMemorySubstitution(target, field, value);
}
else if (invocation instanceof FieldReadInvocation)
{
+ Object target = invocation.getTargetObject();
FieldInvocation fieldInvocation =
(FieldInvocation) invocation;
Field field = fieldInvocation.getField();
@@ -146,14 +149,18 @@
else
{
result = pCache_.getObject(fqn_, field.getName());
+
+ // Work around AOP issue with field reads
+ if (result != null && result.getClass().isArray())
+ registerArrayWithAOP(target, field.getName(), result);
}
// If the result is null, the object might have been detached
if (result == null)
- verifyAttached(invocation.getTargetObject());
+ verifyAttached(target);
// Update last known state associated with this pojo.
- util_.inMemorySubstitution(invocation.getTargetObject(), field, result);
+ util_.inMemorySubstitution(target, field, result);
// Allow interceptor chain to process, but ignore the result
invocation.invokeNext();
@@ -165,6 +172,13 @@
return invocation.invokeNext();
}
+ private void registerArrayWithAOP(Object owner, String fieldName, Object array)
+ {
+ CachedArray cached = CachedArrayRegistry.lookup(array);
+ if (cached != null)
+ ArrayRegistry.getInstance().addFieldReference(owner, fieldName, array);
+ }
+
/**
* Check if the pojo is detached already.
*/
Modified: pojo/trunk/src/main/java/org/jboss/cache/pojo/util/AopUtil.java
===================================================================
--- pojo/trunk/src/main/java/org/jboss/cache/pojo/util/AopUtil.java 2008-03-11 01:48:44
UTC (rev 5409)
+++ pojo/trunk/src/main/java/org/jboss/cache/pojo/util/AopUtil.java 2008-03-11 04:05:28
UTC (rev 5410)
@@ -67,7 +67,7 @@
* @param advisor
* @return Interceptor
*/
- static public Interceptor findCacheInterceptor(InstanceAdvisor advisor)
+ static public CacheFieldInterceptor findCacheInterceptor(InstanceAdvisor advisor)
{
// TODO we assume there is only one interceptor now.
Interceptor[] interceptors = advisor.getInterceptors();
@@ -77,7 +77,7 @@
Interceptor interceptor = interceptors[i];
if (interceptor instanceof CacheFieldInterceptor)
{
- return interceptor;
+ return (CacheFieldInterceptor)interceptor;
}
}
return null;
Modified: pojo/trunk/src/main/resources/META-INF/pojocache-aop.xml
===================================================================
--- pojo/trunk/src/main/resources/META-INF/pojocache-aop.xml 2008-03-11 01:48:44 UTC (rev
5409)
+++ pojo/trunk/src/main/resources/META-INF/pojocache-aop.xml 2008-03-11 04:05:28 UTC (rev
5410)
@@ -145,5 +145,13 @@
<prepare expr="field(*
$instanceof{(a)org.jboss.cache.pojo.annotation.Replicable}->*)" />
<!-- Work around that ensures annotated classes which do not access fields are
instrumented -->
- <introduction
expr="class($instanceof{(a)org.jboss.cache.pojo.annotation.Replicable})"/>
-</aop>
\ No newline at end of file
+ <introduction
expr="class($instanceof{(a)org.jboss.cache.pojo.annotation.Replicable})"/>
+
+ <!-- Array support
+ <arrayreplacement
expr="class($instanceof{(a)org.jboss.cache.pojo.annotation.Replicable})"/>
+ <interceptor name="array"
class="org.jboss.cache.pojo.interceptors.dynamic.ArrayInterceptor"/>
+ <arraybind type="READ_WRITE">
+ <interceptor-ref name="array"/>
+ </arraybind>
+ -->
+</aop>
Modified: pojo/trunk/src/test/java/org/jboss/cache/pojo/ArrayTest.java
===================================================================
--- pojo/trunk/src/test/java/org/jboss/cache/pojo/ArrayTest.java 2008-03-11 01:48:44 UTC
(rev 5409)
+++ pojo/trunk/src/test/java/org/jboss/cache/pojo/ArrayTest.java 2008-03-11 04:05:28 UTC
(rev 5410)
@@ -8,10 +8,25 @@
package org.jboss.cache.pojo;
+import java.util.HashMap;
+
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.jboss.cache.config.Configuration.CacheMode;
+import org.jboss.cache.factories.UnitTestCacheConfigurationFactory;
+import org.jboss.cache.notifications.annotation.CacheListener;
+import org.jboss.cache.notifications.annotation.NodeActivated;
+import org.jboss.cache.notifications.annotation.NodeCreated;
+import org.jboss.cache.notifications.annotation.NodeModified;
+import org.jboss.cache.notifications.annotation.NodePassivated;
+import org.jboss.cache.notifications.annotation.NodeRemoved;
+import org.jboss.cache.notifications.annotation.NodeVisited;
+import org.jboss.cache.notifications.event.NodeEvent;
+import org.jboss.cache.notifications.event.NodeModifiedEvent;
+import org.jboss.cache.notifications.event.NodeVisitedEvent;
import org.jboss.cache.pojo.test.ArrayObject;
-import org.jboss.cache.pojo.test.Person;
+import org.jboss.cache.pojo.test.ArrayObject.Person;
+import org.testng.AssertJUnit;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
@@ -25,22 +40,26 @@
public class ArrayTest
{
Log log = LogFactory.getLog(ArrayTest.class);
- PojoCache cache_;
+ PojoCache cache1, cache2;
@BeforeMethod(alwaysRun = true)
protected void setUp() throws Exception
{
log.info("setUp() ....");
- String configFile = "META-INF/local-service.xml";
- boolean toStart = false;
- cache_ = PojoCacheFactory.createCache(configFile, toStart);
- cache_.start();
+ cache1 =
PojoCacheFactory.createCache(UnitTestCacheConfigurationFactory.createConfiguration(CacheMode.REPL_SYNC),
false);
+ cache1.getCache().addCacheListener(new MyCacheListener(false));
+ cache1.start();
+
+ cache2 =
PojoCacheFactory.createCache(UnitTestCacheConfigurationFactory.createConfiguration(CacheMode.REPL_SYNC),
false);
+ cache2.getCache().addCacheListener(new MyCacheListener(true));
+ cache2.start();
+
}
@AfterMethod(alwaysRun = true)
protected void tearDown() throws Exception
{
- cache_.stop();
+ cache1.stop();
}
public void testSimple() throws Exception
@@ -57,14 +76,61 @@
ao.setPerson(0, joe);
- cache_.attach("ao", ao);
+ cache1.attach("/ao", ao);
- // TODO This should trigger a write on team but instead it does a read only. Why?
ao.setPerson(1, ben);
+ ao.setPerson(2, joe);
+ ao.setPerson(3, ben);
+ ao.setPerson(4, joe);
+ ao.setPerson(5, ben);
+
+ AssertJUnit.assertSame(ao.getPerson(1), ben);
+ AssertJUnit.assertSame(ao.getPerson(2), joe);
+ AssertJUnit.assertSame(ao.getPerson(3), ben);
+ AssertJUnit.assertSame(ao.getPerson(4), joe);
+ AssertJUnit.assertSame(ao.getPerson(5), ben);
+
+ ArrayObject obj = (ArrayObject) cache2.find("/ao");
+ Person person = obj.getPerson(4);
+ obj.setPerson(5, person);
+ AssertJUnit.assertSame(ao.getPerson(5), ao.getPerson(4));
+
+ ao.setNum(5, 4);
+ AssertJUnit.assertEquals(4, obj.getNum(5));
+ }
+ @CacheListener
+ public class MyCacheListener
+ {
+ private boolean visits;
+
+ public MyCacheListener(boolean visits)
+ {
+ this.visits = visits;
+ }
+
+ @NodeActivated
+ @NodePassivated
+ @NodeCreated
+ @NodeRemoved
+ @NodeVisited
+ public void print(NodeEvent ne)
+ {
+ if (visits != ne instanceof NodeVisitedEvent)
+ return;
+
+ if (!ne.isPre())
+ System.out.println((!visits ? "[one] " : "[two] ") +
ne.getType() + " " + ne.getFqn());
+ }
+
+ @NodeModified
+ public void print(NodeModifiedEvent ne)
+ {
+ if (!visits && !ne.isPre())
+ System.out.println((!visits ? "[one] " : "[two] ") +
ne.getType() + " " + ne.getFqn() + " - " + new
HashMap(ne.getData()));
+ }
}
-
}
Modified: pojo/trunk/src/test/java/org/jboss/cache/pojo/ReplicatedByteTest.java
===================================================================
--- pojo/trunk/src/test/java/org/jboss/cache/pojo/ReplicatedByteTest.java 2008-03-11
01:48:44 UTC (rev 5409)
+++ pojo/trunk/src/test/java/org/jboss/cache/pojo/ReplicatedByteTest.java 2008-03-11
04:05:28 UTC (rev 5410)
@@ -80,13 +80,12 @@
Resource res1 = (Resource) cache1.find("resource");
assertEquals("Name ", res.getName(), res1.getName());
- assertEquals("byte ", res.getByte()[0], res1.getByte()[0]);
+ assertEquals("byte ", res.getByte(0), res1.getByte(0));
// field modification
by = 2;
- b[0] = by;
- res1.setByte(b);
+ res.setByte(0, by);
assertEquals("Name ", res.getName(), res1.getName());
- assertEquals("byte ", res.getByte()[0], res1.getByte()[0]);
+ assertEquals("byte ", res.getByte(0), res1.getByte(0));
}
}
Modified: pojo/trunk/src/test/java/org/jboss/cache/pojo/test/ArrayObject.java
===================================================================
--- pojo/trunk/src/test/java/org/jboss/cache/pojo/test/ArrayObject.java 2008-03-11
01:48:44 UTC (rev 5409)
+++ pojo/trunk/src/test/java/org/jboss/cache/pojo/test/ArrayObject.java 2008-03-11
04:05:28 UTC (rev 5410)
@@ -7,17 +7,46 @@
package org.jboss.cache.pojo.test;
+import java.io.Serializable;
+
/**
*/
// We are using JDK1.5 annotation.
@org.jboss.cache.pojo.annotation.Replicable
public class ArrayObject
{
+ // Support array interception and serializable
+ @org.jboss.cache.pojo.annotation.Replicable
+ public static class Person implements Serializable
+ {
+ private static final long serialVersionUID = 1L;
+ private String name;
+ private int age;
+
+ public String getName()
+ {
+ return name;
+ }
+ public void setName(String name)
+ {
+ this.name = name;
+ }
+ public int getAge()
+ {
+ return age;
+ }
+ public void setAge(int age)
+ {
+ this.age = age;
+ }
+ }
private Person[] team;
+ private int[] nums;
public ArrayObject()
{
team = new Person[10];
+ nums = new int[] {1,2,3,4,5,6,7,8,9};
}
public Person[] getTeam()
@@ -29,14 +58,35 @@
{
team = t;
}
+
+ public void setNum(int index, int value)
+ {
+ int nums[] = this.nums;
+ nums[index] = value;
+
+ // This will be optimized away if array interception is enabled
+ this.nums = nums;
+ }
+
+ public int getNum(int index)
+ {
+ return nums[index];
+ }
public Person getPerson(int index)
{
- return team[index];
+ Object o = team[index];
+ return (Person)o;
}
public void setPerson(int index, Person p)
{
- team[index] = p;
+ Person[] array = team;
+ array[index] = p;
+
+ // This will be optimized away if array interception is enabled
+ team = array;
}
}
+
+
Modified: pojo/trunk/src/test/java/org/jboss/cache/pojo/test/Resource.java
===================================================================
--- pojo/trunk/src/test/java/org/jboss/cache/pojo/test/Resource.java 2008-03-11 01:48:44
UTC (rev 5409)
+++ pojo/trunk/src/test/java/org/jboss/cache/pojo/test/Resource.java 2008-03-11 04:05:28
UTC (rev 5410)
@@ -52,6 +52,21 @@
{
bin = b;
}
+
+ public void setByte(int index, byte b)
+ {
+ byte[] array = bin;
+ array[index] = b;
+
+ // This will be optimized away if array interception is enabled
+ // However, it is needed if it is disabled (since serialization is used then)
+ bin = array;
+ }
+
+ public byte getByte(int index)
+ {
+ return bin[index];
+ }
public String toString()
{