[jboss-cvs] JBossCache/src/org/jboss/cache/pojo/impl ...
Jason Thomas Greene
jgreene at jboss.com
Wed May 30 02:08:02 EDT 2007
User: jgreene
Date: 07/05/30 02:08:02
Modified: src/org/jboss/cache/pojo/impl
AdvisedPojoHandler.java CollectionClassHandler.java
InternalHelper.java ObjectGraphHandler.java
PojoCacheDelegate.java PojoCacheImpl.java
SerializableObjectHandler.java
Added: src/org/jboss/cache/pojo/impl
CacheListenerAdaptor.java CachedType.java
InternalConstant.java MethodDeclarations.java
NotificationDispatcher.java PojoInstance.java
PojoReference.java PojoUtil.java Referrer.java
Log:
Switch to new notification system
Resolve jmx test failure
ensure that the pojo package is api only
Revision Changes Path
1.6 +2 -6 JBossCache/src/org/jboss/cache/pojo/impl/AdvisedPojoHandler.java
(In the diff below, changes in quantity of whitespace are not shown.)
Index: AdvisedPojoHandler.java
===================================================================
RCS file: /cvsroot/jboss/JBossCache/src/org/jboss/cache/pojo/impl/AdvisedPojoHandler.java,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -b -r1.5 -r1.6
--- AdvisedPojoHandler.java 23 May 2007 10:28:49 -0000 1.5
+++ AdvisedPojoHandler.java 30 May 2007 06:08:01 -0000 1.6
@@ -16,10 +16,6 @@
import org.jboss.cache.CacheException;
import org.jboss.cache.CacheSPI;
import org.jboss.cache.Fqn;
-import org.jboss.cache.pojo.CachedType;
-import org.jboss.cache.pojo.InternalConstant;
-import org.jboss.cache.pojo.PojoInstance;
-import org.jboss.cache.pojo.PojoUtil;
import org.jboss.cache.pojo.interceptors.dynamic.CacheFieldInterceptor;
import org.jboss.cache.pojo.memory.FieldPersistentReference;
import org.jboss.cache.pojo.util.AopUtil;
@@ -36,7 +32,7 @@
*
* @author Ben Wang
* Date: Aug 4, 2005
- * @version $Id: AdvisedPojoHandler.java,v 1.5 2007/05/23 10:28:49 msurtani Exp $
+ * @version $Id: AdvisedPojoHandler.java,v 1.6 2007/05/30 06:08:01 jgreene Exp $
*/
class AdvisedPojoHandler
{
1.3 +1 -3 JBossCache/src/org/jboss/cache/pojo/impl/CollectionClassHandler.java
(In the diff below, changes in quantity of whitespace are not shown.)
Index: CollectionClassHandler.java
===================================================================
RCS file: /cvsroot/jboss/JBossCache/src/org/jboss/cache/pojo/impl/CollectionClassHandler.java,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -b -r1.2 -r1.3
--- CollectionClassHandler.java 23 May 2007 10:28:49 -0000 1.2
+++ CollectionClassHandler.java 30 May 2007 06:08:01 -0000 1.3
@@ -14,9 +14,7 @@
import org.jboss.cache.CacheException;
import org.jboss.cache.CacheSPI;
import org.jboss.cache.Fqn;
-import org.jboss.cache.pojo.CachedType;
import org.jboss.cache.pojo.PojoCacheException;
-import org.jboss.cache.pojo.PojoInstance;
import org.jboss.cache.pojo.collection.CollectionInterceptorUtil;
import org.jboss.cache.pojo.interceptors.dynamic.AbstractCollectionInterceptor;
import org.jboss.cache.pojo.interceptors.dynamic.BaseInterceptor;
@@ -31,7 +29,7 @@
*
* @author Ben Wang
* Date: Aug 4, 2005
- * @version $Id: CollectionClassHandler.java,v 1.2 2007/05/23 10:28:49 msurtani Exp $
+ * @version $Id: CollectionClassHandler.java,v 1.3 2007/05/30 06:08:01 jgreene Exp $
*/
class CollectionClassHandler
{
1.5 +0 -3 JBossCache/src/org/jboss/cache/pojo/impl/InternalHelper.java
(In the diff below, changes in quantity of whitespace are not shown.)
Index: InternalHelper.java
===================================================================
RCS file: /cvsroot/jboss/JBossCache/src/org/jboss/cache/pojo/impl/InternalHelper.java,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -b -r1.4 -r1.5
--- InternalHelper.java 24 May 2007 13:11:10 -0000 1.4
+++ InternalHelper.java 30 May 2007 06:08:01 -0000 1.5
@@ -12,10 +12,7 @@
import org.jboss.cache.CacheSPI;
import org.jboss.cache.Fqn;
import org.jboss.cache.config.Option;
-import org.jboss.cache.pojo.InternalConstant;
import org.jboss.cache.pojo.PojoCacheException;
-import org.jboss.cache.pojo.PojoInstance;
-import org.jboss.cache.pojo.PojoReference;
import org.jboss.cache.pojo.util.ObjectUtil;
import java.util.Map;
1.5 +1 -4 JBossCache/src/org/jboss/cache/pojo/impl/ObjectGraphHandler.java
(In the diff below, changes in quantity of whitespace are not shown.)
Index: ObjectGraphHandler.java
===================================================================
RCS file: /cvsroot/jboss/JBossCache/src/org/jboss/cache/pojo/impl/ObjectGraphHandler.java,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -b -r1.4 -r1.5
--- ObjectGraphHandler.java 23 May 2007 10:28:49 -0000 1.4
+++ ObjectGraphHandler.java 30 May 2007 06:08:01 -0000 1.5
@@ -16,10 +16,7 @@
import org.jboss.cache.CacheException;
import org.jboss.cache.CacheSPI;
import org.jboss.cache.Fqn;
-import org.jboss.cache.pojo.CachedType;
import org.jboss.cache.pojo.PojoCacheException;
-import org.jboss.cache.pojo.PojoInstance;
-import org.jboss.cache.pojo.PojoReference;
import org.jboss.cache.pojo.collection.CollectionInterceptorUtil;
import org.jboss.cache.pojo.interceptors.dynamic.BaseInterceptor;
import org.jboss.cache.pojo.util.AopUtil;
@@ -29,7 +26,7 @@
*
* @author Ben Wang
* Date: Aug 4, 2005
- * @version $Id: ObjectGraphHandler.java,v 1.4 2007/05/23 10:28:49 msurtani Exp $
+ * @version $Id: ObjectGraphHandler.java,v 1.5 2007/05/30 06:08:01 jgreene Exp $
*/
class ObjectGraphHandler
{
1.8 +33 -32 JBossCache/src/org/jboss/cache/pojo/impl/PojoCacheDelegate.java
(In the diff below, changes in quantity of whitespace are not shown.)
Index: PojoCacheDelegate.java
===================================================================
RCS file: /cvsroot/jboss/JBossCache/src/org/jboss/cache/pojo/impl/PojoCacheDelegate.java,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -b -r1.7 -r1.8
--- PojoCacheDelegate.java 23 May 2007 10:28:49 -0000 1.7
+++ PojoCacheDelegate.java 30 May 2007 06:08:01 -0000 1.8
@@ -17,11 +17,7 @@
import org.jboss.cache.CacheSPI;
import org.jboss.cache.Fqn;
import org.jboss.cache.Node;
-import org.jboss.cache.pojo.CachedType;
import org.jboss.cache.pojo.PojoCacheException;
-import org.jboss.cache.pojo.PojoInstance;
-import org.jboss.cache.pojo.PojoReference;
-import org.jboss.cache.pojo.PojoUtil;
import org.jboss.cache.pojo.collection.CollectionInterceptorUtil;
import org.jboss.cache.pojo.interceptors.dynamic.AbstractCollectionInterceptor;
import org.jboss.cache.pojo.interceptors.dynamic.BaseInterceptor;
@@ -182,6 +178,9 @@
serializableHandler_.put(internalFqn, obj);
}
+ // Used by notification sub-system
+ cache_.put(internalFqn, InternalConstant.POJOCACHE_STATUS, "ATTACHED");
+
setPojoReference(fqn, obj, field, internalFqn);
}
@@ -267,7 +266,10 @@
{
graphHandler_.remove(fqn, internalFqn, result);
}
- else if (Advised.class.isAssignableFrom(clazz))
+ else
+ {
+ cache_.put(internalFqn, InternalConstant.POJOCACHE_STATUS, "DETACHING");
+ if (Advised.class.isAssignableFrom(clazz))
{
advisedHandler_.remove(internalFqn, result, clazz);
internal_.cleanUp(internalFqn, null);
@@ -283,6 +285,7 @@
serializableHandler_.remove();
internal_.cleanUp(internalFqn, null);
}
+ }
internal_.cleanUp(fqn, field);
// remove the interceptor as well.
@@ -311,22 +314,19 @@
private Object getObjectInternal(Fqn fqn, String field) throws CacheException
{
- // the class attribute is implicitly stored as an immutable read-only attribute
+ Fqn internalFqn = fqn;
PojoReference pojoReference = internal_.getPojoReference(fqn, field);
- if (pojoReference == null)
+ if (pojoReference != null)
+ {
+ internalFqn = pojoReference.getFqn();
+ }
+ else if (field != null)
{
- // clazz and pojoReference can be not null if this node is the replicated brother node.
return null;
}
- // This is the real location for the pojo.
- Fqn internalFqn = pojoReference.getFqn();
- Class clazz = pojoReference.getPojoClass();
if (log.isDebugEnabled())
- {
- log.debug("getObject(): id: " + fqn + " with a corresponding internal id: "
- + internalFqn);
- }
+ log.debug("getObject(): id: " + fqn + " with a corresponding internal id: " + internalFqn);
/**
* Reconstruct the managed POJO
@@ -334,11 +334,12 @@
Object obj;
PojoInstance pojoInstance = internal_.getAopInstance(internalFqn);
+
if (pojoInstance == null)
- {
- throw new PojoCacheException("PojoCacheDelegate.getObjectInternal(): null PojoInstance for fqn: " +
- internalFqn);
- }
+ return null;
+ //throw new PojoCacheException("PojoCacheDelegate.getObjectInternal(): null PojoInstance for fqn: " + internalFqn);
+
+ Class clazz = pojoInstance.getPojoClass();
// 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.
1.10 +30 -120 JBossCache/src/org/jboss/cache/pojo/impl/PojoCacheImpl.java
(In the diff below, changes in quantity of whitespace are not shown.)
Index: PojoCacheImpl.java
===================================================================
RCS file: /cvsroot/jboss/JBossCache/src/org/jboss/cache/pojo/impl/PojoCacheImpl.java,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -b -r1.9 -r1.10
--- PojoCacheImpl.java 23 May 2007 15:22:04 -0000 1.9
+++ PojoCacheImpl.java 30 May 2007 06:08:01 -0000 1.10
@@ -7,10 +7,13 @@
package org.jboss.cache.pojo.impl;
+import java.util.Collection;
+import java.util.Map;
+import java.util.WeakHashMap;
+import java.util.regex.Pattern;
+
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
-import org.jboss.aop.Advised;
-import org.jboss.aop.proxy.ClassProxy;
import org.jboss.cache.Cache;
import org.jboss.cache.CacheException;
import org.jboss.cache.CacheSPI;
@@ -19,31 +22,18 @@
import org.jboss.cache.Version;
import org.jboss.cache.config.Configuration;
import org.jboss.cache.factories.XmlConfigurationParser;
-import org.jboss.cache.pojo.CachedType;
import org.jboss.cache.pojo.PojoCache;
import org.jboss.cache.pojo.PojoCacheException;
import org.jboss.cache.pojo.PojoCacheListener;
import org.jboss.cache.pojo.annotation.Attach;
import org.jboss.cache.pojo.annotation.Detach;
import org.jboss.cache.pojo.annotation.Find;
-import org.jboss.cache.pojo.notification.AttachNotification;
-import org.jboss.cache.pojo.notification.DetachNotification;
-import org.jboss.cache.pojo.notification.Notification;
-import org.jboss.cache.pojo.notification.NotificationContext;
-
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Set;
-import java.util.WeakHashMap;
-import java.util.concurrent.CopyOnWriteArraySet;
/**
* Implementation class for PojoCache interface
*
* @author Ben Wang
- * @version $Id: PojoCacheImpl.java,v 1.9 2007/05/23 15:22:04 msurtani Exp $
+ * @version $Id: PojoCacheImpl.java,v 1.10 2007/05/30 06:08:01 jgreene Exp $
*/
public class PojoCacheImpl implements PojoCache
{
@@ -54,17 +44,7 @@
// use WeakHashMap to allow class reloading
private Map cachedTypes_ = new WeakHashMap();
private boolean hasCreate_ = false;
-
- /**
- * Set of TreeCacheListener.
- *
- * @see #addListener
- */
- private final Set listeners = new CopyOnWriteArraySet();
- /**
- * True if listeners are initialized.
- */
- protected boolean hasListeners = false;
+ private CacheListenerAdaptor listenerAdaptor = new CacheListenerAdaptor(this);
public PojoCacheImpl(String configStr, boolean toStart)
{
@@ -153,9 +133,7 @@
obj = delegate_.putObjectI(id, pojo, field);
if (obj != null) return obj;
- notifyAttach(pojo, true);
obj = delegate_.putObjectII(id, pojo, field);
- notifyAttach(pojo, false);
return obj;
}
@@ -172,9 +150,7 @@
Object pojo = getObject(id, field);// TODO need optimization here since it will be redundant here
if (pojo == null) return pojo;
- notifyDetach(pojo, true);
Object obj = removeObject(id, field);
- notifyDetach(pojo, false);
return obj;
}
catch (CacheException e)
@@ -297,40 +273,40 @@
cache_.destroy();
}
- public void addListener(PojoCacheListener listener)
- {
- // synchronize on listenrs just to
- // ensure hasListeners is set correctly
- // based on possibility of concurrent adds/removes
- //
- synchronized (listeners)
+ public Collection<PojoCacheListener> getListeners()
{
- listeners.add(listener);
- hasListeners = true;
+ return listenerAdaptor.getListeners();
}
+
+ public void addListener(PojoCacheListener listener)
+ {
+ addListener(listener, null);
}
- public Collection getListeners()
+ public void addListener(PojoCacheListener listener, Pattern pattern)
+ {
+ // Add and remove listner operations must be serialized to ensure that
+ // the adaptor is always present only once, when at least one listener
+ // is registered.
+ synchronized (listenerAdaptor)
{
- return Collections.unmodifiableCollection(listeners);
+ listenerAdaptor.addListener(listener, pattern);
+ cache_.addCacheListener(listenerAdaptor);
+ }
}
public void removeListener(PojoCacheListener listener)
{
- // synchronize on listenrs just to
- // ensure hasListeners is set correctly
- // based on possibility of concurrent adds/removes
- //
- synchronized (listeners)
+ synchronized (listenerAdaptor)
{
- listeners.remove(listener);
- hasListeners = !listeners.isEmpty();
+ listenerAdaptor.removeListener(listener);
+ if (listenerAdaptor.isEmpty())
+ cache_.removeCacheListener(listenerAdaptor);
}
}
- public Cache getCache()
+ public Cache<Object,Object> getCache()
{
- // TODO Need to return the real Cache interface later on.
return cache_;
}
@@ -372,72 +348,6 @@
}
}
- /**
- * *****************************************************************************
- * Internal API for event notification
- * ******************************************************************************
- */
-
- private NotificationContext makeContext()
- {
- return new NotificationContext()
- {
- public PojoCache getPojoCache()
- {
- return PojoCacheImpl.this;
- }
- };
- }
-
- private void notifyAttach(Object pojo, boolean pre)
- {
- if (pojo == null) return;
- if (!shouldNotify(pojo)) return;
-
- boolean isLocal = true;// TODO Not yet supported. Always true now.
- if (hasListeners)
- {
- for (Iterator it = listeners.iterator(); it.hasNext();)
- {
- AttachNotification notification = new AttachNotification(makeContext(), pojo, pre ? Notification.Phase.PRE : Notification.Phase.POST, isLocal);
- ((PojoCacheListener) it.next()).attach(notification);
- }
- }
- }
-
- private void notifyDetach(Object pojo, boolean pre)
- {
- if (pojo == null) return;
- if (!shouldNotify(pojo)) return;
-
- boolean isLocal = true;// TODO Not yet supported. Always true now.
- if (hasListeners)
- {
- for (Iterator it = listeners.iterator(); it.hasNext();)
- {
- DetachNotification notification = new DetachNotification(makeContext(), pojo, pre ? Notification.Phase.PRE : Notification.Phase.POST, isLocal);
- ((PojoCacheListener) it.next()).detach(notification);
- }
- }
- }
-
- /**
- * Decide whether we want to emit notification event or not.
- *
- * @param pojo
- */
- private boolean shouldNotify(Object pojo)
- {
- // Not Advised or not Collection
- if (!(pojo instanceof Advised) &&
- !(pojo instanceof ClassProxy || pojo instanceof Collection ||
- pojo instanceof Map))
- {
- return false;
- }
- return true;
- }
-
public String toString()
{
return getClass().getName() +
1.3 +1 -3 JBossCache/src/org/jboss/cache/pojo/impl/SerializableObjectHandler.java
(In the diff below, changes in quantity of whitespace are not shown.)
Index: SerializableObjectHandler.java
===================================================================
RCS file: /cvsroot/jboss/JBossCache/src/org/jboss/cache/pojo/impl/SerializableObjectHandler.java,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -b -r1.2 -r1.3
--- SerializableObjectHandler.java 23 May 2007 10:28:49 -0000 1.2
+++ SerializableObjectHandler.java 30 May 2007 06:08:02 -0000 1.3
@@ -12,8 +12,6 @@
import org.jboss.cache.CacheException;
import org.jboss.cache.CacheSPI;
import org.jboss.cache.Fqn;
-import org.jboss.cache.pojo.InternalConstant;
-import org.jboss.cache.pojo.PojoInstance;
import java.util.HashMap;
import java.util.Map;
@@ -22,7 +20,7 @@
* Handle Serializable object cache management.
*
* @author Ben Wang
- * @version $Id: SerializableObjectHandler.java,v 1.2 2007/05/23 10:28:49 msurtani Exp $
+ * @version $Id: SerializableObjectHandler.java,v 1.3 2007/05/30 06:08:02 jgreene Exp $
*/
class SerializableObjectHandler
{
1.1 date: 2007/05/30 06:08:01; author: jgreene; state: Exp;JBossCache/src/org/jboss/cache/pojo/impl/CacheListenerAdaptor.java
Index: CacheListenerAdaptor.java
===================================================================
/*
* 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;
import java.util.Collection;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;
import org.jboss.cache.AbstractCacheListener;
import org.jboss.cache.Fqn;
import org.jboss.cache.pojo.PojoCache;
import org.jboss.cache.pojo.PojoCacheListener;
import org.jboss.cache.pojo.interceptors.PojoTxLockInterceptor;
import org.jboss.cache.pojo.notification.AttachNotification;
import org.jboss.cache.pojo.notification.DetachNotification;
import org.jboss.cache.pojo.notification.FieldModifyNotification;
import org.jboss.cache.pojo.notification.Notification;
import org.jboss.cache.pojo.notification.NotificationContext;
/**
* Adapts the core cache listener API into the POJO listener API.
*
* @author Jason T. Greene
* @revision $Id: CacheListenerAdaptor.java,v 1.1 2007/05/30 06:08:01 jgreene Exp $
*/
public class CacheListenerAdaptor extends AbstractCacheListener implements NotificationContext
{
private static final HashSet<String> internalKeys = new HashSet<String>();
static
{
internalKeys.add(InternalConstant.POJOCACHE_STATUS);
internalKeys.add(PojoInstance.KEY);
internalKeys.add(PojoReference.KEY);
internalKeys.add(PojoTxLockInterceptor.LOCK_KEY);
}
private PojoCacheImpl cache;
private NotificationDispatcher dispatcher = new NotificationDispatcher();
public CacheListenerAdaptor(PojoCacheImpl cache)
{
this.cache = cache;
}
public PojoCache getPojoCache()
{
return this.cache;
}
private FieldModifyNotification createModifyEvent(Fqn fqn, String key, Object value, boolean local)
{
if (value instanceof PojoReference)
value = cache.find(((PojoReference)value).getFqn().toString());
Object o = cache.find(fqn.toString());
Field f;
try
{
f = o.getClass().getDeclaredField(key);
}
catch (NoSuchFieldException e)
{
System.err.println("Could not get field " + key + " on class " + o.getClass());
return null;
}
return new FieldModifyNotification(this, o, f, value, local);
}
private void sendNotification(Notification notification, Set<PojoCacheListener> listeners)
{
if (listeners == null)
dispatcher.dispatch(notification);
else
dispatcher.dispatch(notification, listeners);
}
public void nodeModified(Fqn fqn, boolean pre, boolean isLocal, ModificationType modType, Map<Object, Object> data)
{
if (pre)
return;
// If we are filtering, don't load as much as possible
Set<PojoCacheListener> matched = null;
if (dispatcher.hasFilters())
{
matched = matchListeners(fqn);
if (matched != null && matched.isEmpty())
return;
}
if (modType == ModificationType.PUT_DATA)
{
if ("ATTACHED".equals(data.get(InternalConstant.POJOCACHE_STATUS)))
{
Object o = cache.find(fqn.toString());
sendNotification(new AttachNotification(this, o, isLocal), matched);
}
else if ("DETACHING".equals(data.get(InternalConstant.POJOCACHE_STATUS)))
{
Object o = cache.find(fqn.toString());
sendNotification(new DetachNotification(this, o, isLocal), matched);
}
else if ("ATTACHED".equals(cache.getCache().get(fqn, InternalConstant.POJOCACHE_STATUS)))
{
for (Map.Entry<Object, Object> entry : data.entrySet())
{
String key = entry.getKey().toString();
Object value = entry.getValue();
if (internalKeys.contains(key))
continue;
sendNotification(createModifyEvent(fqn, key, value, isLocal), matched);
}
}
}
else if (modType == ModificationType.REMOVE_DATA)
{
for (Map.Entry<Object, Object> entry : data.entrySet())
{
String key = entry.getKey().toString();
if (internalKeys.contains(key))
continue;
sendNotification(createModifyEvent(fqn, key, null, isLocal), matched);
}
}
}
private Set<PojoCacheListener> matchListeners(Fqn fqn)
{
if (dispatcher.hasFilters())
{
PojoInstance instance = (PojoInstance) cache.getCache().get(fqn, PojoInstance.KEY);
if (instance != null)
return dispatcher.getListeners(instance.getReferences());
}
return null;
}
public boolean isEmpty()
{
return dispatcher.isEmpty();
}
public Collection<PojoCacheListener> getListeners()
{
return dispatcher.getListeners();
}
public void addListener(PojoCacheListener listener)
{
dispatcher.add(listener);
}
public void addListener(PojoCacheListener listener, Pattern pattern)
{
if (pattern == null)
dispatcher.add(listener);
else
dispatcher.add(listener, pattern);
}
public void removeListener(PojoCacheListener listener)
{
dispatcher.remove(listener);
}
}
1.1 date: 2007/05/30 06:08:01; author: jgreene; state: Exp;JBossCache/src/org/jboss/cache/pojo/impl/CachedType.java
Index: CachedType.java
===================================================================
package org.jboss.cache.pojo.impl;
import org.jboss.aop.Advisor;
import org.jboss.aop.joinpoint.FieldInvocation;
import org.jboss.cache.pojo.interceptors.PojoBeginInterceptor;
import org.jboss.cache.pojo.memory.FieldPersistentReference;
import org.jboss.cache.pojo.memory.PersistentReference;
import java.lang.ref.WeakReference;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;
/**
* Represent a cached object type, e.g., whether it is <b>primitive</b> or not.
* Note: need to pay special attention not to leak classloader.
*
* @author <a href="mailto:harald at gliebe.de">Harald Gliebe</a>
* @author Ben Wang
*/
public class CachedType
{
// Types that are considered "primitive".
private static final Set immediates =
new HashSet(Arrays.asList(new Object[]{
String.class,
Boolean.class,
Double.class,
Float.class,
Integer.class,
Long.class,
Short.class,
Character.class,
Byte.class,
Boolean.TYPE,
Double.TYPE,
Float.TYPE,
Integer.TYPE,
Long.TYPE,
Short.TYPE,
Character.TYPE,
Byte.TYPE,
Class.class}));
private WeakReference<Class> type;
private boolean immutable;
private boolean immediate;
// This map caches the class that contains no annotation.
private static Map CachedClassWithNoAnnotation_ = new WeakHashMap();
private static Map CachedClassWithAnnotation_ = new WeakHashMap();
// Java fields . Will use special FieldPersistentReference to prevent classloader leakage.
private List fields = new ArrayList();
private Map fieldMap = new HashMap();// Name -> CachedAttribute
public CachedType()
{
}
public CachedType(Class type)
{
this.type = new WeakReference<Class>(type);
analyze();
}
public Class getType()
{
return type.get();
}
// determines if the object should be stored in the Nodes map or as a subnode
public boolean isImmediate()
{
return immediate;
}
private static boolean isImmediate(Class clazz)
{
return immediates.contains(clazz);
}
public boolean isImmutable()
{
return immutable;
}
public List getFields()
{
return fields;
}
public Field getField(String name)
{
FieldPersistentReference ref = (FieldPersistentReference) fieldMap.get(name);
if (ref == null) return null;
return (Field) ref.get();
}
/*
public List getAttributes()
{
return attributes;
}
public CachedAttribute getAttribute(Method m)
{
return (CachedAttribute) attributeMap.get(m);
}
protected void setAttributes(List attributes)
{
this.attributes = attributes;
attributeMap.clear();
// TODO: is a class with no set methods immutable ?
this.immutable = true;
for (Iterator i = attributes.iterator(); i.hasNext();) {
CachedAttribute attribute = (CachedAttribute) i.next();
if (attribute.getGet() != null) {
attributeMap.put(attribute.getGet(), attribute);
}
if (attribute.getSet() != null) {
attributeMap.put(attribute.getSet(), attribute);
immutable = false;
}
}
}
*/
public String toString()
{
StringBuffer sb = new StringBuffer();
sb.append(getType().getName()).append(" {\n");
/*
for (Iterator i = attributes.iterator(); i.hasNext();) {
CachedAttribute attr = (CachedAttribute) i.next();
sb
.append("\t")
.append(attr.getType().getLastElementAsString())
.append(" ")
.append(attr.getLastElementAsString())
.append(" [")
.append(attr.getGet() == null
? "<no get>"
: attr.getGet().getLastElementAsString())
.append(", ")
.append(attr.getSet() == null
? "<no set>"
: attr.getSet().getLastElementAsString())
.append("]\n");
}
*/
sb.append("}, immutable =").append(immutable);
return sb.toString();
}
/* ---------------------------------------- */
private void analyze()
{
/*
// We intercept all fields now (instead of setter methods) so there is no need to
// track the individual fields.
HashMap attributes = new HashMap();
Method[] methods = type.getMethods();
for (int i = 0; i < methods.length; i++) {
Method method = methods[i];
if (isGet(method)) {
CachedAttribute attribute =
getAttribute(method, attributes, true);
attribute.setGet(method);
attribute.setType(method.getReturnType());
} else if (isSet(method)) {
CachedAttribute attribute =
getAttribute(method, attributes, true);
attribute.setSet(method);
attribute.setType(method.getParameterTypes()[0]);
}
}
this.setAttributes(new ArrayList(attributes.values()));
*/
analyzeFields(getType());
immediate = isImmediate(getType());
}
private void analyzeFields(Class clazz)
{
if (clazz == null)
{
return;
}
analyzeFields(clazz.getSuperclass());
Field[] classFields = clazz.getDeclaredFields();
for (int i = 0; i < classFields.length; i++)
{
Field f = classFields[i];
if (isPrimitiveNonReplicatable(f)) continue;
f.setAccessible(true);
FieldPersistentReference persistentRef = new FieldPersistentReference(f, PersistentReference.REFERENCE_SOFT);
fields.add(persistentRef);
fieldMap.put(f.getName(), persistentRef);
}
}
/**
* We check whether this class has any field annotation declaration. We assume that there is only
* one such declaring class per vm and it is static.
*/
public static boolean hasAnnotation(Class clazz, Advisor advisor, CachedType type)
{
// It is ok that we don't synchronize it here.
if (CachedClassWithNoAnnotation_.get(clazz) != null)
{
return false;
}
else if (CachedClassWithAnnotation_.get(clazz) != null)
{
return true;
}
for (Iterator i = type.getFields().iterator(); i.hasNext();)
{
Field field = (Field) (((FieldPersistentReference) i.next())).get();
// check for non-replicatable types
if (CachedType.hasFieldAnnotation(field, advisor))
{
synchronized (CachedClassWithAnnotation_)
{
CachedClassWithAnnotation_.put(clazz, clazz.getName());
}
return true;
}
}
// This obj class doesn't have field annotation. It is ok that multiple threads
// put it repeatedly actually.
synchronized (CachedClassWithNoAnnotation_)
{
CachedClassWithNoAnnotation_.put(clazz, clazz.getName());
}
return false;
}
public static boolean isPrimitiveNonReplicatable(Field f)
{
int mods = f.getModifiers();
/**
* The following modifiers are ignored in the cache, i.e., they will not be stored in the cache.
* Whenever, user trying to access these fields, it will be accessed from the in-memory version.
*/
if (Modifier.isStatic(mods)
|| Modifier.isTransient(mods))
{
return true;
}
if (!PojoBeginInterceptor.getReplicateFinalField() && Modifier.isFinal(mods))
{
return true;
}
return false;
}
/**
* Check if we have @Transient annotation.
*
* @param invocation
* @return true if @Transient is present.
*/
private static boolean hasTransientAnnotation(FieldInvocation invocation)
{
Object obj = invocation.resolveAnnotation(org.jboss.cache.pojo.annotation.Transient.class);
if (obj != null)
{
return true;
}
return false;
}
private static boolean hasFieldAnnotation(Field field, Advisor advisor)
{
return hasTransientAnnotation(field, advisor) || hasSerializableAnnotation(field, advisor);
}
public static boolean hasTransientAnnotation(Field field, Advisor advisor)
{
Object obj = advisor.resolveAnnotation(field, org.jboss.cache.pojo.annotation.Transient.class);
if (obj != null)
{
return true;
}
return false;
}
public static boolean hasSerializableAnnotation(Field field, Advisor advisor)
{
Object obj = advisor.resolveAnnotation(field, org.jboss.cache.pojo.annotation.Serializable.class);
if (obj != null)
{
return true;
}
return false;
}
public static boolean hasSerializableAnnotation(FieldInvocation invocation)
{
Object obj = invocation.resolveAnnotation(org.jboss.cache.pojo.annotation.Serializable.class);
if (obj != null)
{
return true;
}
return false;
}
/*
* converts a get/set method to an attribute name
*/
protected static String attributeName(String methodName)
{
return methodName.substring(3, 4).toLowerCase()
+ methodName.substring(4);
}
protected static boolean isGet(Method method)
{
return method.getName().startsWith("get")
&& method.getParameterTypes().length == 0
&& method.getReturnType() != Void.TYPE;
}
protected static boolean isSet(Method method)
{
return method.getName().startsWith("set")
&& method.getParameterTypes().length == 1
&& method.getReturnType() == Void.TYPE;
}
}// CachedType
1.1 date: 2007/05/30 06:08:01; author: jgreene; state: Exp;JBossCache/src/org/jboss/cache/pojo/impl/InternalConstant.java
Index: InternalConstant.java
===================================================================
/*
* JBoss, Home of Professional Open Source
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package org.jboss.cache.pojo.impl;
import org.jboss.cache.Fqn;
/**
* Internal helper class to handle internal cache sotre, that is, the portion that is not part of
* user's data.
*
* @author Ben Wang
*/
public class InternalConstant
{
public static final String CLASS_INTERNAL = "__jboss:internal:class__";
public static final String SERIALIZED = "__SERIALIZED__";
public static final String JBOSS_INTERNAL_STRING = "__JBossInternal__";
public static final String JBOSS_INTERNAL_ID_SEP_STRING = "_ID_";
public static final Fqn JBOSS_INTERNAL = new Fqn(JBOSS_INTERNAL_STRING);
public static final Fqn JBOSS_INTERNAL_ID_SEP = new Fqn(JBOSS_INTERNAL_ID_SEP_STRING);
public static final Fqn JBOSS_INTERNAL_MAP = new Fqn(InternalConstant.JBOSS_INTERNAL, "__RefMap__");
public static final String JBOSS_INTERNAL_STATIC = "__jboss:static__";
public static final String ENUM_KEY = "name";
public static final String POJOCACHE_KEY_PREFIX = "POJOCache.";
public static final String POJOCACHE_STATUS = POJOCACHE_KEY_PREFIX + "STATUS";
}
1.1 date: 2007/05/30 06:08:01; author: jgreene; state: Exp;JBossCache/src/org/jboss/cache/pojo/impl/MethodDeclarations.java
Index: MethodDeclarations.java
===================================================================
/*
* JBoss, Home of Professional Open Source
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package org.jboss.cache.pojo.impl;
import org.jboss.aop.InstanceAdvisor;
import org.jboss.aop.advice.Interceptor;
import org.jboss.cache.Fqn;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.List;
/**
* Method declarations for rollback method mostly.
*
* @author Ben Wang
* @version $Revision: 1.1 $
*/
public class MethodDeclarations
{
public static final Method attachInterceptor;
public static final Method detachInterceptor;
public static final Method undoAttachInterceptor;
public static final Method undoDetachInterceptor;
;
public static final Method inMemorySubstitution;
;
public static final Method undoInMemorySubstitution;
;
public static final Method incrementReferenceCount;
public static final Method decrementReferenceCount;
public static final Method undoIncrementReferenceCount;
public static final Method undoDecrementReferenceCount;
static
{
try
{
attachInterceptor = PojoUtil.class.getDeclaredMethod("attachInterceptor",
new Class[]{Object.class, InstanceAdvisor.class, Interceptor.class});
detachInterceptor = PojoUtil.class.getDeclaredMethod("detachInterceptor",
new Class[]{InstanceAdvisor.class, Interceptor.class});
undoAttachInterceptor = PojoUtil.class.getDeclaredMethod("undoAttachInterceptor",
new Class[]{Object.class, InstanceAdvisor.class, Interceptor.class});
undoDetachInterceptor = PojoUtil.class.getDeclaredMethod("undoDetachInterceptor",
new Class[]{InstanceAdvisor.class, Interceptor.class});
inMemorySubstitution = PojoUtil.class.getDeclaredMethod("inMemorySubstitution",
new Class[]{Object.class, Field.class, Object.class});
undoInMemorySubstitution = PojoUtil.class.getDeclaredMethod("undoInMemorySubstitution",
new Class[]{Object.class, Field.class, Object.class});
incrementReferenceCount = PojoUtil.class.getDeclaredMethod("incrementReferenceCount",
new Class[]{Fqn.class, int.class, List.class});
decrementReferenceCount = PojoUtil.class.getDeclaredMethod("decrementReferenceCount",
new Class[]{Fqn.class, int.class, List.class});
undoIncrementReferenceCount = PojoUtil.class.getDeclaredMethod("undoIncrementReferenceCount",
new Class[]{Fqn.class, int.class, List.class});
undoDecrementReferenceCount = PojoUtil.class.getDeclaredMethod("undoDecrementReferenceCount",
new Class[]{Fqn.class, int.class, List.class});
}
catch (NoSuchMethodException e)
{
throw new ExceptionInInitializerError(e);
}
}
}
1.1 date: 2007/05/30 06:08:01; author: jgreene; state: Exp;JBossCache/src/org/jboss/cache/pojo/impl/NotificationDispatcher.java
Index: NotificationDispatcher.java
===================================================================
/*
* 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.Method;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.regex.Pattern;
import org.jboss.cache.Fqn;
import org.jboss.cache.pojo.PojoCacheException;
import org.jboss.cache.pojo.PojoCacheListener;
import org.jboss.cache.pojo.notification.Notification;
/**
* Dispatches notificaiton events to POJO cache listeners.
*
* @author Jason T. Greene
* @revision $Id: NotificationDispatcher.java,v 1.1 2007/05/30 06:08:01 jgreene Exp $
*/
public class NotificationDispatcher
{
private final static Map<Class<?>, Method> notifiers = new HashMap<Class<?>, Method>();
private final Set<Entry> listeners = new CopyOnWriteArraySet<Entry>();
private Set<PojoCacheListener> filteredListeners = new HashSet<PojoCacheListener>();
private volatile boolean hasFilters;
private final static class Entry
{
private final PojoCacheListener listener;
private final Pattern pattern;
public Entry(PojoCacheListener listener)
{
this(listener, null);
}
public Entry(PojoCacheListener listener, Pattern pattern)
{
if (listener == null)
throw new IllegalArgumentException("Listener can't be null");
this.listener = listener;
this.pattern = pattern;
}
// pattern is just extra information, equality is confined to listener
public int hashCode()
{
return listener.hashCode();
}
// pattern is just extra information, equality is confined to listener
public boolean equals(Object o)
{
if (o == this)
return true;
if (! (o instanceof Entry))
return false;
return ((Entry)o).equals(listener);
}
}
static
{
for (Method method : PojoCacheListener.class.getMethods())
{
Class<?>[] parameterTypes = method.getParameterTypes();
if (parameterTypes.length == 1 && Notification.class.isAssignableFrom(parameterTypes[0]))
notifiers.put(parameterTypes[0], method);
}
}
public void add(PojoCacheListener listener)
{
listeners.add(new Entry(listener));
}
// gaurds filteredListeners
public synchronized void add(PojoCacheListener listener, Pattern pattern)
{
listeners.add(new Entry(listener, pattern));
filteredListeners.add(listener);
hasFilters = true;
}
// gaurds filteredListeners
public synchronized void remove(PojoCacheListener listener)
{
filteredListeners.remove(listener);
if (filteredListeners.size() == 0)
hasFilters = false;
listeners.remove(new Entry(listener));
}
public boolean hasFilters()
{
return hasFilters;
}
public Set<PojoCacheListener> getListeners()
{
Set<PojoCacheListener> set = new HashSet<PojoCacheListener>();
for (Entry entry : listeners)
set.add(entry.listener);
return Collections.unmodifiableSet(set);
}
public Set<PojoCacheListener> getListeners(List<Fqn> fqns)
{
Set<PojoCacheListener> set = new HashSet<PojoCacheListener>();
for (Entry entry : listeners)
{
if (entry.pattern == null)
{
set.add(entry.listener);
continue;
}
for (Fqn fqn : fqns)
{
if (entry.pattern.matcher(fqn.toString()).matches())
{
set.add(entry.listener);
break;
}
}
}
return set;
}
public boolean isEmpty()
{
return listeners.size() == 0;
}
public void dispatch(Notification notification)
{
for (Entry entry : listeners)
{
// Prevent dispatch to filtered entries
if (entry.pattern == null)
dispatch(notification, entry.listener);
}
}
public void dispatch(Notification notification, Set<PojoCacheListener> listeners)
{
for (PojoCacheListener listener : listeners)
dispatch(notification, listener);
}
private void dispatch(Notification notification, PojoCacheListener listener)
{
Method method = notifiers.get(notification.getClass());
try
{
if (method != null)
method.invoke(listener, notification);
}
catch (Exception e)
{
throw new PojoCacheException(e);
}
}
}
1.1 date: 2007/05/30 06:08:02; author: jgreene; state: Exp;JBossCache/src/org/jboss/cache/pojo/impl/PojoInstance.java
Index: PojoInstance.java
===================================================================
/*
* JBoss, the OpenSource J2EE webOS
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package org.jboss.cache.pojo.impl;
import org.jboss.cache.Fqn;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* POJO class metadata information.
* When an object is looked up or put in PojoCache, this object will be advised with a CacheFieldInterceptor.
* The underlying cache stores a reference to this object (for example to update the instance variables, etc.).
* Since this reference need to be transactional but never replicated (the reference is only valid
* within the VM this reference is thus stored into an PojoReference (as a transient field).
* In addition, this instance also serves as a metadata for PojoCache. E.g., it has a reference counting for
* multiple references and reference FQN.
*
* @author Ben Wang
*/
public class PojoInstance implements Serializable // Externalizable is no more efficient
{
// protected static Log log=LogFactory.getLog(PojoReference.class.getLastElementAsString());
public static final String KEY = InternalConstant.POJOCACHE_KEY_PREFIX + "PojoInstance";
public static final int INITIAL_COUNTER_VALUE = -1;
static final long serialVersionUID = 6492134565825613209L;
// The instance is transient to avoid replication outside the VM
private transient Object instance_;
// If not null, it signifies that this is a reference that points to this fqn.
// Note that this will get replicated.
private String internalFqn_ = null;
// Reference counting. THis will get replicated as well. This keep track of number of
// other instances that referenced this fqn.
private int refCount_ = INITIAL_COUNTER_VALUE;
// List of fqns that reference this fqn. Assume list size is not big since it may not be efficient.
private List<Fqn> referencedBy_ = null;
private Class clazz_ = null;
private transient PojoUtil util_ = new PojoUtil();
public PojoInstance()
{
}
public PojoInstance(Object instance)
{
set(instance);
}
public void setPojoClass(Class clazz)
{
clazz_ = clazz;
}
public Class getPojoClass()
{
return clazz_;
}
public Object get()
{
return instance_;
}
public void set(Object instance)
{
instance_ = instance;
}
public String getInternalFqn()
{
return internalFqn_;
}
public void setInternalFqn(String refFqn)
{
internalFqn_ = refFqn;
}
public void removeInternalFqn()
{
internalFqn_ = null;
}
synchronized public int incrementRefCount(Fqn sourceFqn)
{
if (sourceFqn == null)
{
throw new IllegalStateException("PojoInstance.incrementRefCount(): null sourceFqn");
}
if (referencedBy_ == null)
{
referencedBy_ = new ArrayList();
}
if (referencedBy_.contains(sourceFqn))
throw new IllegalStateException("PojoReference.incrementRefCount(): source fqn: " +
sourceFqn + " is already present.");
if (util_ == null) util_ = new PojoUtil();
refCount_ = util_.incrementReferenceCount(sourceFqn, refCount_, referencedBy_);
// referencedBy_.add(sourceFqn);
// refCount_ += 1;
//logger_.info("incrementRefCount(): current ref count " +refCount_);
return refCount_;
}
synchronized public int decrementRefCount(Fqn sourceFqn)
{
if (sourceFqn == null)
{
throw new IllegalStateException("PojoInstance.incrementRefCount(): null sourceFqn");
}
if (!referencedBy_.contains(sourceFqn))
throw new IllegalStateException("PojoReference.decrementRefCount(): source fqn: " +
sourceFqn + " is not present.");
if (util_ == null) util_ = new PojoUtil();
refCount_ = util_.decrementReferenceCount(sourceFqn, refCount_, referencedBy_);
// referencedBy_.remove(sourceFqn);
// refCount_ -= 1;
//logger_.info("decrementRefCount(): current ref count " +refCount_);
return refCount_;
}
synchronized public int getRefCount()
{
return refCount_;
}
public List<Fqn> getReferences()
{
return Collections.unmodifiableList(referencedBy_);
}
synchronized public Fqn getAndRemoveFirstFqnInList()
{
return (Fqn) referencedBy_.remove(0);
}
synchronized public void addXFqnIntoList(Fqn fqn)
{
referencedBy_.add(0, fqn);
}
public String toString()
{
return "PI[fqn=" + internalFqn_ + " ref=" + refCount_ + " class=" + clazz_.getName() + "]";
}
}
1.1 date: 2007/05/30 06:08:02; author: jgreene; state: Exp;JBossCache/src/org/jboss/cache/pojo/impl/PojoReference.java
Index: PojoReference.java
===================================================================
/*
* JBoss, the OpenSource J2EE webOS
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package org.jboss.cache.pojo.impl;
import org.jboss.cache.Fqn;
import java.io.Serializable;
/**
* POJO reference that contains the information to point to the real POJO storage.
*
* @author Ben Wang
*/
public class PojoReference implements Serializable // Externalizable is no more efficient
{
// protected static Log log=LogFactory.getLog(PojoReference.class.getLastElementAsString());
public static final String KEY = InternalConstant.POJOCACHE_KEY_PREFIX + "PojoReference";
static final long serialVersionUID = 6492134565825613209L;
// If not null, it signifies that this is a reference that points to this fqn.
// Note that this will get replicated.
private Fqn internalFqn_ = null;
private Class clazz_ = null;
public PojoReference()
{
}
public void setFqn(Fqn fqn)
{
internalFqn_ = fqn;
}
public Fqn getFqn()
{
return internalFqn_;
}
public void setPojoClass(Class clazz)
{
clazz_ = clazz;
}
public Class getPojoClass()
{
return clazz_;
}
public String toString()
{
StringBuffer buf = new StringBuffer();
buf.append("Internal Fqn --> ").append(internalFqn_);
return buf.toString();
}
}
1.1 date: 2007/05/30 06:08:02; author: jgreene; state: Exp;JBossCache/src/org/jboss/cache/pojo/impl/PojoUtil.java
Index: PojoUtil.java
===================================================================
/*
* JBoss, Home of Professional Open Source
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package org.jboss.cache.pojo.impl;
import org.jboss.aop.Advised;
import org.jboss.aop.Domain;
import org.jboss.aop.InstanceAdvisor;
import org.jboss.aop.advice.AdviceBinding;
import org.jboss.aop.advice.Interceptor;
import org.jboss.aop.pointcut.ast.ParseException;
import org.jboss.cache.Fqn;
import org.jboss.cache.pojo.PojoCacheException;
import org.jboss.cache.pojo.annotation.TxUndo;
import org.jboss.cache.pojo.interceptors.dynamic.CacheFieldInterceptor;
import org.jboss.cache.pojo.interceptors.dynamic.ReentrancyStopperInterceptor;
import java.lang.reflect.Field;
import java.util.List;
/**
* Utility class for method wrappers that we are interested to rollback (i.e., rollback).
*
* @author Ben Wang
* @version $Id: PojoUtil.java,v 1.1 2007/05/30 06:08:02 jgreene Exp $
*/
public class PojoUtil
{
private static final String BindingName = "ReentrancyStopperInterceptor.";
private boolean checkRecursive = false;
@TxUndo
public void attachInterceptor(Object pojo, InstanceAdvisor advisor, Interceptor interceptor)
{
_attachInterceptor(pojo, advisor, interceptor);
}
@TxUndo
public void detachInterceptor(InstanceAdvisor advisor, Interceptor interceptor)
{
_detachInterceptor(advisor, interceptor);
}
public void undoAttachInterceptor(Object pojo, InstanceAdvisor advisor, Interceptor interceptor)
{
_detachInterceptor(advisor, interceptor);
}
public void undoDetachInterceptor(InstanceAdvisor advisor, Interceptor interceptor)
{
Object pojo = ((CacheFieldInterceptor) interceptor).getAopInstance().get();
if (pojo == null)
{
throw new PojoCacheException("PojoUtil.detachInterceptor(): null pojo");
}
_attachInterceptor(pojo, advisor, interceptor);
}
@TxUndo
public void inMemorySubstitution(Object obj, Field field, Object newValue)
{
_inMemorySubstitution(obj, field, newValue);
}
public void undoInMemorySubstitution(Object obj, Field field, Object oldValue)
{
_inMemorySubstitution(obj, field, oldValue);
}
private void _attachInterceptor(Object pojo, InstanceAdvisor advisor, Interceptor interceptor)
{
// Note that subject interceptor should come before the cache interceptor.
advisor.appendInterceptor(interceptor);
if (checkRecursive)
{
// Insert interceptor to detect recursive call
Class clazz = pojo.getClass();
Field[] fields = clazz.getDeclaredFields();
String clazzName = clazz.getName();
for (Field field : fields)
{
String name = field.getName();
if (name.contains("$aop")) continue; // this is aop declared field.
StringBuffer buf = new StringBuffer().append("set(* ").append(clazzName).append("->").
append(name).append(")");
AdviceBinding binding = null;
try
{
binding = new AdviceBinding(BindingName + name, buf.toString(), null);
}
catch (ParseException e)
{
throw new PojoCacheException("PojoUtil._attachInterceptor(): can't parse the field binding: "
+ e, e);
}
binding.addInterceptor(ReentrancyStopperInterceptor.class);
getInstanceDomain(pojo).addBinding(binding);
}
}
}
private Domain getInstanceDomain(Object obj)
{
Advised advised = ((Advised) obj);
InstanceAdvisor advisor = advised._getInstanceAdvisor();
return advisor.getDomain();
}
private void _inMemorySubstitution(Object obj, Field field, Object newValue)
{
try
{
field.set(obj, newValue);
}
catch (IllegalAccessException e)
{
throw new PojoCacheException(
"PojoUtil.inMemorySubstitution(): Can't swap out the class of field \" " +
"+field.getLastElementAsString()," + e);
}
}
private void _detachInterceptor(InstanceAdvisor advisor, Interceptor interceptor)
{
advisor.removeInterceptor(interceptor.getName());
// retrieve pojo
Object pojo = ((CacheFieldInterceptor) interceptor).getAopInstance().get();
if (pojo == null)
{
throw new PojoCacheException("PojoUtil.detachInterceptor(): null pojo");
}
if (checkRecursive)
{
// Insert interceptor to detect recursive call
Class clazz = pojo.getClass();
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields)
{
String name = field.getName();
if (name.contains("$aop")) continue; // this is aop declared field.
getInstanceDomain(pojo).removeBinding(BindingName + name);
}
}
}
@TxUndo
public int incrementReferenceCount(Fqn sourceFqn, int count, List refList)
{
return _incrementReferenceCount(sourceFqn, count, refList);
}
public int undoIncrementReferenceCount(Fqn sourceFqn, int count, List refList)
{
return _decrementReferenceCount(sourceFqn, count, refList);
}
private int _incrementReferenceCount(Fqn sourceFqn, int count, List refList)
{
refList.add(sourceFqn);
return count + 1;
}
@TxUndo
public int decrementReferenceCount(Fqn sourceFqn, int count, List refList)
{
return _decrementReferenceCount(sourceFqn, count, refList);
}
public int undoDecrementReferenceCount(Fqn sourceFqn, int count, List refList)
{
return _incrementReferenceCount(sourceFqn, count, refList);
}
private int _decrementReferenceCount(Fqn sourceFqn, int count, List refList)
{
refList.remove(sourceFqn);
return count - 1;
}
}
1.1 date: 2007/05/30 06:08:02; author: jgreene; state: Exp;JBossCache/src/org/jboss/cache/pojo/impl/Referrer.java
Index: Referrer.java
===================================================================
/*
* 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;
/**
* A referrer node refers to an internal node.
*
* @author Jason T. Greene
*/
final class Referrer
{
private Fqn fqn;
private String field;
Referrer(Fqn fqn)
{
this(fqn, null);
}
Referrer(Fqn fqn, String field)
{
if (fqn == null)
throw new IllegalArgumentException("Fqn can not be null!!");
this.fqn = fqn;
this.field = field;
}
public String getField()
{
return field;
}
public Fqn getFqn()
{
return fqn;
}
private boolean equals(Object o1, Object o2)
{
if (o1 == o2)
return true;
if (o1 != null && o1.equals(o2))
return true;
return false;
}
public int hashCode()
{
int result = 629 * fqn.hashCode();
if (field != null)
result = 37 * result + field.hashCode();
return result;
}
public boolean equals(Object o)
{
if (o instanceof Referrer)
return equals(((Referrer)o).fqn, fqn) && equals(((Referrer)o).field, field);
return false;
}
}
More information about the jboss-cvs-commits
mailing list