[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