[jboss-cvs] JBossCache/old/src/org/jboss/cache/aop ...

Ben Wang bwang at jboss.com
Tue Oct 31 03:01:13 EST 2006


  User: bwang   
  Date: 06/10/31 03:01:13

  Added:       old/src/org/jboss/cache/aop                      
                        AopMarker.java WriteReplaceable.java
                        PojoCacheIfc.java TreeCacheAopIfc.java
                        ModificationEntry.java PojoCache.java
                        MarshalledTreeCache.java
                        SerializableObjectHandler.java
                        CollectionClassHandler.java TreeCacheAopView.java
                        CacheInterceptor.java
                        PojoTxSynchronizationHandler.java
                        ObjectGraphHandler.java InstanceOfAopMarker.java
                        WriteReplacer.java CachedType.java
                        TreeCacheAop.java InternalDelegate.java
                        TreeCacheAopDelegate.java CachedAttribute.java
                        AOPInstance.java BaseInterceptor.java
  Log:
  Deprecated files moved to old dir.
  
  Revision  Changes    Path
  1.1      date: 2006/10/31 08:01:13;  author: bwang;  state: Exp;JBossCache/old/src/org/jboss/cache/aop/AopMarker.java
  
  Index: AopMarker.java
  ===================================================================
  package org.jboss.cache.aop;
  
  /**
   * Marker interface for use in aop annotation declaration. For example, can use this in pojo
   * annotation instead of declaring jboss-aop.xml.
   * @author Ben Wang
   */
  public interface AopMarker {
  }
  
  
  
  1.1      date: 2006/10/31 08:01:13;  author: bwang;  state: Exp;JBossCache/old/src/org/jboss/cache/aop/WriteReplaceable.java
  
  Index: WriteReplaceable.java
  ===================================================================
  /*
   * JBoss, the OpenSource J2EE webOS
   *
   * Distributable under LGPL license.
   * See terms of license at gnu.org.
   */
  
  package org.jboss.cache.aop;
  
  import java.io.ObjectStreamException;
  
  /**
   * @author <a href="mailto:harald at gliebe.de">Harald Gliebe</a>
   * @deprecated 1.0
   */
  
  public interface WriteReplaceable
  {
  
     Object writeReplace() throws ObjectStreamException;
  
  }
  
  
  
  1.1      date: 2006/10/31 08:01:13;  author: bwang;  state: Exp;JBossCache/old/src/org/jboss/cache/aop/PojoCacheIfc.java
  
  Index: PojoCacheIfc.java
  ===================================================================
  /*
   * JBoss, the OpenSource J2EE webOS
   *
   * Distributable under LGPL license.
   * See terms of license at gnu.org.
   */
  package org.jboss.cache.aop;
  
  import org.jboss.cache.CacheException;
  import org.jboss.cache.Fqn;
  
  import java.util.Map;
  
  /**
   * Interface for PojoCache. User should use this interface directly to access the public APIs.
   * <p>PojoCache is an in-memory, transactional, fine-grained, and object-oriented cache system. It
   * differs from the typical generic cache library by operating on the pojo level directly without requiring
   * that object to be serializable (although it does require "aspectizing" the POJO). Further, it can
   * preserve object graph during replication or persistency. It also track the replication via fine-grained
   * maner, i.e., only changed fields are replicated.</p>
   *
   * @author Ben Wang
   * @since 1.4
   */
  public interface PojoCacheIfc
  {
     /**
       * Retrieve pojo from the cache. Return null if object does not exist in the cache.
      * Note that this operation is fast if there is already an POJO instance attached to the cache.
       *
       * @param fqn Instance that associates with this node.
       * @return Current content value. Null if does not exist.
       * @throws CacheException Throws if there is an error related to the cache operation, e.g.,
      * {@link org.jboss.cache.lock.TimeoutException}.
       */
     Object getObject(String fqn) throws CacheException;
  
     /**
       * Retrieve pojo object from the cache. Return null if object does not exist in the cache.
      * Note that this operation is fast if there is already an POJO instance attached to the cache.
       *
       * @param fqn Instance that associates with this node.
       * @return Current content value. Null if does not exist.
      * @throws CacheException Throws if there is an error related to the cache operation, e.g.,
     * {@link org.jboss.cache.lock.TimeoutException}.
       */
     Object getObject(Fqn fqn) throws CacheException;
  
     /**
      * Insert a pojo into the cache.
      * It will also recursively put the any sub-object that is
      * declared as aop-capable (i.e., in <code>jboss-aop.xml</code>).
      * Note that <code>List</code>, <code>Map</code>, <code>Set</code>
      * attributes are aop-enabled, by default, as well.
      *
      * @param fqn The fqn instance to associate with the object in the cache.
      * @param obj aop-enabled object to be inerted into the cache. If null,
      *            it will nullify the fqn node.
      * @param obj Return the previous content under fqn.
      * @return Existing POJO or null if there is not.
      * @throws CacheException Throws if there is an error related to the cache operation, e.g.,
     * {@link org.jboss.cache.lock.TimeoutException}.
      */
     Object putObject(String fqn, Object obj) throws CacheException;
  
     /**
      * Insert a pojo into the cache.
      * It will also recursively put the any sub-object that is
      * declared as aop-capable (i.e., in <code>jboss-aop.xml</code>).
      * Note that <code>List</code>, <code>Map</code>, <code>Set</code>
      * attributes are aop-enabled, by default, as well.
      *
      * @param fqn The fqn instance to associate with the object in the cache.
      * @param obj aop-enabled object to be inerted into the cache. If null,
      *            it will nullify the fqn node.
      * @param obj Return the previous content under fqn.
      * @return Existing POJO or null if there is not.
      * @throws CacheException Throws if there is an error related to the cache operation, e.g.,
     * {@link org.jboss.cache.lock.TimeoutException}.
      */
     Object putObject(Fqn fqn, Object obj) throws CacheException;
  
     /**
      * Remove pojo object from the cache.
      *
      * @param fqn Instance that associates with this node.
      * @return Original value object from this node.
      * @throws CacheException Throws if there is an error related to the cache operation, e.g.,
     * {@link org.jboss.cache.lock.TimeoutException}.
      */
     Object removeObject(String fqn) throws CacheException;
  
     /**
      * Remove pojo object from the cache.
      *
      * @param fqn Instance that associates with this node.
      * @return Original value object from this node.
      * @throws CacheException Throws if there is an error related to the cache operation, e.g.,
     * {@link org.jboss.cache.lock.TimeoutException}.
      */
     Object removeObject(Fqn fqn) throws CacheException;
  
     /**
      * Query all managed pojo objects under the fqn recursively. Note that this will not return the sub-object pojos,
      * e.g., if Person has a sub-object of Address, it won't return Address pojo. Note also that this operation is
      * not thread-safe now. In addition, it assumes that once a pojo is found with a fqn, no more pojo is stored
      * under the children of the fqn. That is, we don't mixed the fqn with different pojos.
      * @param fqn The starting place to find all pojos.
      * @return Map of all pojos found with (fqn, pojo) pair. Return size of 0, if not found.
      * @throws CacheException Throws if there is an error related to the cache operation, e.g.,
     * {@link org.jboss.cache.lock.TimeoutException}.
      */
     Map findObjects(String fqn) throws CacheException;
  
     /**
      * Query all managed pojo objects under the fqn recursively. Note that this will not return the sub-object pojos,
      * e.g., if Person has a sub-object of Address, it won't return Address pojo. Note also that this operation is
      * not thread-safe now. In addition, it assumes that once a pojo is found with a fqn, no more pojo is stored
      * under the children of the fqn. That is, we don't mixed the fqn with different pojos.
      * @param fqn The starting place to find all pojos.
      * @return Map of all pojos found with (fqn, pojo) pair. Return size of 0, if not found.
      * @throws CacheException
      */
     Map findObjects(Fqn fqn) throws CacheException;
  
     /**
      * If the flag is set, then POJO which is not instrumented under AOP and which is not implementing the
      * Serializable interface will still be marshalled and make serializable.
      *
      */
     void setMarshallNonSerializable(boolean marshall);
  
     /**
      * Indicate whether the flag is set or not.
      */
     boolean isMarshallNonSerializable();
  
     /**
      * Obtain a cache aop type for user to traverse the defined "primitive" types in aop.
      *
      * @param clazz The original pojo class
      * @return CachedType
      */
     public CachedType getCachedType(Class clazz);
  
  }
  
  
  
  1.1      date: 2006/10/31 08:01:13;  author: bwang;  state: Exp;JBossCache/old/src/org/jboss/cache/aop/TreeCacheAopIfc.java
  
  Index: TreeCacheAopIfc.java
  ===================================================================
  /*
   * JBoss, the OpenSource J2EE webOS
   *
   * Distributable under LGPL license.
   * See terms of license at gnu.org.
   */
  package org.jboss.cache.aop;
  
  import org.jboss.cache.CacheException;
  import org.jboss.cache.Fqn;
  
  /**
    *
    * @author Harald Gliebe
    * @author Ben Wang
   * @deprecated Since 1.4, replaced by {@link PojoCacheIfc}
   */
  public interface TreeCacheAopIfc extends PojoCacheIfc
  {
  }
  
  
  
  1.1      date: 2006/10/31 08:01:13;  author: bwang;  state: Exp;JBossCache/old/src/org/jboss/cache/aop/ModificationEntry.java
  
  Index: ModificationEntry.java
  ===================================================================
  /*
   * JBoss, Home of Professional Open Source
   *
   * Distributable under LGPL license.
   * See terms of license at gnu.org.
   */
  
  package org.jboss.cache.aop;
  
  import org.jboss.cache.Fqn;
  import org.jboss.aop.InstanceAdvisor;
  
  import java.io.Serializable;
  import java.util.List;
  import java.util.ArrayList;
  import java.lang.reflect.Field;
  
  /**
   * Modification entry for undo compensation. This is kind of ad hoc now.
   * We need to come up with an more formal undo operations to handle other cases
   * like object graph.
   * @author Ben Wang
   */
  public class ModificationEntry
  {
     public static final int INTERCEPTOR_ADD = 0;
     public static final int INTERCEPTOR_REMOVE = 1;
     public static final int COLLECTION_REPLACE = 2;
     private InstanceAdvisor advisor_;
     private BaseInterceptor interceptor_;
     private Field field_;
     private Object key_;
     private Object oldValue_;
  
     int opType_;
  
     public ModificationEntry(InstanceAdvisor advisor, BaseInterceptor interceptor, int op)
     {
        advisor_ = advisor;
        interceptor_ = interceptor;
        opType_ = op;
     }
  
     public ModificationEntry(Field field, Object key, Object oldValue)
     {
        field_ = field;
        key_ = key;
        oldValue_ = oldValue;
        opType_ = COLLECTION_REPLACE;
     }
  
     public int getOpType() { return opType_; }
  
     public InstanceAdvisor getInstanceAdvisor() { return advisor_; }
  
     public BaseInterceptor getCacheInterceptor() { return interceptor_; }
  
  
     public Field getField() {
        return field_;
     }
  
     public Object getKey() {
        return key_;
     }
  
     public Object getOldValue() {
        return oldValue_;
     }
  
  }
  
  
  
  1.1      date: 2006/10/31 08:01:13;  author: bwang;  state: Exp;JBossCache/old/src/org/jboss/cache/aop/PojoCache.java
  
  Index: PojoCache.java
  ===================================================================
  /*
   * JBoss, the OpenSource J2EE webOS
   *
   * Distributable under LGPL license.
   * See terms of license at gnu.org.
   */
  package org.jboss.cache.aop;
  
  import org.jboss.aop.InstanceAdvisor;
  import org.jboss.cache.CacheException;
  import org.jboss.cache.Fqn;
  import org.jboss.cache.NodeImpl;
  import org.jboss.cache.Region;
  import org.jboss.cache.RegionNotEmptyException;
  import org.jboss.cache.TreeCache;
  import org.jboss.cache.aop.eviction.AopEvictionPolicy;
  import org.jboss.cache.aop.statetransfer.PojoStateTransferManager;
  import org.jboss.cache.lock.UpgradeException;
  import org.jboss.cache.marshall.ObjectSerializationFactory;
  import org.jboss.cache.marshall.RegionNameConflictException;
  import org.jboss.cache.transaction.BatchModeTransactionManager;
  import org.jboss.cache.xml.XmlHelper;
  import org.jgroups.JChannel;
  import org.w3c.dom.Element;
  
  import javax.transaction.RollbackException;
  import javax.transaction.Status;
  import javax.transaction.SystemException;
  import javax.transaction.Transaction;
  import javax.transaction.TransactionManager;
  import java.lang.reflect.Field;
  import java.util.ArrayList;
  import java.util.List;
  import java.util.Map;
  import java.util.WeakHashMap;
  
  /**
   * PojoCache implementation class. User should use the {@link PojoCacheIfc} interface directly to
   * access the public APIs.
   * <p>PojoCache is an in-memory, transactional, fine-grained, and object-oriented cache system. It
   * differs from the typical generic cache library by operating on the pojo level directly without requiring
   * that object to be serializable (although it does require "aspectizing" the POJO). Further, it can
   * preserve object graph during replication or persistency. It also track the replication via fine-grained
   * maner, i.e., only changed fields are replicated.</p>
   *
   * @author Ben Wang
   * @since 1.4
   */
  public class PojoCache extends TreeCache// implements PojoCacheMBean //TODO: Need to properly implement a JMX interface
  {
     // Class -> CachedType
     // use WeakHashMap to allow class reloading
     protected Map cachedTypes = new WeakHashMap();
     // Use batch mode tm to simulate the batch processing.
     TransactionManager localTm_ = BatchModeTransactionManager.getInstance();
     protected TreeCacheAopDelegate delegate_;
     Element config_ = null;
     protected final String LOCK = "_lock_";
     protected final int RETRY = 5; // retry times for lockPojo just in case there is upgrade exception during concurrent access.
     //   boolean detachPojoWhenEvicted_ = false;
     protected boolean marshallNonSerializable_ = false;
     protected ThreadLocal undoListLocal_ = new ThreadLocal();
     protected ThreadLocal hasSynchronizationHandler_ = new ThreadLocal();
  
     public PojoCache(String cluster_name,
                      String props,
                      long state_fetch_timeout)
             throws Exception
     {
        // TODO: use a CacheFactory
  
        //super(cluster_name, props, state_fetch_timeout);
        init();
     }
  
     public PojoCache() throws Exception
     {
        init();
     }
  
     public PojoCache(JChannel channel) throws Exception
     {
        super(channel);
        init();
     }
  
     protected void init()
     {
        delegate_ = new TreeCacheAopDelegate(this);
     }
  
     public void start() throws Exception
     {
        // Replace the default state transfer manager
        setStateTransferManager(new PojoStateTransferManager(this));
        super.start();
        parseConfig();
     }
  
     public void stop()
     {
        super.stop();
     }
  
     protected void parseConfig()
     {
        if (config_ == null)
        {
           log.info("parseConfig(): PojoCacheConfig is empty");
           return;
        }
        marshallNonSerializable_ = XmlHelper.readBooleanContents(config_, "marshallNonSerializable");
        log.info("marshallNonSerializable flag is set: " + marshallNonSerializable_);
  
  //      detachPojoWhenEvicted_ = XmlHelper.readBooleanContents(config_, "DetachPojoWhenEvicted");
     }
  
     /**
      * Over-ride to make sure we are using an eviction policy specific to aop.
      */
     public void setEvictionPolicyClass(String eviction_policy_class)
     {
        getConfiguration().setEvictionPolicyClass(eviction_policy_class);
        if (eviction_policy_class == null || eviction_policy_class.length() == 0)
           return;
  
        try
        {
           Object obj = loadClass(eviction_policy_class).newInstance();
           if (!(obj instanceof AopEvictionPolicy))
              throw new RuntimeException("PojoCache.setEvictionPolicyClass(). Eviction policy provider:" +
                      eviction_policy_class + " is not an instance of AopEvictionPolicy.");
           getConfiguration().setEvictionPolicyClass(eviction_policy_class);
        }
        catch (RuntimeException ex)
        {
           log.error("setEvictionPolicyClass(): failed creating instance of  " + eviction_policy_class, ex);
           throw ex;
        }
        catch (Throwable t)
        {
           log.error("setEvictionPolicyClass(): failed creating instance of  " + eviction_policy_class, t);
        }
     }
  
     public void addUndoInterceptor(InstanceAdvisor advisor, BaseInterceptor interceptor, int op)
     {
        List list = (List) undoListLocal_.get();
        if (list == null)
        {
           list = new ArrayList();
           undoListLocal_.set(list);
        }
        ModificationEntry ent = new ModificationEntry(advisor, interceptor, op);
        list.add(ent);
     }
  
     public void addUndoCollectionProxy(Field field, Object key, Object oldValue)
     {
        List list = (List) undoListLocal_.get();
        if (list == null)
        {
           list = new ArrayList();
           undoListLocal_.set(list);
        }
        ModificationEntry ent = new ModificationEntry(field, key, oldValue);
        list.add(ent);
     }
  
     public void resetUndoOp()
     {
        List list = (List) undoListLocal_.get();
        if (list != null)
           list.clear();
        hasSynchronizationHandler_.set(null);
     }
  
     public List getModList()
     {
        // No need to make it unmodifiable since this is thread local
        return (List) undoListLocal_.get();
     }
  
     /**
      * Override to provide aop specific eviction.
      * <p/>
      * <p/>
      * Called by eviction policy provider. Note that eviction is done only in local mode,
      * that is, it doesn't replicate the node removal. This will cause the replication nodes
      * not synchronizing, but it is ok since user is supposed to add the node again when get is
      * null. After that, the contents will be in sync.
      *
      * @param fqn Will remove everythign assoicated with this fqn.
      * @throws org.jboss.cache.CacheException
      */
     public void evict(Fqn fqn) throws CacheException
     {
        // We will remove all children nodes as well since we assume all children nodes are part
        // of this "object" node.
        if (delegate_.isAopNode(fqn))
        {
           if (log.isDebugEnabled())
           {
              log.debug("evict(): evicting whole aop node " + fqn);
           }
  //         _evictObject(fqn);
           recursiveEvict(fqn);
        }
        else
        {
           super.evict(fqn);
        }
     }
  
     void recursiveEvict(Fqn fqn) throws CacheException
     {
        boolean create_undo_ops = true;
        boolean sendNodeEvent = false;
        // Let's do it brute force.
        _remove(null, fqn, create_undo_ops, sendNodeEvent);
     }
  
     /**
      * Package level evict for plain cache.
      *
      * @param fqn
      * @throws CacheException
      */
     void plainEvict(Fqn fqn) throws CacheException
     {
        super.evict(fqn);
     }
  
     protected void createEvictionPolicy()
     {
        super.createEvictionPolicy();
        this.evictionInterceptorClass = "org.jboss.cache.aop.interceptors.PojoEvictionInterceptor";
     }
  
     protected void _evictSubtree(Fqn subtree) throws CacheException
     {
  
        if (log.isTraceEnabled())
           log.trace("_evictSubtree(" + subtree + ")");
  
        //    We will remove all children nodes as well since we assume all children nodes are part
        // of this "object" node.
        if (delegate_.isAopNode(subtree))
        {
           if (log.isDebugEnabled())
           {
              log.debug("evict(): evicting whole aop node " + subtree);
           }
  //         _evictObject(subtree);
           recursiveEvict(subtree);
        }
        else
        {
           super._evictSubtree(subtree);
        }
  
     }
  
     /**
      * Overrides the {@link TreeCache#activateRegion(String) superclass method} by
      * ensuring that the internal region where information on shared object is stored
      * has been activated.
      */
     public void activateRegion(String subtreeFqn) throws RegionNotEmptyException, RegionNameConflictException, CacheException
     {
        if (!getConfiguration().isUseRegionBasedMarshalling())
           throw new IllegalStateException("TreeCache.activateRegion(). useRegionBasedMarshalling flag is not set!");
  
        if ("/".equals(subtreeFqn))
        {
           // Just pass it through, as we'll get the internal area
           // with the normal state transfer
           super.activateRegion(subtreeFqn);
        }
        else
        {
           // If the internal region is not activated yet, activate it first
           //MarshRegion region = regionManager_.getRegion(InternalDelegate.JBOSS_INTERNAL);
           Region region = getCacheSPI().getRegion(InternalDelegate.JBOSS_INTERNAL, false);
           if ((region == null && getConfiguration().isInactiveOnStartup())
                   || (region != null && !region.isActive()))
           {
              super.activateRegion(InternalDelegate.JBOSS_INTERNAL.toString());
           }
  
           // If we don't have an internal map node yet, create one.
           // Doing this ensures the code that integrates map references for
           // the region will have a node to integrate into
           if (get(InternalDelegate.JBOSS_INTERNAL_MAP) == null)
              createSubtreeRootNode(InternalDelegate.JBOSS_INTERNAL_MAP);
  
           // Now activate the requested region
           super.activateRegion(subtreeFqn);
        }
     }
  
     /**
      * Obtain a cache aop type for user to traverse the defined "primitive" types in aop.
      * Note that this is not a synchronized call now for speed optimization.
      *
      * @param clazz The original pojo class
      * @return CachedType
      */
     public synchronized CachedType getCachedType(Class clazz)
     {
        CachedType type = (CachedType) cachedTypes.get(clazz);
        if (type == null)
        {
           type = new CachedType(clazz);
           cachedTypes.put(clazz, type);
           return type;
        }
        else
        {
           return type;
        }
     }
  
     /**
      */
     public Object getObject(String fqn) throws CacheException
     {
        return getObject(Fqn.fromString(fqn));
     }
  
     /**
      */
     public Object getObject(Fqn fqn) throws CacheException
     {
        return _getObject(fqn);
     }
  
     /**
      */
     public Object putObject(String fqn, Object obj) throws CacheException
     {
        return putObject(Fqn.fromString(fqn), obj);
     }
  
     /**
      */
     public Object putObject(Fqn fqn, Object obj) throws CacheException
     {
        checkFqnValidity(fqn);
        if (log.isDebugEnabled())
        {
           log.debug("putObject(): Fqn:" + fqn);
        }
  
        Object owner = null;
        if (hasCurrentTransaction())  // We have a transaction context going on now.
        {
           // Start a new transaction, we need transaction so the operation is batch.
           owner = getOwnerForLock(); // lock it for the whole duration of batch mode.
           // Lock the parent, create and add the child
           if (!lockPojo(owner, fqn))
           {
              throw new CacheException("PojoCache.putObject(): Can't obtain the pojo lock under fqn: " + fqn);
           }
           return _putObject(fqn, obj);
        }
        else
        {
           // Start a new transaction, we need transaction so the operation is batch.
           try
           {
              // Need this just in case the node does yet exist.
  
              localTm_.begin();
              owner = getOwnerForLock(); // lock it for the whole duration of batch mode.
              // Lock the parent, create and add the child
              if (!lockPojo(owner, fqn))
              {
                 throw new CacheException("PojoCache.putObject(): Can't obtain the pojo lock under fqn: " + fqn);
              }
              Object objOld = _putObject(fqn, obj);
              return objOld;
           }
           catch (Exception e)
           {
              log.warn("putObject(): exception occurred: " + e);
              try
              {
                 localTm_.setRollbackOnly();
              }
              catch (Exception exn)
              {
                 exn.printStackTrace();
              }
  
              if (!(e instanceof CacheException))
                 throw new RuntimeException("PojoCache.putObject(): fqn: " + fqn, e);
              else
                 throw(CacheException) e;
           }
           finally
           {
              endTransaction(fqn);
              // Release no matter what.
  //            releasePojo(owner, fqn);
           }
        }
     }
  
     /**
      */
     public Object removeObject(String fqn) throws CacheException
     {
        return removeObject(Fqn.fromString(fqn));
     }
  
     /**
      */
     public Object removeObject(Fqn fqn) throws CacheException
     {
        checkFqnValidity(fqn);
  
        if (log.isDebugEnabled())
        {
           log.debug("removeObject(): Fqn:" + fqn);
        }
  
        Object owner = null;
        if (hasCurrentTransaction())  // We have a transaction context going on now.
        {
           owner = getOwnerForLock();
           if (!lockPojo(owner, fqn))
           {
              throw new CacheException("PojoCache.removeObject(): Can't obtain the pojo lock under fqn: " + fqn);
           }
           return _removeObject(fqn, true);
        }
        else
        {
           // Start a new transaction, we need transaction so the operation is atomic.
           try
           {
              localTm_.begin();
              owner = getOwnerForLock();
              if (!lockPojo(owner, fqn))
              {
                 throw new CacheException("PojoCache.removeObject(): Can't obtain the pojo lock under fqn: " + fqn);
              }
              return _removeObject(fqn, true);
           }
           catch (Exception e)
           {
              log.warn("removeObject(): exception occurred: " + e);
              try
              {
                 localTm_.setRollbackOnly();
              }
              catch (Exception exn)
              {
                 exn.printStackTrace();
              }
  
              if (!(e instanceof CacheException))
                 throw new RuntimeException("PojoCache.removeObject(): fqn: " + fqn, e);
              else
                 throw(CacheException) e;
           }
           finally
           {
              endTransaction(fqn);
              // Release no matter what.
  //            releasePojo(owner, fqn);
           }
        }
     }
  
     /**
      */
     public Map findObjects(String fqn) throws CacheException
     {
        return findObjects(Fqn.fromString(fqn));
     }
  
     /**
      */
     public Map findObjects(Fqn fqn) throws CacheException
     {
        return _findObjects(fqn);
     }
  
     public void setMarshallNonSerializable(boolean marshall)
     {
        if (marshall)
        {
           if (!ObjectSerializationFactory.useJBossSerialization())
           {
              throw new IllegalStateException("PojoCache.setMarshallNonSerializable(). " +
                      "Can't set MarshallNonSerializable to true since useJBossSerialization is false");
           }
        }
        marshallNonSerializable_ = marshall;
     }
  
     public boolean isMarshallNonSerializable()
     {
        return marshallNonSerializable_;
     }
  
  
     /**
      * Inject the config element that is specific to PojoCache.
      *
      * @param config
      * @throws CacheException
      */
     public void setPojoCacheConfig(Element config) throws CacheException
     {
        config_ = config;
     }
  
     public Element getPojoCacheConfig()
     {
        return config_;
     }
  
     private void checkFqnValidity(Fqn fqn)
     {
        // throws exception is fqn is JBossInternal
        if (fqn.equals(InternalDelegate.JBOSS_INTERNAL))
        {
           throw new IllegalArgumentException("checkFqnValidity(): fqn is not valid: " + fqn);
        }
     }
  
     protected boolean lockPojo(Object owner, Fqn fqn) throws CacheException
     {
        if (log.isDebugEnabled())
        {
           log.debug("lockPojo(): Fqn:" + fqn + " Owner: " + owner);
        }
  
        boolean isNeeded = true;
        int retry = 0;
        while (isNeeded)
        {
           try
           {
              put(fqn, LOCK, "LOCK");
              isNeeded = false;
           }
           catch (UpgradeException upe)
           {
              log.warn("lockPojo(): can't upgrade the lock during lockPojo. Will re-try. Fqn: " + fqn
                      + " retry times: " + retry);
              get(fqn).release(owner);
              if (retry++ > RETRY)
              {
                 return false;
              }
              // try to sleep a little as well.
              try
              {
                 Thread.sleep(10);
              }
              catch (InterruptedException e)
              {
                 ;
              }
              continue;
           }
        }
  
        return true;
     }
  
     protected void releasePojo(Object owner, Fqn fqn) throws CacheException
     {
        NodeImpl node = get(fqn);
        if (node == null)
        {
           if (log.isDebugEnabled())
           {
              log.debug("releasePojo(): node could have been released already.");
           }
           return;
        }
  
        node.release(owner);
     }
  
     protected boolean hasCurrentTransaction()
     {
        try
        {
           if (getCurrentTransaction() != null || localTm_.getTransaction() != null)
           {
              // We have transaction context. Return null to signify don't do anything
              return true;
           }
        }
        catch (SystemException e)
        {
           throw new RuntimeException("PojoCache.hasCurrentTransaction: ", e);
        }
        return false;
     }
  
     protected void endTransaction(Fqn fqn)
     {
        if (localTm_ == null)
        {
           log.warn("PojoCache.endTransaction(): tm is null for fqn: " + fqn);
           return;
        }
  
  
        try
        {
           if (localTm_.getTransaction().getStatus() != Status.STATUS_MARKED_ROLLBACK)
           {
              localTm_.commit();
           }
           else if (localTm_.getTransaction().getStatus() == Status.STATUS_ROLLEDBACK)
           {
              log.info("PojoCache.endTransaction(): has been rolled back for fqn: " + fqn);
           }
           else
           {
              log.info("PojoCache.endTransaction(): rolling back tx for fqn: " + fqn);
              localTm_.rollback();
           }
        }
        catch (RollbackException re)
        {
           // Do nothing here since cache may rollback automatically.
           log.warn("PojoCache.endTransaction(): rolling back transaction with exception: " + re);
        }
        catch (Exception e)
        {
           log.warn("PojoCache.endTransaction(): Failed with exception: " + e);
        }
     }
  
     /**
      * Used by internal implementation. Not for general public.
      */
     public Object _getObject(Fqn fqn) throws CacheException
     {
        return delegate_._getObject(fqn);
     }
  
     /**
      * Used by internal implementation. Not for general public.
      */
     public Object _putObject(Fqn fqn, Object obj) throws CacheException
     {
        registerTxHandler();
        return delegate_._putObject(fqn, obj);
     }
  
     protected void registerTxHandler() throws CacheException
     {
        try
        {
           // Need to have this in case of rollback
           Boolean isTrue = (Boolean) hasSynchronizationHandler_.get();
           if (isTrue == null || !isTrue.booleanValue())
           {
              Transaction tx = getLocalTransaction();
              if (tx == null) tx = localTm_.getTransaction();
  
              if (tx == null)
              {
                 throw new IllegalStateException("PojoCache.registerTxHanlder(). Can't have null tx handle.");
              }
              tx.registerSynchronization(
                      new PojoTxSynchronizationHandler(tx, this));
  
              hasSynchronizationHandler_.set(Boolean.TRUE);
           }
        }
        catch (RollbackException e)
        {
           throw new CacheException("_putObject(). Exception: " + e);
        }
        catch (SystemException e)
        {
           throw new CacheException("_putObject(). Exception: " + e);
        }
     }
  
     /**
      * Used by internal implementation. Not for general public.
      */
     public Object _removeObject(Fqn fqn) throws CacheException
     {
        boolean removeCacheInterceptor = true;
        return _removeObject(fqn, removeCacheInterceptor);
     }
  
     /**
      * Used by internal implementation. Not for general public.
      */
     public Object _removeObject(Fqn fqn, boolean removeCacheInterceptor) throws CacheException
     {
        boolean evict = false;
        // Don't trigger bulk remove now since there is still some problem with Collection class
        // when it is detached.
        delegate_.setBulkRemove(true);
        registerTxHandler();
        return delegate_._removeObject(fqn, removeCacheInterceptor, evict);
     }
  
     /**
      * Used by internal implementation. Not for general public.
      */
     public Object _evictObject(Fqn fqn) throws CacheException
     {
        boolean evict = true;
        boolean removeCacheInterceptor = false;
  
        // Configurable option to see if we want to remove the cache interceptor when the pojo is
        // evicted.
  //      if(detachPojoWhenEvicted_) removeCacheInterceptor = true;
        delegate_.setBulkRemove(false);
        return delegate_._removeObject(fqn, removeCacheInterceptor, evict);
     }
  
     /**
      * Used by internal implementation. Not for general public.
      */
     public Map _findObjects(Fqn fqn) throws CacheException
     {
        return delegate_._findObjects(fqn);
     }
  }
  
  
  
  1.1      date: 2006/10/31 08:01:13;  author: bwang;  state: Exp;JBossCache/old/src/org/jboss/cache/aop/MarshalledTreeCache.java
  
  Index: MarshalledTreeCache.java
  ===================================================================
  /*
   * JBoss, the OpenSource J2EE webOS
   *
   * Distributable under LGPL license.
   * See terms of license at gnu.org.
   */
  package org.jboss.cache.aop;
  
  import org.jboss.cache.CacheException;
  import org.jboss.cache.CacheListener;
  import org.jboss.cache.CacheSPI;
  import org.jboss.cache.Fqn;
  import org.jboss.cache.TreeCache;
  import org.jboss.cache.config.Configuration;
  import org.jboss.cache.lock.IsolationLevel;
  import org.jboss.aop.util.MarshalledValue;
  import org.jgroups.JChannel;
  import org.jgroups.View;
  import org.jgroups.stack.IpAddress;
  
  import java.io.IOException;
  import java.util.HashMap;
  import java.util.Map;
  
  /**
   * <p>Version of TreeCache that added call to handle marshalling values. You will need marshalling when your application
   * is running under different class loader scope, for example, under JBoss AS where your application has a scoped
   * class loader.</p>
   * <p>Note that: Currently, we also have a in-memory cache copy to minimize the call to unmarshalling. And we also
   * have an invalidation mechanism in place to synchronize the external updates.</p>
   * <p>In the future, it'd be best if JBossCache can provides 1) notification excluding myself, 2) notification granulairty
   * with specific modified key, 3) we will also move this to different package.</p>
   * <p>Finally, since the use of in-memory copy, the memory usage is almost doubled since we have one in-memory copy and
   * the marshalled value in the cache store.</p>
   *
   * @author Ben Wang
   */
  public class MarshalledTreeCache extends TreeCache implements CacheListener
  {
     // Store the in-memory copy of the treecache (key, value) pair.
     // This is used for performance reason so there is no need to un-marshall every single operation.
     // In addition, it will support an invalidation mechanism.
     protected TreeCache localCopy_;
     protected String nodeId_;
     // Key to denotes the caller's ID. We will use this to check whether this is from myself or not.
     // TODO Will need to document this.
     protected static final String NODEID_KEY = "__NODEID_KEY__";
     // Context class loader. If it is not null, marshalling/unmarshalling will use this.
     protected ClassLoader tcl_ = null;
     // If it is on, will use an internal copy to keep the unmarshalling value.
     protected boolean useLocalOptimization_ = true;
     // Indicate whether we want marshalling or not. If it is false, useLocalOptimization will be false as wel.
     protected boolean marshalling_ = true;
  
     public MarshalledTreeCache(String cluster_name,
                                String props,
                                long state_fetch_timeout)
             throws Exception
     {
        // TODO: Use factory
        //super(cluster_name, props, state_fetch_timeout);
        this._init();
     }
  
     public MarshalledTreeCache() throws Exception
     {
        this._init();
     }
  
     public MarshalledTreeCache(JChannel channel) throws Exception
     {
        super(channel);
        this._init();
     }
  
     private void _init() throws Exception
     {
        localCopy_ = new TreeCache();
        Configuration conf = new Configuration();
        conf.setCacheMode("LOCAL");
        conf.setIsolationLevel(IsolationLevel.REPEATABLE_READ);
        localCopy_.setConfiguration(conf);
        marshalling_ = true;
        useLocalOptimization_ = true;
        tcl_ = null;
     }
  
     public void start() throws Exception
     {
        super.getNotifier().addCacheListener(this);
        super.start();
        if (localCopy_ == null)
           throw new RuntimeException("start(): null localCopy_");
        localCopy_.start();
        obtainNodeId();
     }
  
     public void stop()
     {
        nodeId_ = null;
        localCopy_.stop();
        super.stop();
     }
  
     /**
      * Get a node id based on jgroups properties.
      */
     protected void obtainNodeId()
     {
        IpAddress address = (IpAddress) getLocalAddress();
        if (address == null)
        {
           log.info("obtainNodeId(): has null IpAddress. Assume it is running in local mode.");
           nodeId_ = "local";
           return;
        }
  
        if (address.getAdditionalData() == null)
        {
           nodeId_ = address.getIpAddress().getHostAddress() + ":" + address.getPort();
        }
        else
        {
           nodeId_ = new String(address.getAdditionalData());
        }
     }
  
     /**
      * DataNode id is a communication id that denotes the cluster node.
      */
     public String getNodeId()
     {
        return nodeId_;
     }
  
  
     /**
      * Turn marshalling layer on or off. If off, no marshalling. Default is on.
      */
     public void setMarshalling(boolean marshalling)
     {
        marshalling_ = marshalling;
     }
  
     /**
      * Indicate whether to have a in-memory copy of the unmarshalling object such that
      * there is no need to unmarshal. If it is on, invlidation will be handled where another active
      * node has update this fqn.
      */
     public void setLocalOptimization(boolean optimization)
     {
        useLocalOptimization_ = optimization;
        throw new RuntimeException("MarshalledTreeCache.setLocalOptimization(): operation not supported yet.");
     }
  
     /**
      * The context class loader to perform marshalling/unmarshalling
      */
     public void setClassLoader(ClassLoader tcl)
     {
        tcl_ = tcl;
     }
  
     public void marshalledPut(String fqn, Object key, Object value) throws CacheException
     {
        marshalledPut(Fqn.fromString(fqn), key, value);
     }
  
     /**
      * Marshalled put. That is, the value that is put into cache is marshalled first. Note that
      * we still require that key to be primitive type.
      */
     public void marshalledPut(Fqn fqn, Object key, Object value) throws CacheException
     {
        if (marshalling_)
        {
           marshalledPut_(fqn, key, value);
        }
        else
        {
           put(fqn, key, value);
        }
     }
  
     public void marshalledPut_(Fqn fqn, Object key, Object value) throws CacheException
     {
        MarshalledValue mv = null;
        try
        {
           mv = new MarshalledValue(value);
        }
        catch (IOException e)
        {
           e.printStackTrace();
           throw new CacheException("marshalledPut() exception: " + e);
        }
  
        // Put into local copy first.
        localCopy_.put(fqn, key, value);
        // Put into cache
        Map map = new HashMap();
        map.put(key, mv);
        map.put(NODEID_KEY, nodeId_);
        this.put(fqn, map);
     }
  
     public Object marshalledGet(String fqn, Object key) throws CacheException
     {
        return marshalledGet(Fqn.fromString(fqn), key);
     }
  
     /**
      * Obtain the value from the marshalled cache. Note that the return value is un-marshalled
      * either from the local copy or from the distributed store.
      */
     public Object marshalledGet(Fqn fqn, Object key) throws CacheException
     {
        if (marshalling_)
        {
           ClassLoader prevTCL = null;
           if (tcl_ != null)
           {
              prevTCL = Thread.currentThread().getContextClassLoader();
              Thread.currentThread().setContextClassLoader(tcl_);
           }
           try
           {
              return marshalledGet_(fqn, key);
           }
           finally
           {
              if (tcl_ != null && prevTCL != null)
              {
                 Thread.currentThread().setContextClassLoader(prevTCL);
              }
           }
        }
        else
        {
           return get(fqn, key);
        }
     }
  
     public Object marshalledGet_(Fqn fqn, Object key) throws CacheException
     {
        // Check if it is in local copy first.
        Object value;
        try
        {
           if ((value = localCopy_.get(fqn, key)) != null)
              return value;
           else
           {  // get it from cache store
              value = get(fqn, key);
              if (value == null) return null;
              checkValue(value);
              MarshalledValue mv = (MarshalledValue) value;
              value = mv.get();
              // populate the local copy
              localCopy_.put(fqn, key, value);
              return value;
           }
        }
        catch (IOException e)
        {
           e.printStackTrace();
           throw new CacheException("marshalledGet(): exception encountered: ", e);
        }
        catch (ClassNotFoundException e)
        {
           e.printStackTrace();
           throw new CacheException("marshalledGet(): exception encountered: ", e);
        }
     }
  
     public Object marshalledRemove(String fqn, Object key) throws CacheException
     {
        return marshalledRemove(Fqn.fromString(fqn), key);
     }
  
     /**
      * Remove a marshalled node. This is required if you have performed a marshalledPut since
      * we will need to do clean up.
      */
     public Object marshalledRemove(Fqn fqn, Object key) throws CacheException
     {
        if (marshalling_)
        {
           return marshalledRemove_(fqn, key);
        }
        else
        {
           return remove(fqn, key);
        }
     }
  
     public Object marshalledRemove_(Fqn fqn, Object key) throws CacheException
     {
        if (!exists(fqn, key))
           log.warn("marshalledRemove(): fqn: " + fqn + " key: " + key + " not found.");
  
        Object value = localCopy_.get(fqn, key);
        localCopy_.remove(fqn);
        remove(fqn, NODEID_KEY);
        Object obj = remove(fqn, key);
        if (value != null) return value;
        checkValue(obj);
        try
        {
           return ((MarshalledValue) obj).get();
        }
        catch (IOException e)
        {
           e.printStackTrace();
           throw new CacheException("marshalledRemove(): exception encountered: ", e);
        }
        catch (ClassNotFoundException e)
        {
           e.printStackTrace();
           throw new CacheException("marshalledRemove(): exception encountered: ", e);
        }
     }
  
     public void nodeCreated(Fqn fqn, boolean pre, boolean isLocal)
     {
     }
  
     public void nodeModified(Fqn fqn, boolean pre, boolean isLocal, Map data)
     {
        if (!pre) invalidate(fqn);
     }
  
     public void nodeRemoved(Fqn fqn, boolean pre, boolean isLocal, Map data)
     {
        if (!pre) invalidate(fqn);
     }
  
     public void nodeVisited(Fqn fqn, boolean pre)
     {
     }
  
     public void nodeEvicted(Fqn fqn, boolean pre, boolean isLocal)
     {
        if (!pre) invalidate(fqn);
     }
  
     public void nodeLoaded(Fqn fqn, boolean pre, Map data)
     {
     }
  
     public void nodeMoved(Fqn from, Fqn to, boolean pre)
     {
     }
  
     public void nodeActivated(Fqn fqn, boolean pre)
     {
     }
  
     public void nodePassivated(Fqn fqn, boolean pre)
     {
     }
  
     public void cacheStarted(CacheSPI cache)
     {
     }
  
     public void cacheStopped(CacheSPI cache)
     {
     }
  
     public void viewChange(View new_view)
     {
     }
  
     protected void checkValue(Object value)
     {
        if (value != null && !(value instanceof MarshalledValue))
           throw new RuntimeException("checkValue: return object is not instance of MarshalledValue. object: " + value);
     }
  
     /**
      * Invalidate the local copy cache. Assumption is invlidation should not happen that often anyway.
      * In addition, we will invalidate the whole thing under the fqn.
      *
      * @param fqn
      */
     protected void invalidate(Fqn fqn)
     {
        if (!marshalling_) return; // No need if there is no marshalling!
        if (fqn.isRoot()) return; // No need to handle root.
        if (!localCopy_.exists(fqn)) return; // probably not a mv node anyway.
  
        try
        {
           String eventId = (String) get(fqn, NODEID_KEY);
           if (eventId == null)
              throw new RuntimeException("invlidate(): fqn to invlidate has null node id. fqn: " + fqn);
  
           if (nodeId_.equals(eventId)) return; // skip since this event is initiated by myself.
           localCopy_.remove(fqn);
        }
        catch (CacheException e)
        {
           e.printStackTrace();
        }
     }
  }
  
  
  
  1.1      date: 2006/10/31 08:01:13;  author: bwang;  state: Exp;JBossCache/old/src/org/jboss/cache/aop/SerializableObjectHandler.java
  
  Index: SerializableObjectHandler.java
  ===================================================================
  /*
   * JBoss, Home of Professional Open Source
   *
   * Distributable under LGPL license.
   * See terms of license at gnu.org.
   */
  
  package org.jboss.cache.aop;
  
  import org.apache.commons.logging.Log;
  import org.apache.commons.logging.LogFactory;
  import org.jboss.cache.Fqn;
  import org.jboss.cache.CacheException;
  
  import java.io.Serializable;
  import java.util.Map;
  import java.util.HashMap;
  
  /**
   * Handle Serializable object cache management.
   *
   * @author Ben Wang
   *         Date: Aug 4, 2005
   * @version $Id: SerializableObjectHandler.java,v 1.1 2006/10/31 08:01:13 bwang Exp $
   */
  public class SerializableObjectHandler  {
     protected PojoCache cache_;
     protected InternalDelegate internal_;
     protected final static Log log=LogFactory.getLog(SerializableObjectHandler.class);
  
     public SerializableObjectHandler(PojoCache cache, InternalDelegate internal)
     {
        cache_ = cache;
        internal_ = internal;
     }
  
  
     Object serializableObjectGet(Fqn fqn)
        throws CacheException
     {
        Object obj = internal_.get(fqn, InternalDelegate.SERIALIZED);
  /*
        if(cache_.isMarshallNonSerializable() && obj instanceof MarshalledObject )
        {
           try {
              obj = ((MarshalledObject)obj).get();
              if (log.isDebugEnabled()) {
                 log.debug("getObject(): since obj is non-serilaizable, we need to unmarshall it first: "
                 + obj.getClass());
              }
              internal_.localPut(fqn, InternalDelegate.SERIALIZED, obj);
           } catch (Exception e) {
              e.printStackTrace();
              throw new CacheException("Exception occurred during unmarshalling of non-serializable pojo: " +
              obj + " using JBoss Serialization", e);
           }
        }
        */
        return obj;
     }
  
  
     protected boolean serializableObjectPut(Fqn fqn, Object obj)
        throws CacheException
     {
        // Note that JBoss Serialization can serialize any type now.
        if (obj instanceof Serializable || cache_.isMarshallNonSerializable()) {
           if (log.isDebugEnabled()) {
              log.debug("putObject(): obj (" + obj.getClass() + ") is non-advisable but is Serializable. ");
           }
  
           putIntoCache(fqn, obj);
           return true;
        }
  
        // If the flag is set, we will marshall it using JBossSerialization
  /*      if(cache_.isMarshallNonSerializable())
        {
           if (log.isDebugEnabled()) {
              log.debug("serialiableObjectPut(): obj (" + obj.getClass() + ") is non-Serializable." +
              " Will marshall it first");
           }
           putIntoCache(fqn, obj);
           return true;
        }
  */
        return false;
     }
  
     protected void putIntoCache(Fqn fqn, Object obj)
             throws CacheException{
        Map map = new HashMap();
        internal_.putAopClazz(fqn, obj.getClass(), map);
  
        // Special optimization here.
        AOPInstance aopInstance = new AOPInstance();
        aopInstance.set(obj);
        map.put(AOPInstance.KEY, aopInstance);
  
        /*
        if(cache_.isMarshallNonSerializable())
        {
           try {
              obj = new MarshalledObject(obj);
           } catch (IOException e) {
              e.printStackTrace();
              throw new CacheException("Exception occurred during marshalling of non-serializable pojo: " +
              obj + " using JBoss Serialization", e);
           }
        } */
        // Note that we will only have one key in this fqn.
        map.put(InternalDelegate.SERIALIZED, obj);
        internal_.put(fqn, map);
     }
  
     protected boolean serializableObjectRemove(Fqn fqn)
        throws CacheException
     {
        // No need to do anything here since we will do clean up afterwards.
        return true;
     }
  
  }
  
  
  
  1.1      date: 2006/10/31 08:01:13;  author: bwang;  state: Exp;JBossCache/old/src/org/jboss/cache/aop/CollectionClassHandler.java
  
  Index: CollectionClassHandler.java
  ===================================================================
  /*
   * JBoss, Home of Professional Open Source
   *
   * Distributable under LGPL license.
   * See terms of license at gnu.org.
   */
  
  package org.jboss.cache.aop;
  
  import org.apache.commons.logging.Log;
  import org.apache.commons.logging.LogFactory;
  import org.jboss.cache.Fqn;
  import org.jboss.cache.CacheException;
  import org.jboss.cache.aop.collection.CollectionInterceptorUtil;
  import org.jboss.cache.aop.collection.AbstractCollectionInterceptor;
  import org.jboss.aop.proxy.ClassProxy;
  import org.jboss.aop.advice.Interceptor;
  import org.jboss.aop.InstanceAdvisor;
  
  import java.lang.reflect.Field;
  import java.util.*;
  
  /**
   * Handling the Collection class management.
   *
   * @author Ben Wang
   *         Date: Aug 4, 2005
   * @version $Id: CollectionClassHandler.java,v 1.1 2006/10/31 08:01:13 bwang Exp $
   */
  public class CollectionClassHandler {
     protected final static Log log=LogFactory.getLog(CollectionClassHandler.class);
     protected PojoCache cache_;
     protected InternalDelegate internal_;
     protected ObjectGraphHandler graphHandler_;
  
     public CollectionClassHandler(PojoCache cache, InternalDelegate internal, ObjectGraphHandler graphHandler)
     {
        cache_ = cache;
        internal_ = internal;
        graphHandler_ = graphHandler;
     }
  
     Object collectionObjectGet(Fqn fqn, Class clazz)
             throws CacheException
     {
        Object obj = null;
        try {
           if(Map.class.isAssignableFrom(clazz)) {
              Object map = clazz.newInstance();
              obj=CollectionInterceptorUtil.createMapProxy(cache_, fqn, clazz, (Map)map);
           } else if(List.class.isAssignableFrom(clazz)) {
              Object list = clazz.newInstance();
              obj=CollectionInterceptorUtil.createListProxy(cache_, fqn, clazz, (List)list);
           } else if(Set.class.isAssignableFrom(clazz)) {
              Object set = clazz.newInstance();
              obj=CollectionInterceptorUtil.createSetProxy(cache_, fqn, clazz, (Set)set);
           }
        } catch (Exception e) {
           throw new CacheException("failure creating proxy", e);
        }
  
        return obj;
     }
  
  
     boolean collectionObjectPut(Fqn fqn, Object obj) throws CacheException {
        boolean isCollection = false;
  
        CachedType type = null;
        AbstractCollectionInterceptor interceptor = null;
        if(obj instanceof ClassProxy)
        {
           Class originalClaz = obj.getClass().getSuperclass();
           interceptor = CollectionInterceptorUtil.getInterceptor((ClassProxy)obj);
           type = cache_.getCachedType(originalClaz);
        } else
        {
           type = cache_.getCachedType(obj.getClass());
        }
  
        if(obj instanceof ClassProxy)
        {
           // A proxy here. We may have multiple references.
           if(interceptor == null)
           {
              if(log.isDebugEnabled())
              {
                 log.debug("collectionObjectPut(): null interceptor. Could be removed previously. "+fqn);
              }
           } else
           {
              if( interceptor.isAttached() ) // If it is not attached, it is not active.
              {
                 // Let's check for object graph, e.g., multiple and circular references first
                 if (graphHandler_.objectGraphPut(fqn, interceptor, type, obj)) { // found cross references
                    return true;
                 }
              } else
              {
                 // Re-attach the interceptor to this fqn.
                 boolean copyToCache = true;
                 interceptor.attach(fqn, copyToCache);
                 internal_.putAopClazz(fqn, type.getType());
                 internal_.setPojo(fqn, obj);
                 return true; // we are done
              }
           }
        }
  
        if (obj instanceof Map) {
           if (log.isDebugEnabled()) {
              log.debug("collectionPutObject(): aspectized obj is a Map type of size: " + ((Map) obj).size());
           }
  
           internal_.putAopClazz(fqn, type.getType());
  
           // Let's replace it with a proxy if necessary
           Map map = (Map)obj;
           if( !(obj instanceof ClassProxy)) {
              Class clazz = obj.getClass();
              try {
                 obj=CollectionInterceptorUtil.createMapProxy(cache_, fqn, clazz, (Map)obj);
              } catch (Exception e) {
                 throw new CacheException("failure creating proxy", e);
              }
           }
  
           isCollection = true;
           // populate via the proxied collection
           for (Iterator i = map.entrySet().iterator(); i.hasNext();) {
              Map.Entry entry = (Map.Entry) i.next();
              ((Map)obj).put(entry.getKey(), entry.getValue());
           }
  
        } else if (obj instanceof List) {
           if (log.isDebugEnabled()) {
              log.debug("collectionPutObject(): aspectized obj is a List type of size: "
                    + ((List) obj).size());
           }
  
           List list = (List) obj;
           internal_.putAopClazz(fqn, type.getType());
  
           // Let's replace it with a proxy if necessary
           if( !(obj instanceof ClassProxy)) {
              Class clazz = obj.getClass();
              try {
                 obj=CollectionInterceptorUtil.createListProxy(cache_, fqn, clazz, (List)obj);
              } catch (Exception e) {
                 throw new CacheException("failure creating proxy", e);
              }
           }
  
           isCollection = true;
           // populate via the proxied collection
           for (Iterator i = list.iterator(); i.hasNext();) {
              ((List)obj).add(i.next());
           }
  
        } else if (obj instanceof Set) {
           if (log.isDebugEnabled()) {
              log.debug("collectionPutObject(): aspectized obj is a Set type of size: "
                    + ((Set) obj).size());
           }
  
           Set set = (Set) obj;
           internal_.putAopClazz(fqn, type.getType());
  
           // Let's replace it with a proxy if necessary
           if( !(obj instanceof ClassProxy)) {
              Class clazz = obj.getClass();
              try {
                 obj=CollectionInterceptorUtil.createSetProxy(cache_, fqn, clazz, (Set)obj);
              } catch (Exception e) {
                 throw new CacheException("failure creating proxy", e);
              }
           }
  
           isCollection = true;
           // populate via the proxied collection
           for (Iterator i = set.iterator(); i.hasNext();) {
              ((Set)obj).add(i.next());
           }
  
        }
  
        if(isCollection)
        {
           // Always initialize the ref count so that we can mark this as an AopNode.
           AOPInstance aopInstance = internal_.initializeAopInstance(fqn);
           cache_.put(fqn, AOPInstance.KEY, aopInstance);
  
           // Attach aopInstance to that interceptor
           BaseInterceptor baseInterceptor = (BaseInterceptor)CollectionInterceptorUtil.getInterceptor((ClassProxy)obj);
           baseInterceptor.setAopInstance(aopInstance);
  
           internal_.setPojo(aopInstance, obj);
        }
        return isCollection;
     }
  
     boolean collectionObjectRemove(Fqn fqn, boolean removeCacheInterceptor,
                                    boolean evict) throws CacheException
     {
        Class clazz = internal_.peekAopClazz(fqn);
  
        if (!Map.class.isAssignableFrom(clazz) && !Collection.class.isAssignableFrom(clazz))
        {
           return false;
        }
  
        Object obj = cache_.getObject(fqn);
        if( !(obj instanceof ClassProxy))
        {
           throw new RuntimeException("CollectionClassHandler.collectionRemoveObject(): object is not a proxy :" +obj);
        }
  
        Interceptor interceptor = CollectionInterceptorUtil.getInterceptor((ClassProxy)obj);
        boolean removeFromCache = true;
        ((AbstractCollectionInterceptor)interceptor).detach(removeFromCache); // detach the interceptor. This will trigger a copy and remove.
  
        return true;
     }
  
     void collectionReplaceWithProxy(Object obj, Object value, Field field, Fqn tmpFqn)
             throws CacheException
     {
        // If value (field member) is of Collection type, e.g., composite class
        // that contains Collection member, we will swap out the old reference
        // with the proxy one.
        // This can probably be optimized with check for instanceof proxy
        if( value instanceof Map || value instanceof List || value instanceof Set ) {
           Object newValue = cache_.getObject(tmpFqn);
           try {
              field.set(obj, newValue);
              cache_.addUndoCollectionProxy(field, obj, value);
           } catch (IllegalAccessException e) {
              log.error("collectionReplaceWithProxy(): Can't swap out the Collection class of field " +field.getName() +
                    "Exception " +e);
              throw new CacheException("CollectionClassHandler.collectionReplaceWithProxy(): Can't swap out the Collection class of field \" +field.getName(),"
                    +e);
           }
        }
     }
  }
  
  
  
  1.1      date: 2006/10/31 08:01:13;  author: bwang;  state: Exp;JBossCache/old/src/org/jboss/cache/aop/TreeCacheAopView.java
  
  Index: TreeCacheAopView.java
  ===================================================================
  /*
   * JBoss, the OpenSource J2EE webOS
   *
   * Distributable under LGPL license.
   * See terms of license at gnu.org.
   * Created on March 25 2003
   */
  package org.jboss.cache.aop;
  
  
  import org.apache.commons.logging.Log;
  import org.apache.commons.logging.LogFactory;
  import org.jboss.cache.CacheListener;
  import org.jboss.cache.CacheSPI;
  import org.jboss.cache.Fqn;
  import org.jboss.cache.TreeCacheView;
  import org.jboss.cache.factories.XmlConfigurationParser;
  import org.jgroups.View;
  
  import javax.swing.*;
  import javax.swing.event.TableModelEvent;
  import javax.swing.event.TableModelListener;
  import javax.swing.event.TreeSelectionEvent;
  import javax.swing.event.TreeSelectionListener;
  import javax.swing.table.DefaultTableModel;
  import javax.swing.table.TableColumn;
  import javax.swing.tree.DefaultMutableTreeNode;
  import javax.swing.tree.DefaultTreeModel;
  import javax.swing.tree.TreeNode;
  import javax.swing.tree.TreePath;
  import javax.swing.tree.TreeSelectionModel;
  import java.awt.*;
  import java.awt.event.ActionEvent;
  import java.awt.event.MouseAdapter;
  import java.awt.event.MouseEvent;
  import java.awt.event.MouseListener;
  import java.awt.event.WindowEvent;
  import java.awt.event.WindowListener;
  import java.io.File;
  import java.util.HashMap;
  import java.util.Iterator;
  import java.util.Map;
  import java.util.Set;
  import java.util.StringTokenizer;
  import java.util.Vector;
  
  //import java.util.List;
  
  /**
   * Graphical view of a ReplicatedTree (using the MVC paradigm). An instance of this class needs to be given a
   * reference to the underlying model (ReplicatedTree) and needs to registers as a ReplicatedTreeListener. Changes
   * to the tree structure are propagated from the model to the view (via ReplicatedTreeListener), changes from the
   * GUI (e.g. by a user) are executed on the tree model (which will broadcast the changes to all replicas).<p>
   * The view itself caches only the nodes, but doesn't cache any of the data (HashMap) associated with it. When
   * data needs to be displayed, the underlying tree will be accessed directly.
   *
   * @author Ben Wang
   * @version $Revision: 1.1 $
   * @deprecated Not used now. Use TreeCacheView2 directly.
   */
  public class TreeCacheAopView
  {
     TreeCacheAopGui gui_ = null;
     PojoCache cache_ = null;
     static Log log = LogFactory.getLog(TreeCacheAopView.class.getName());
  
     public TreeCacheAopView(PojoCache cache) throws Exception
     {
        this.cache_ = cache;
     }
  
     public void start() throws Exception
     {
        if (gui_ == null)
        {
           log.info("start(): creating the GUI");
           gui_ = new TreeCacheAopGui(cache_);
        }
     }
  
     public void stop()
     {
        if (gui_ != null)
        {
           log.info("stop(): disposing the GUI");
           gui_.dispose();
           gui_ = null;
        }
     }
  
     void populateTree(String dir) throws Exception
     {
        File file = new File(dir);
  
        if (!file.exists()) return;
  
        put(dir, null);
  
        if (file.isDirectory())
        {
           String[] children = file.list();
           if (children != null && children.length > 0)
           {
              for (int i = 0; i < children.length; i++)
                 populateTree(dir + "/" + children[i]);
           }
        }
     }
  
     void put(String fqn, Map m)
     {
        try
        {
           cache_.put(fqn, m);
        }
        catch (Throwable t)
        {
           log.error("TreeCacheAopView.put(): " + t);
        }
     }
  
     public static void main(String args[])
     {
        PojoCache tree = null;
        TreeCacheAopView demo;
        String start_directory = null;
        String resource = "META-INF/replSync-service.xml";
  
        for (int i = 0; i < args.length; i++)
        {
           if (args[i].equals("-config"))
           {
              resource = args[++i];
              continue;
           }
           help();
           return;
        }
  
  
        try
        {
           tree = new PojoCache();
           tree.setConfiguration(new XmlConfigurationParser().parseFile(resource));
  
           tree.getNotifier().addCacheListener(new TreeCacheView.MyListener());
           tree.create();
           tree.start();
  
           Runtime.getRuntime().addShutdownHook(new ShutdownThread(tree));
  
           demo = new TreeCacheAopView(tree);
           demo.start();
           if (start_directory != null && start_directory.length() > 0)
           {
              demo.populateTree(start_directory);
           }
        }
        catch (Exception ex)
        {
           ex.printStackTrace();
        }
     }
  
  
     static class ShutdownThread extends Thread
     {
        PojoCache tree = null;
  
        ShutdownThread(PojoCache tree)
        {
           this.tree = tree;
        }
  
        public void run()
        {
           tree.stop();
        }
     }
  
     static void help()
     {
        System.out.println("TreeCacheAopView [-help] [-config <configuration file (XML)]" +
                "[-mbean_name <name of TreeCache MBean>] " +
                "[-start_directory <dirname>] [-props <props>] " +
                "[-use_queue <true/false>] [-queue_interval <ms>] " +
                "[-queue_max_elements <num>]");
     }
  
  }
  
  
  class TreeCacheAopGui extends JFrame implements WindowListener, CacheListener,
          TreeSelectionListener, TableModelListener
  {
     private static final long serialVersionUID = -7044654602510185865L;
  
     PojoCache cache_;
     DefaultTreeModel tree_model = null;
     Log log = LogFactory.getLog(getClass());
     JTree jtree = null;
     DefaultTableModel table_model = new DefaultTableModel();
     JTable table = new JTable(table_model);
     MyNode root = new MyNode(SEP, Fqn.fromString(SEP));
     String props = null;
     String selected_node = null;
     JPanel tablePanel = null;
     JMenu operationsMenu = null;
     JPopupMenu operationsPopup = null;
     JMenuBar menubar = null;
     boolean use_system_exit = false;
     static String SEP = Fqn.SEPARATOR;
     private static final int KEY_COL_WIDTH = 20;
     private static final int VAL_COL_WIDTH = 300;
     final String STRING = String.class.getName();
     final String MAP = Map.class.getName();
     final String OBJECT = Object.class.getName();
     String currentNodeSelected = null;
  
     public TreeCacheAopGui(PojoCache cache) throws Exception
     {
        this.cache_ = cache;
  
        cache_.getNotifier().addCacheListener(this);
        addNotify();
        setTitle("TreeCacheAopGui: mbr=" + getLocalAddress());
  
        tree_model = new DefaultTreeModel(root);
        jtree = new JTree(tree_model);
        jtree.setDoubleBuffered(true);
        jtree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
  
        JPanel panel = new JPanel();
        panel.setLayout(new BorderLayout());
        JScrollPane scroll_pane = new JScrollPane(jtree);
        panel.add(scroll_pane, BorderLayout.CENTER);
  
        populateTree();
  
        getContentPane().add(panel, BorderLayout.CENTER);
        addWindowListener(this);
  
        table_model.setColumnIdentifiers(new String[]{"Name", "Value"});
        table_model.addTableModelListener(this);
  
        setTableColumnWidths();
  
        tablePanel = new JPanel();
        tablePanel.setLayout(new BorderLayout());
        tablePanel.add(table.getTableHeader(), BorderLayout.NORTH);
        tablePanel.add(table, BorderLayout.CENTER);
  
        getContentPane().add(tablePanel, BorderLayout.SOUTH);
  
        jtree.addTreeSelectionListener(this);//REVISIT
  
        MouseListener ml = new MouseAdapter()
        {
           public void mouseClicked(MouseEvent e)
           {
              int selRow = jtree.getRowForLocation(e.getX(), e.getY());
              TreePath selPath = jtree.getPathForLocation(e.getX(), e.getY());
              if (selRow != -1)
              {
                 selected_node = makeFQN(selPath.getPath());
                 jtree.setSelectionPath(selPath);
  
                 if (e.getModifiers() == java.awt.event.InputEvent.BUTTON3_MASK)
                 {
                    operationsPopup.show(e.getComponent(),
                            e.getX(), e.getY());
                 }
              }
           }
        };
  
        jtree.addMouseListener(ml);
  
        createMenus();
        setLocation(50, 50);
        setSize(getInsets().left + getInsets().right + 485,
                getInsets().top + getInsets().bottom + 367);
  
        init();
        setVisible(true);
     }
  
     void setSystemExit(boolean flag)
     {
        use_system_exit = flag;
     }
  
     public void windowClosed(WindowEvent event)
     {
     }
  
     public void windowDeiconified(WindowEvent event)
     {
     }
  
     public void windowIconified(WindowEvent event)
     {
     }
  
     public void windowActivated(WindowEvent event)
     {
     }
  
     public void windowDeactivated(WindowEvent event)
     {
     }
  
     public void windowOpened(WindowEvent event)
     {
     }
  
     public void windowClosing(WindowEvent event)
     {
        dispose();
     }
  
  
     public void tableChanged(TableModelEvent evt)
     {
        int row, col;
        String key, val;
  
        if (evt.getType() == TableModelEvent.UPDATE)
        {
           row = evt.getFirstRow();
           col = evt.getColumn();
           if (col == 0)
           {  // set()
              key = (String) table_model.getValueAt(row, col);
              val = (String) table_model.getValueAt(row, col + 1);
              if (key != null && val != null)
              {
                 // tree.put(selected_node, key, val);
  
                 try
                 {
                    cache_.put(selected_node, key, val);
                 }
                 catch (Exception e)
                 {
                    e.printStackTrace();
                 }
  
              }
           }
           else
           {          // add()
              key = (String) table_model.getValueAt(row, col - 1);
              val = (String) table.getValueAt(row, col);
              if (key != null && val != null)
              {
                 put(selected_node, key, val);
              }
           }
        }
     }
  
  
     public void valueChanged(TreeSelectionEvent evt)
     {
        TreePath path = evt.getPath();
        String fqn = SEP;
        String component_name;
        Map data = null;
  
        for (int i = 0; i < path.getPathCount(); i++)
        {
           component_name = ((MyNode) path.getPathComponent(i)).name;
           if (component_name.equals(SEP))
              continue;
           if (fqn.equals(SEP))
              fqn += component_name;
           else
              fqn = fqn + SEP + component_name;
        }
        data = getData(fqn);
        System.out.println("valueChanged(): fqn: " + fqn + " data: " + data);
        if (data != null)
        {
           getContentPane().add(tablePanel, BorderLayout.SOUTH);
           populateTable(data);
           validate();
        }
        else
        {
           clearTable();
           getContentPane().remove(tablePanel);
           validate();
        }
     }
  
     /* ------------------ ReplicatedTree.ReplicatedTreeListener interface ------------ */
  
     public void nodeCreated(Fqn fqn, boolean pre, boolean isLocal)
     {
        if (!pre)
        {
           MyNode n, p;
  
           n = root.add(fqn);
           if (n != null)
           {
              p = (MyNode) n.getParent();
              tree_model.reload(p);
              jtree.scrollPathToVisible(new TreePath(n.getPath()));
           }
        }
     }
  
     public void nodeRemoved(Fqn fqn, boolean pre, boolean isLocal, Map data)
     {
        if (!pre)
        {
           MyNode n;
           TreeNode par;
  
           n = root.findNode(fqn.toString());
           if (n != null)
           {
              n.removeAllChildren();
              par = n.getParent();
              n.removeFromParent();
              tree_model.reload(par);
           }
        }
     }
  
     public void nodeLoaded(Fqn fqn, boolean pre, Map data)
     {
        nodeCreated(fqn, pre, true);
     }
  
     public void nodeEvicted(Fqn fqn, boolean pre, boolean isLocal)
     {
        nodeRemoved(fqn, pre, isLocal, null);
     }
  
     public void nodeMoved(Fqn from, Fqn to, boolean pre)
     {
     }
  
     public void nodeActivated(Fqn fqn, boolean pre)
     {
     }
  
     public void nodePassivated(Fqn fqn, boolean pre)
     {
     }
  
  
     public void nodeModified(final Fqn fqn, boolean pre, boolean isLocal, Map d)
     {
        if (!pre)
        {
           // needs to be in a separate thread because Swing thread is different from callback thread,
           // resulting in a lock until lock timeout kicks in
           // new Thread() {
           //  public void run() {
           Map data;
           if (currentNodeSelected != null && !currentNodeSelected.equals(fqn.toString()))
              return; // DataNode modified is not visible. Continue...
           data = getData(fqn.toString());
           populateTable(data); // REVISIT
           //   }
           //}.start();
  
           /*
             poulateTable is the current table being shown is the info of the node. that is modified.
           */
        }
     }
  
     public void nodeVisited(Fqn fqn, boolean pre)
     {
     }
  
     public void cacheStarted(CacheSPI cache)
     {
     }
  
     public void cacheStopped(CacheSPI cache)
     {
     }
  
     public void viewChange(final View new_view)
     {
        new Thread()
        {
           public void run()
           {
              Vector mbrship;
              if (new_view != null && (mbrship = new_view.getMembers()) != null)
              {
                 _put(SEP, "members", mbrship);
                 _put(SEP, "coordinator", mbrship.firstElement());
              }
           }
        }.start();
     }
  
     /* ---------------- End of ReplicatedTree.ReplicatedTreeListener interface -------- */
  
     /*----------------- Runnable implementation to make View change calles in AWT Thread ---*/
  
     public void run()
     {
  
     }
  
     /* ----------------------------- Private Methods ---------------------------------- */
  
     /**
      * Fetches all data from underlying tree model and display it graphically
      */
     void init()
     {
        Vector mbrship = null;
  
        addGuiNode(SEP);
  
        mbrship = getMembers() != null ? (Vector) getMembers().clone() : null;
        if (mbrship != null && mbrship.size() > 0)
        {
           _put(SEP, "members", mbrship);
           _put(SEP, "coordinator", mbrship.firstElement());
        }
     }
  
  
     /**
      * Fetches all data from underlying tree model and display it graphically
      */
     private void populateTree()
     {
        addGuiNode(SEP);
     }
  
  
     /**
      * Recursively adds GUI nodes starting from fqn
      */
     void addGuiNode(String fqn)
     {
        Set children;
        String child_name;
  
        if (fqn == null) return;
  
        // 1 . Add myself
        root.add(Fqn.fromString(fqn));
  
        // 2. Then add my children
        children = getChildrenNames(fqn);
        if (children != null)
        {
           for (Iterator it = children.iterator(); it.hasNext();)
           {
              child_name = (String) it.next();
              addGuiNode(fqn + SEP + child_name);
           }
        }
     }
  
  
     String makeFQN(Object[] path)
     {
        StringBuffer sb = new StringBuffer("");
        String tmp_name;
  
        if (path == null) return null;
        for (int i = 0; i < path.length; i++)
        {
           tmp_name = ((MyNode) path[i]).name;
           if (tmp_name.equals(SEP))
           {
           }
           else
              sb.append(SEP + tmp_name);
        }
        tmp_name = sb.toString();
        if (tmp_name.length() == 0)
           return SEP;
        else
           return tmp_name;
     }
  
     void clearTable()
     {
        int num_rows = table.getRowCount();
  
        if (num_rows > 0)
        {
           for (int i = 0; i < num_rows; i++)
              table_model.removeRow(0);
           table_model.fireTableRowsDeleted(0, num_rows - 1);
           repaint();
        }
     }
  
  
     void populateTable(Map data)
     {
        String key, strval = "<null>";
        Object val;
        int num_rows = 0;
        Map.Entry entry;
  
        if (data == null) return;
        num_rows = data.size();
        clearTable();
  
        if (num_rows > 0)
        {
           for (Iterator it = data.entrySet().iterator(); it.hasNext();)
           {
              entry = (Map.Entry) it.next();
              key = (String) entry.getKey();
              val = entry.getValue();
              if (val != null) strval = val.toString();
              table_model.addRow(new Object[]{key, strval});
           }
           table_model.fireTableRowsInserted(0, num_rows - 1);
           validate();
        }
     }
  
     private void setTableColumnWidths()
     {
        table.sizeColumnsToFit(JTable.AUTO_RESIZE_NEXT_COLUMN);
        TableColumn column = null;
        column = table.getColumnModel().getColumn(0);
        column.setMinWidth(KEY_COL_WIDTH);
        column.setPreferredWidth(KEY_COL_WIDTH);
        column = table.getColumnModel().getColumn(1);
        column.setPreferredWidth(VAL_COL_WIDTH);
     }
  
     private void createMenus()
     {
        menubar = new JMenuBar();
        operationsMenu = new JMenu("Operations");
        AddNodeAction addNode = new AddNodeAction();
        addNode.putValue(AbstractAction.NAME, "Add to this node");
        RemoveNodeAction removeNode = new RemoveNodeAction();
        removeNode.putValue(AbstractAction.NAME, "Remove this node");
        AddModifyDataForNodeAction addModAction = new AddModifyDataForNodeAction();
        addModAction.putValue(AbstractAction.NAME, "Add/Modify data");
        PrintLockInfoAction print_locks = new PrintLockInfoAction();
        print_locks.putValue(AbstractAction.NAME, "Print lock information (stdout)");
        ReleaseAllLocksAction release_locks = new ReleaseAllLocksAction();
        release_locks.putValue(AbstractAction.NAME, "Release all locks");
        ExitAction exitAction = new ExitAction();
        exitAction.putValue(AbstractAction.NAME, "Exit");
        operationsMenu.add(addNode);
        operationsMenu.add(removeNode);
        operationsMenu.add(addModAction);
        operationsMenu.add(print_locks);
        operationsMenu.add(release_locks);
        operationsMenu.add(exitAction);
        menubar.add(operationsMenu);
        setJMenuBar(menubar);
  
        operationsPopup = new JPopupMenu();
        operationsPopup.add(addNode);
        operationsPopup.add(removeNode);
        operationsPopup.add(addModAction);
     }
  
     Object getLocalAddress()
     {
        try
        {
           return cache_.getLocalAddress();
        }
        catch (Throwable t)
        {
           log.error("TreeCacheAopGui.getLocalAddress(): " + t);
           return null;
        }
     }
  
     Map getData(String fqn)
     {
        Map data;
        Set keys;
        String key;
        Object value;
  
        if (fqn == null) return null;
        // Let's track the node displayed.
        currentNodeSelected = fqn;
  
  //		System.out.println("findNode(): fqnStr: " +fqn);
        MyNode node = root.findNode(fqn);
        if (node == null) return null;
        // System.out.println("findNode(): fqnStr: " + fqn + " node fqn: " + node.getFqn().toString());
        keys = getKeys(node.getFqn());
        if (keys == null) return null;
        data = new HashMap();
        for (Iterator it = keys.iterator(); it.hasNext();)
        {
           key = it.next().toString();
           value = get(node.getFqn(), key);
           if (value != null)
              data.put(key, value);
        }
        return data;
     }
  
  
     void put(String fqn, Map m)
     {
        try
        {
           cache_.put(fqn, m);
        }
        catch (Throwable t)
        {
           log.error("TreeCacheAopGui.put(): " + t);
        }
     }
  
  
     private void put(String fqn, String key, Object value)
     {
        try
        {
           cache_.put(fqn, key, value);
        }
        catch (Throwable t)
        {
           log.error("TreeCacheAopGui.put(): " + t);
        }
     }
  
     void _put(String fqn, String key, Object value)
     {
        try
        {
           cache_._put(null, fqn, key, value, false);
        }
        catch (Throwable t)
        {
           log.error("TreeCacheAopGui._put(): " + t);
        }
     }
  
     Set getKeys(Fqn fqn)
     {
        try
        {
           return cache_.getKeys(fqn);
        }
        catch (Throwable t)
        {
           t.printStackTrace();
           log.error("TreeCacheAopGui.getKeys(): " + t);
           return null;
        }
     }
  
     Object get(Fqn fqn, String key)
     {
        try
        {
           return cache_.get(fqn, key);
        }
        catch (Throwable t)
        {
           log.error("TreeCacheAopGui.get(): " + t);
           return null;
        }
     }
  
     Set getChildrenNames(String fqn)
     {
        try
        {
           return cache_.getChildrenNames(fqn);
        }
        catch (Throwable t)
        {
           log.error("TreeCacheAopGui.getChildrenNames(): " + t);
           return null;
        }
     }
  
     Vector getMembers()
     {
        try
        {
           return cache_.getMembers();
        }
        catch (Throwable t)
        {
           log.error("TreeCacheAopGui.getMembers(): " + t);
           return null;
        }
     }
  
     /* -------------------------- End of Private Methods ------------------------------ */
  
     /*----------------------- Actions ---------------------------*/
  
     class ExitAction extends AbstractAction
     {
        private static final long serialVersionUID = 3309349735197545040L;
  
        public void actionPerformed(ActionEvent e)
        {
           dispose();
           System.exit(0);
        }
     }
  
     class AddNodeAction extends AbstractAction
     {
        private static final long serialVersionUID = -1846726449742865362L;
  
        public void actionPerformed(ActionEvent e)
        {
           JTextField fqnTextField = new JTextField();
           if (selected_node != null)
              fqnTextField.setText(selected_node);
           Object[] information = {"Enter fully qualified name",
                   fqnTextField};
           final String btnString1 = "OK";
           final String btnString2 = "Cancel";
           Object[] options = {btnString1, btnString2};
           int userChoice = JOptionPane.showOptionDialog(null,
                   information,
                   "Add DataNode",
                   JOptionPane.YES_NO_OPTION,
                   JOptionPane.PLAIN_MESSAGE,
                   null,
                   options,
                   options[0]);
           if (userChoice == 0)
           {
              String userInput = fqnTextField.getText();
              put(userInput, null);
           }
        }
     }
  
  
     class PrintLockInfoAction extends AbstractAction
     {
        private static final long serialVersionUID = -1547808705937201967L;
  
        public void actionPerformed(ActionEvent e)
        {
           System.out.println("\n*** lock information ****\n" + cache_.printLockInfo());
        }
     }
  
     class ReleaseAllLocksAction extends AbstractAction
     {
        private static final long serialVersionUID = -856964838566617006L;
  
        public void actionPerformed(ActionEvent e)
        {
           cache_.releaseAllLocks("/");
        }
     }
  
     class RemoveNodeAction extends AbstractAction
     {
        private static final long serialVersionUID = 116863545772054467L;
  
        public void actionPerformed(ActionEvent e)
        {
           try
           {
              cache_.remove(selected_node);
           }
           catch (Throwable t)
           {
              log.error("RemoveNodeAction.actionPerformed(): " + t);
           }
        }
     }
  
     class AddModifyDataForNodeAction extends AbstractAction
     {
        private static final long serialVersionUID = 8035968024123769723L;
  
        public void actionPerformed(ActionEvent e)
        {
           Map data = getData(selected_node);
           if (data != null)
           {
           }
           else
           {
              clearTable();
              data = new HashMap();
              data.put("Add Key", "Add Value");
  
           }
           populateTable(data);
           getContentPane().add(tablePanel, BorderLayout.SOUTH);
           validate();
  
        }
     }
  
  
     class MyNode extends DefaultMutableTreeNode
     {
        private static final long serialVersionUID = -3391522498362829190L;
        String name = "<unnamed>"; // node name
        Fqn fqn;   // corresponding fqn
  
        MyNode(String name, Fqn fqn)
        {
           this.fqn = fqn;
           this.name = name;
        }
  
        public Fqn getFqn()
        {
           return fqn;
        }
  
        /**
         * Adds a new node to the view. Intermediary nodes will be created if they don't yet exist.
         * Returns the first node that was created or null if node already existed
         */
        public MyNode add(Fqn fqn)
        {
           MyNode curr, n, ret = null;
           StringTokenizer tok;
           String child_name;
  
           if (fqn == null) return null;
           curr = this;
           String fqnStr = fqn.toString();
           tok = new StringTokenizer(fqnStr, TreeCacheAopGui.SEP);
  
           int i = 0;
           while (tok.hasMoreTokens())
           {
              child_name = tok.nextToken();
              n = curr.findChild(child_name);
              if (n == null)
              {
                 n = new MyNode(child_name, fqn.getFqnChild(i + 1));
                 if (ret == null) ret = n;
                 curr.add(n);
              }
              curr = n;
              i++;
           }
           return ret;
        }
  
  
        /**
         * Removes a node from the view. Child nodes will be removed as well
         */
        public void remove(String fqn)
        {
           removeFromParent();
        }
  
  
        MyNode findNode(String fqn)
        {
           MyNode curr, n;
           StringTokenizer tok;
           String child_name;
  
           if (fqn == null) return null;
           curr = this;
           tok = new StringTokenizer(fqn, TreeCacheAopGui.SEP);
  
           while (tok.hasMoreTokens())
           {
              child_name = tok.nextToken();
              n = curr.findChild(child_name);
              if (n == null)
                 return null;
              curr = n;
           }
           return curr;
        }
  
  
        MyNode findChild(String relative_name)
        {
           MyNode child;
  
           if (relative_name == null || getChildCount() == 0)
              return null;
           for (int i = 0; i < getChildCount(); i++)
           {
              child = (MyNode) getChildAt(i);
              if (child.name == null)
              {
                 continue;
              }
  
              if (child.name.equals(relative_name))
                 return child;
           }
           return null;
        }
  
  
        String print(int indent)
        {
           StringBuffer sb = new StringBuffer();
  
           for (int i = 0; i < indent; i++)
              sb.append(" ");
           if (!isRoot())
           {
              if (name == null)
                 sb.append("/<unnamed>");
              else
              {
                 sb.append(TreeCacheAopGui.SEP + name);
              }
           }
           sb.append("\n");
           if (getChildCount() > 0)
           {
              if (isRoot())
                 indent = 0;
              else
                 indent += 4;
              for (int i = 0; i < getChildCount(); i++)
                 sb.append(((MyNode) getChildAt(i)).print(indent));
           }
           return sb.toString();
        }
  
  
        public String toString()
        {
           return name;
        }
  
     }
  
  
  }
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  1.1      date: 2006/10/31 08:01:13;  author: bwang;  state: Exp;JBossCache/old/src/org/jboss/cache/aop/CacheInterceptor.java
  
  Index: CacheInterceptor.java
  ===================================================================
  /*
   * JBoss, the OpenSource J2EE webOS
   *
   * Distributable under LGPL license.
   * See terms of license at gnu.org.
   */
  package org.jboss.cache.aop;
  
  import org.apache.commons.logging.Log;
  import org.apache.commons.logging.LogFactory;
  import org.jboss.aop.joinpoint.FieldReadInvocation;
  import org.jboss.aop.joinpoint.FieldWriteInvocation;
  import org.jboss.aop.joinpoint.Invocation;
  import org.jboss.aop.joinpoint.MethodInvocation;
  import org.jboss.aop.joinpoint.FieldInvocation;
  import org.jboss.aop.Advised;
  import org.jboss.aop.InstanceAdvisor;
  import org.jboss.aop.Advisor;
  import org.jboss.cache.Fqn;
  import org.jboss.cache.aop.util.AopUtil;
  import org.jboss.cache.aop.references.FieldPersistentReference;
  
  import java.io.Externalizable;
  import java.io.ObjectInput;
  import java.io.ObjectOutput;
  import java.lang.reflect.Field;
  import java.lang.reflect.Method;
  import java.util.Iterator;
  
  /**
   * Created: Sat Apr 26 10:35:01 2003
   *
   * @author Harald Gliebe
   * @author Ben Wang
   */
  
  public class CacheInterceptor implements BaseInterceptor
  {
     protected static final Log log_ = LogFactory.getLog(CacheInterceptor.class);
     protected PojoCache cache;
     protected CachedType type;
     protected Fqn fqn;
     boolean checkSerialization;
     protected String name;
     protected AOPInstance aopInstance;
  
     static Method writeExternal, readExternal;
  
     static
     {
        try {
           writeExternal =
                 Externalizable.class.getMethod("writeExternal",
                       new Class[]{ObjectOutput.class});
           readExternal =
                 Externalizable.class.getMethod("readExternal",
                       new Class[]{ObjectInput.class});
        } catch (Exception e) {
           e.printStackTrace();
        }
     }
  
     public CacheInterceptor(PojoCache cache, Fqn fqn, CachedType type)
     {
        this.cache = cache;
        this.fqn = fqn;
        this.type = type;
        checkSerialization =
              !WriteReplaceable.class.isAssignableFrom(type.getType());
     }
  
     public AOPInstance getAopInstance() {
        return aopInstance;
     }
  
     public void setAopInstance(AOPInstance aopInstance) {
        this.aopInstance = aopInstance;
     }
  
     public String getName()
     {
        if(name == null)
        {
           this.name = "CacheInterceptor on [" + fqn + "]";
        }
        return name;
     }
  
     public Object invoke(Invocation invocation) throws Throwable
     {
        // Check if CLASS_INTERNAL exists. If not, that means we are done. We need to remove ourself.
        // Note that if speed is important, we will need to perform the detach step pro-actively,
        // that is, use a listener to listen for the removeObject event.
        if(isPojoDetached(invocation))
        {
           return invocation.invokeNext();  // invoke the in-memory pojo directly
        }
  
        if (invocation instanceof FieldWriteInvocation) {
           FieldInvocation fieldInvocation =
                 (FieldInvocation) invocation;
  
           Advisor advisor = fieldInvocation.getAdvisor();
           Field field = fieldInvocation.getField();
  
           // Only if this field is replicatable. static, transient and final are not.
           CachedType fieldType = cache.getCachedType(field.getType());
           CachedType parentType = cache.getCachedType(field.getDeclaringClass());
           if(!isNonReplicatable(field, advisor, parentType)) {
              Object value = ((FieldWriteInvocation)fieldInvocation).getValue();
              if (fieldType.isImmediate() || hasSerializableAnnotation(field, advisor, parentType)) {
                 cache.put(fqn, field.getName(), value);
              } else {
                 //cache.putObject(((Fqn)fqn.clone()).add(field.getName()), value);
                 cache.putObject(new Fqn(fqn, field.getName()), value);
              }
           }
  
        } else if (invocation instanceof FieldReadInvocation) {
           FieldInvocation fieldInvocation =
                 (FieldInvocation) invocation;
           Field field = fieldInvocation.getField();
           Advisor advisor = fieldInvocation.getAdvisor();
  
           // Only if this field is replicatable
           CachedType fieldType = cache.getCachedType(field.getType());
           CachedType parentType = cache.getCachedType(field.getDeclaringClass());
           if( !isNonReplicatable(field, advisor, parentType)) {
              Object result;
              if (fieldType.isImmediate()|| hasSerializableAnnotation(field, advisor, parentType)) {
                 result = cache.get(fqn, field.getName());
              } else {
                 //result = cache.getObject(((Fqn)fqn.clone()).add(field.getName()));
                 result = cache.getObject(new Fqn(fqn, field.getName()));
              }
  
              // if result is null, we need to make sure the in-memory reference is null
              // as well. If it is not, then we know this one is null because it has
              // been evicted. Will need to reconstruct it
              if(result != null)
                 return result;
              else {
                 // TODO There is a chance of recursive loop here if caller tries to print out obj that will trigger the fieldRead interception.
                 Object value = invocation.getTargetObject();
                 if(value == null || field.get(value) == null)   // if both are null, we know this is null as well.
                    return null;
                 else {
                    if(log_.isTraceEnabled()) {
                       log_.trace("invoke(): DataNode on fqn: " +fqn + " has obviously been evicted. Will need to reconstruct it");
                    }
  
                    cache.putObject(fqn, value);
                 }
              }
           }
        } else if (checkSerialization) { // Have no use now.
           MethodInvocation methodInvocation = (MethodInvocation) invocation;
           Method method = methodInvocation.getMethod();
  
           if (method != null
                 && method.getName().equals("writeReplace")
                 && method.getReturnType().equals(Object.class)
                 && method.getParameterTypes().length == 0) {
  
              beforeSerialization(invocation.getTargetObject());
           } else if (method == writeExternal) {
              Object target = methodInvocation.getTargetObject();
              beforeSerialization(target);
           }
        }
  
        return invocation.invokeNext();
  
     }
  
     /**
      * See if this field is non-replicatable such as @Transient or transient modifier.
      */
     private boolean isNonReplicatable(Field field, Advisor advisor, CachedType type)
     {
        if(CachedType.hasAnnotation(field.getDeclaringClass(), advisor, type))
        {
           if(CachedType.hasTransientAnnotation(field, advisor)) return true;
        }
  
        if(CachedType.isPrimitiveNonReplicatable(field)) return true;
  
        return false;
     }
  
     private boolean hasSerializableAnnotation(Field field, Advisor advisor, CachedType type)
     {
        if(CachedType.hasAnnotation(field.getDeclaringClass(), advisor, type))
        {
           if(CachedType.hasSerializableAnnotation(field, advisor)) return true;
        }
  
        return false;
     }
  
     /**
      * Check if the pojo is detached already. If it is and we still have the cache interceptor on
      * this pojo, we will go ahead and remove it since it should not be there in the first place.
      * @param invocation
      * @return
      * @throws Exception
      */
     protected boolean isPojoDetached(Invocation invocation) throws Exception
     {
        boolean detached = false;
        if( !cache.exists(fqn, InternalDelegate.CLASS_INTERNAL) )
        {
           detached = true;
           Object obj = invocation.getTargetObject();
           if(! (obj instanceof Advised) )
              throw new RuntimeException("Interception on non-advised pojo " +obj.toString());
  
           InstanceAdvisor advisor = ((Advised)obj)._getInstanceAdvisor();
           CacheInterceptor interceptor = (CacheInterceptor) AopUtil.findCacheInterceptor(advisor);
           if (interceptor != null)
           {
              if (log_.isDebugEnabled()) {
                 log_.debug("isPojoDetached(): removed cache interceptor fqn: " + fqn + " interceptor: "+interceptor);
              }
              advisor.removeInterceptor(interceptor.getName());
           }
        }
  
        return detached;
     }
  
     protected void checkCacheConsistency() throws Exception
     {
        if (this != cache.peek(fqn, AOPInstance.KEY)) {
           throw new RuntimeException("Cache inconsistency: Outdated AOPInstance");
        }
     }
  
     public void beforeSerialization(Object target) throws Exception
     {
  
        // fill objects
        for (Iterator i = type.getFields().iterator(); i.hasNext();) {
           Field field = (Field)(((FieldPersistentReference) i.next())).get();
           CachedType fieldType = cache.getCachedType(field.getType());
           Object value = null;
           if (fieldType.isImmediate()) {
              value = cache.get(fqn, field.getName());
           } else {
              //		value = removeObject(fqn+TreeCache.SEPARATOR+field.getName());
              //value = cache.getObject(((Fqn)fqn.clone()).add(field.getName()));
              value = cache.getObject(new Fqn(fqn, field.getName()));
           }
           //	    System.out.println("Setting field " + field.getName() + "[" + field.getDeclaringClass() + "] of "+ target.getClass() + " to " + value);
           field.set(target, value);
        }
     }
  
     boolean isChildOf(Fqn parentFqn)
     {
        return fqn.isChildOf(parentFqn);
     }
  
  //   void setFqn(Fqn fqn)
  //   {
  //      this.fqn = fqn;
  //   }
  
     public Fqn getFqn() {
        return fqn;
     }
  
     public void setFqn(Fqn fqn)
     {
        this.fqn = fqn;
     }
  
  }
  
  
  
  1.1      date: 2006/10/31 08:01:13;  author: bwang;  state: Exp;JBossCache/old/src/org/jboss/cache/aop/PojoTxSynchronizationHandler.java
  
  Index: PojoTxSynchronizationHandler.java
  ===================================================================
  /*
   * JBoss, Home of Professional Open Source
   *
   * Distributable under LGPL license.
   * See terms of license at gnu.org.
   */
  
  package org.jboss.cache.aop;
  
  import org.apache.commons.logging.Log;
  import org.apache.commons.logging.LogFactory;
  import org.jboss.aop.InstanceAdvisor;
  
  import javax.transaction.Status;
  import javax.transaction.Synchronization;
  import javax.transaction.Transaction;
  import java.util.List;
  import java.lang.reflect.Field;
  
  /**
   * Handling the rollback operation for PojoCache level, specifically interceptor add/remove, etc.
   *
   * @author Ben Wang
   * @version $Id: PojoTxSynchronizationHandler.java,v 1.1 2006/10/31 08:01:13 bwang Exp $
   */
  
  public class PojoTxSynchronizationHandler implements Synchronization {
     static Log log = LogFactory.getLog(PojoTxSynchronizationHandler.class.getName());
     private Transaction tx_;
     private PojoCache cache_;
  
     PojoTxSynchronizationHandler(Transaction tx, PojoCache cache)
     {
        tx_ = tx;
        cache_ = cache;
     }
  
     public void beforeCompletion() {
        // Not interested
     }
  
     public void afterCompletion(int status) {
        try {
           switch (status) {
              case Status.STATUS_COMMITTED:
                 break;
              case Status.STATUS_MARKED_ROLLBACK:
              case Status.STATUS_ROLLEDBACK:
                 log.debug("Running rollback phase");
                 runRollbackPhase();
                 log.debug("Finished rollback phase");
                 break;
  
              default:
                 throw new IllegalStateException("illegal status: " + status);
           }
        }
        finally {
        }
     }
  
     private void runRollbackPhase()
     {
        // Rollback the pojo interceptor add/remove
        List list = cache_.getModList();
        for(int i=(list.size()-1); i >= 0; i--)
        {
           ModificationEntry ent = (ModificationEntry)list.get(i);
           InstanceAdvisor advisor = ent.getInstanceAdvisor();
           BaseInterceptor interceptor = ent.getCacheInterceptor();
           switch (ent.getOpType())
           {
              case ModificationEntry.INTERCEPTOR_ADD:
                 advisor.removeInterceptor(interceptor.getName());
                 break;
              case ModificationEntry.INTERCEPTOR_REMOVE:
                 advisor.appendInterceptor(interceptor);
                 break;
              case ModificationEntry.COLLECTION_REPLACE:
                 Field field = ent.getField();
                 Object key = ent.getKey();
                 Object value = ent.getOldValue();
                 try {
                    field.set(key, value);
                 } catch (IllegalAccessException e) {
                    throw new RuntimeException("PojoTxSynchronizationHandler.runRollbackPhase(): Exception: " +e);
                 }
                 break;
              default:
                 throw new IllegalArgumentException("PojoTxSynchronizationHandler.runRollbackPhase: getOptType: "
                         +ent.getOpType());
           }
        }
        cache_.resetUndoOp();
     }
  }
  
  
  
  
  1.1      date: 2006/10/31 08:01:13;  author: bwang;  state: Exp;JBossCache/old/src/org/jboss/cache/aop/ObjectGraphHandler.java
  
  Index: ObjectGraphHandler.java
  ===================================================================
  /*
   * JBoss, Home of Professional Open Source
   *
   * Distributable under LGPL license.
   * See terms of license at gnu.org.
   */
  
  package org.jboss.cache.aop;
  
  import org.jboss.cache.Fqn;
  import org.jboss.cache.CacheException;
  import org.jboss.cache.aop.util.AopUtil;
  import org.jboss.cache.aop.collection.AbstractCollectionInterceptor;
  import org.jboss.aop.advice.Interceptor;
  import org.jboss.aop.InstanceAdvisor;
  import org.jboss.aop.Advised;
  import org.apache.commons.logging.Log;
  import org.apache.commons.logging.LogFactory;
  
  /**
   * Handle the object graph management.
   *
   * @author Ben Wang
   *         Date: Aug 4, 2005
   * @version $Id: ObjectGraphHandler.java,v 1.1 2006/10/31 08:01:13 bwang Exp $
   */
  public class ObjectGraphHandler {
     protected PojoCache cache_;
     protected InternalDelegate internal_;
     protected final static Log log=LogFactory.getLog(ObjectGraphHandler.class);
     protected TreeCacheAopDelegate delegate_;
  
     public ObjectGraphHandler(PojoCache cache, InternalDelegate internal, TreeCacheAopDelegate delegate)
     {
        cache_ = cache;
        internal_ = internal;
        delegate_ = delegate;
     }
  
     Object objectGraphGet(Fqn fqn) throws CacheException
     {
        // Note this is actually the aliasFqn, not the real fqn!
        String refFqn = internal_.getRefFqn(fqn);
        Object obj;
        if (refFqn != null) {
           // this is recursive. Need to obtain the object from parent fqn
           // No need to add CacheInterceptor as a result. Everything is re-directed.
           // In addition, this op will not be recursive.
           if (log.isDebugEnabled()) {
              log.debug("getObject(): obtain value from reference fqn: " + refFqn);
           }
           obj = cache_.getObject(refFqn);
           if(obj == null)
              throw new RuntimeException("ObjectGraphHandler.objectGraphGet(): null object from internal ref node." +
                      " Original fqn: " +fqn + " Internal ref node: " +refFqn);
  
           return obj; // No need to set the instance under fqn. It is located in refFqn anyway.
        }
  
        return null;
     }
  
     boolean objectGraphPut(Fqn fqn, Interceptor interceptor, CachedType type, Object obj) throws CacheException
     {
        Fqn originalFqn = null;
        if (interceptor == null) {
           return false;  // No interceptor no object graph possibility.
        }
  
        if(interceptor instanceof AbstractCollectionInterceptor)
        {
           // Special case for Collection class. If it is detached, we don't care.
           if( !((AbstractCollectionInterceptor)interceptor).isAttached())
           {
              return false;
           }
        }
        // ah, found something. So this will be multiple referenced.
        originalFqn = ((BaseInterceptor) interceptor).getFqn();
  
        if(originalFqn == null) return false;
  
        if (log.isDebugEnabled()) {
           log.debug("handleObjectGraph(): fqn: " + fqn + " and " + originalFqn + " share the object.");
        }
  
        // This will increment the ref count, reset, and add ref fqn in the current fqn node.
        setupRefCounting(fqn, originalFqn);
        internal_.putAopClazz(fqn, type.getType());
        return true;
     }
  
     boolean objectGraphRemove(Fqn fqn, boolean removeCacheInterceptor, Object pojo, boolean evict)
             throws CacheException
     {
        boolean isTrue = false;
  
        // Note this is actually the aliasFqn, not the real fqn!
        AOPInstance aopInstance = internal_.getAopInstance(fqn);
        String refFqn = internal_.getRefFqn(aopInstance, fqn);
        // check if this is a refernce
        if (refFqn != null) {
           if (log.isDebugEnabled()) {
              log.debug("objectGraphRemove(): removing object fqn: " + fqn + " but is actually from ref fqn: " + refFqn
              + " Will just de-reference it.");
           }
           removeFromReference(fqn, refFqn, removeCacheInterceptor, evict);
           internal_.cleanUp(fqn, evict);
           isTrue = true;
        } else {
           if(internal_.isReferenced(aopInstance, fqn))
           {
              // This node is currently referenced by others. We will relocate it to the next in line,
              // and update the indirectFqnMap
  
              // First decrement counter.
              decrementRefCount(fqn, null);
              // Determine where to move first.
              Fqn newFqn = internal_.getNextFqnInLine(fqn);
              // Is newFqn is child of fqn?
              if(newFqn.isChildOf(fqn))
              {
                 // Take out the child fqn reference to me.
                 internal_.removeRefFqn(newFqn);
  
                 if (log.isDebugEnabled()) {
                    log.debug("objectGraphRemove(): this node "+ fqn + " is currently referenced by a cyclic reference: "
                            + newFqn + "Will only decrement reference count.");
                 }
              } else
              {
                 // Relocate all the contents from old to the new fqn
                 internal_.relocate(fqn, newFqn);
                 // Reset the fqn in the cache interceptor
                 InstanceAdvisor advisor = ((Advised) pojo)._getInstanceAdvisor();
                 CacheInterceptor interceptor = (CacheInterceptor) AopUtil.findCacheInterceptor(advisor);
                 if(interceptor == null)
                    throw new IllegalStateException("ObjectGraphHandler.objectGraphRemove(): null interceptor");
                 interceptor.setFqn(newFqn);
                 // reset the fqn in the indirect fqn map
                 internal_.setIndirectFqn(fqn.toString(), newFqn.toString());
  
                 isTrue = true;
  
                 if (log.isDebugEnabled()) {
                    log.debug("objectGraphRemove(): this node "+ fqn + " is currently referenced by " +
                            +internal_.getRefCount(newFqn) +
                            " other pojos after relocating to " +newFqn.toString());
                 }
              }
           }
        }
  
        return isTrue;
     }
  
     /**
      * Remove the object from the the reference fqn, meaning just decrement the ref counter.
      * @param fqn
      * @param refFqn
      * @param removeCacheInterceptor
      * @param evict
      * @throws CacheException
      */
     private void removeFromReference(Fqn fqn, String refFqn, boolean removeCacheInterceptor,
                       boolean evict) throws CacheException {
        synchronized (refFqn) {  // we lock the internal fqn here so no one else has access.
           // Decrement ref counting on the internal node
           if (decrementRefCount(Fqn.fromString(refFqn), fqn) == AOPInstance.INITIAL_COUNTER_VALUE) {
              // No one is referring it so it is safe to remove
              // TODO we should make sure the parent nodes are also removed they are empty as well.
              delegate_._removeObject(Fqn.fromString(refFqn), removeCacheInterceptor, evict);
           }
        }
  
        // Remove ref fqn from this fqn
        internal_.removeRefFqn(fqn);
     }
  
     /**
      * 1. increment reference counter
      * 2. put in refFqn so we can get it.
      *
      * @param fqn The original fqn node
      * @param refFqn The new internal fqn node
      */
     void setupRefCounting(Fqn fqn, Fqn refFqn) throws CacheException
     {
        synchronized (refFqn) { // we lock the ref fqn here so no one else has access.
           // increment the reference counting
           String aliasFqn = null;
           if( incrementRefCount(refFqn, fqn) == 1 )
           {
              // We have the first multiple reference
              aliasFqn = internal_.createIndirectFqn(refFqn.toString());
           } else
           {
              aliasFqn = internal_.getIndirectFqn(refFqn.toString());
           }
           // set the internal fqn in fqn so we can reference it.
           if(log.isTraceEnabled())
           {
              log.trace("setupRefCounting(): current fqn: " +fqn + " set to point to: " +refFqn);
           }
  
           internal_.setRefFqn(fqn, aliasFqn);
        }
     }
  
     int incrementRefCount(Fqn originalFqn, Fqn referencingFqn) throws CacheException
     {
        return internal_.incrementRefCount(originalFqn, referencingFqn);
     }
  
     int decrementRefCount(Fqn originalFqn, Fqn referencingFqn) throws CacheException
     {
        int count = 0;
        if( (count = internal_.decrementRefCount(originalFqn, referencingFqn)) == (AOPInstance.INITIAL_COUNTER_VALUE +1) )
        {
           internal_.removeIndirectFqn(originalFqn.toString());
        }
  
        return count;
     }
  }
  
  
  
  1.1      date: 2006/10/31 08:01:13;  author: bwang;  state: Exp;JBossCache/old/src/org/jboss/cache/aop/InstanceOfAopMarker.java
  
  Index: InstanceOfAopMarker.java
  ===================================================================
  package org.jboss.cache.aop;
  
  /**
   * Marker interface for use in aop annotation declaration. For example, can use this in pojo
   * annotation instead of declaring jboss-aop.xml. This is used specifically for instanceof
   * declaration.
   * @author Ben Wang
   */
  public interface InstanceOfAopMarker {
  }
  
  
  
  1.1      date: 2006/10/31 08:01:13;  author: bwang;  state: Exp;JBossCache/old/src/org/jboss/cache/aop/WriteReplacer.java
  
  Index: WriteReplacer.java
  ===================================================================
  /*
   * JBoss, the OpenSource J2EE webOS
   *
   * Distributable under LGPL license.
   * See terms of license at gnu.org.
   */
  
  package org.jboss.cache.aop;
  
  //import java.util.Iterator;
  //import java.util.List;
  
  import org.jboss.aop.Advised;
  import org.jboss.aop.InstanceAdvisor;
  
  import java.io.NotSerializableException;
  import java.io.ObjectStreamException;
  
  /**
   * @author <a href="mailto:harald at gliebe.de">Harald Gliebe</a>
   * @deprecated 1.0
   */
  
  public class WriteReplacer implements WriteReplaceable /*, Interceptor*/
  {
  
     // interceptor
     /*
         public WriteReplacer() {
         }
  
         public String getName() {
        return "WriteReplacer";
         }
  
         public InvocationResponse invoke(Invocation invocation) throws Throwable {
        Method method = MethodInvocation.getMethod(invocation);
  
        if (method != null
            && method.getName().equals("writeReplace")
            && method.getReturnType().equals(Object.class)
            && method.getParameterTypes().length == 0) {
            //hack
            this.obj = MethodInvocation.getTargetObject(invocation);
            this.writeReplace(); // fills Fieldvalues
        }
  
        return invocation.invokeNext();
  
         }
     */
     // mixin
  
     Object obj;
  
     public WriteReplacer(Object obj)
     {
        this.obj = obj;
     }
  
     public Object writeReplace() throws ObjectStreamException
     {
        if (obj instanceof Advised) {
           InstanceAdvisor advisor = ((Advised) obj)._getInstanceAdvisor();
           org.jboss.aop.advice.Interceptor[] interceptors = advisor.getInterceptors();
           CacheInterceptor cacheInterceptor = null;
           for (int i = 0; i < interceptors.length; i++) {
              if (interceptors[i] instanceof CacheInterceptor) {
                 cacheInterceptor = (CacheInterceptor) interceptors[i];
                 break;
              }
           }
           if (cacheInterceptor != null) {
              try {
                 cacheInterceptor.beforeSerialization(obj);
              } catch (Exception e) {
                 e.printStackTrace();
                 throw new NotSerializableException(e.getMessage());
              }
           }
        }
        return obj;
     }
  
  }
  
  
  
  1.1      date: 2006/10/31 08:01:13;  author: bwang;  state: Exp;JBossCache/old/src/org/jboss/cache/aop/CachedType.java
  
  Index: CachedType.java
  ===================================================================
  package org.jboss.cache.aop;
  
  import org.jboss.aop.joinpoint.FieldInvocation;
  import org.jboss.aop.Advisor;
  import org.jboss.cache.aop.references.FieldPersistentReference;
  import org.jboss.cache.aop.references.PersistentReference;
  
  import java.lang.reflect.Field;
  import java.lang.reflect.Method;
  import java.lang.reflect.Modifier;
  import java.lang.ref.WeakReference;
  import java.util.Set;
  import java.util.HashSet;
  import java.util.Arrays;
  import java.util.Map;
  import java.util.WeakHashMap;
  import java.util.List;
  import java.util.HashMap;
  import java.util.ArrayList;
  import java.util.Iterator;
  
  /**  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".
     protected 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,
              Boolean.TYPE,
              Double.TYPE,
              Float.TYPE,
              Integer.TYPE,
              Long.TYPE,
              Short.TYPE,
              Character.TYPE,
              Class.class}));
  
     protected WeakReference type;
     protected boolean immutable;
     protected boolean immediate;
     // This map caches the class that contains no annotation.
     protected static Map CachedClassWithNoAnnotation_ = new WeakHashMap();
     protected static Map CachedClassWithAnnotation_ = new WeakHashMap();
  
     // Java fields . Will use special FieldPersistentReference to prevent classloader leakage.
     protected List fields = new ArrayList();
     protected Map fieldMap = new HashMap(); // Name -> CachedAttribute
  
     public CachedType()
     {
     }
  
     public CachedType(Class type)
     {
        this.type = new WeakReference(type);
        analyze();
     }
  
     public Class getType()
     {
        return (Class)type.get();
     }
  
     // determines if the object should be stored in the Nodes map or as a subnode
     public boolean isImmediate()
     {
        return immediate;
     }
  
     public 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().getName())
                 .append(" ")
                 .append(attr.getName())
                 .append(" [")
                 .append(attr.getGet() == null
                 ? "<no get>"
                 : attr.getGet().getName())
                 .append(", ")
                 .append(attr.getSet() == null
                 ? "<no set>"
                 : attr.getSet().getName())
                 .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());
  
     }
  
     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.
      */
     protected 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;
     }
  
     protected 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)
              || Modifier.isFinal(mods)) {
           return true;
        }
        return false;
     }
  
  
     /**
      * Check if we have @Transient annotation.
      * @param invocation
      * @return true if @Transient is present.
      */
     protected static boolean hasTransientAnnotation(FieldInvocation invocation)
     {
        Object obj = invocation.resolveAnnotation(org.jboss.cache.aop.annotation.Transient.class);
        if(obj != null)
        {
           return true;
        }
        return false;
     }
  
     protected static boolean hasFieldAnnotation(Field field, Advisor advisor)
     {
        return hasTransientAnnotation(field, advisor) || hasSerializableAnnotation(field, advisor);
     }
  
     protected static boolean hasTransientAnnotation(Field field, Advisor advisor)
     {
        Object obj = advisor.resolveAnnotation(field, org.jboss.cache.aop.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.aop.annotation.Serializable.class);
        if(obj != null)
        {
           return true;
        }
        return false;
     }
  
     public static boolean hasSerializableAnnotation(FieldInvocation invocation)
     {
        Object obj = invocation.resolveAnnotation(org.jboss.cache.aop.annotation.Serializable.class);
        if(obj != null)
        {
           return true;
        }
        return false;
     }
  
     public static boolean isNonReplicatable(FieldInvocation fieldInvocation)
     {
        return hasTransientAnnotation(fieldInvocation) || isPrimitiveNonReplicatable(fieldInvocation.getField());
     }
  
  
     /*
      * converts a get/set method to an attribute name
      */
     protected String attributeName(String methodName)
     {
        return methodName.substring(3, 4).toLowerCase()
              + methodName.substring(4);
     }
  
     protected CachedAttribute getAttribute(Method method,
                                            Map map,
                                            boolean create)
     {
        String name = attributeName(method.getName());
  
        CachedAttribute attribute = (CachedAttribute) map.get(name);
        if (create && attribute == null) {
           attribute = new CachedAttribute(name);
           map.put(name, attribute);
        }
        return attribute;
     }
  
     protected boolean isGet(Method method)
     {
        return method.getName().startsWith("get")
              && method.getParameterTypes().length == 0
              && method.getReturnType() != Void.TYPE;
     }
  
     protected boolean isSet(Method method)
     {
        return method.getName().startsWith("set")
              && method.getParameterTypes().length == 1
              && method.getReturnType() == Void.TYPE;
     }
  
  } // CachedType
  
  
  
  1.1      date: 2006/10/31 08:01:13;  author: bwang;  state: Exp;JBossCache/old/src/org/jboss/cache/aop/TreeCacheAop.java
  
  Index: TreeCacheAop.java
  ===================================================================
  /*
   * JBoss, the OpenSource J2EE webOS
   *
   * Distributable under LGPL license.
   * See terms of license at gnu.org.
   */
  package org.jboss.cache.aop;
  
  import org.jgroups.JChannel;
  
  /**
   * @author Harald Gliebe
   * @author Ben Wang
   * @deprecated Since 1.4, replaced by {@link PojoCache}
   */
  public class TreeCacheAop extends PojoCache //implements TreeCacheAopMBean // TODO; Need to come up with proper JMX interfaces
  {
     public TreeCacheAop(String cluster_name,
                         String props,
                         long state_fetch_timeout)
             throws Exception {
        super(cluster_name, props, state_fetch_timeout);
     }
  
     public TreeCacheAop() throws Exception
     {
     }
  
     public TreeCacheAop(JChannel channel) throws Exception
     {
        super(channel);
     }
  
  }
  
  
  
  
  1.1      date: 2006/10/31 08:01:13;  author: bwang;  state: Exp;JBossCache/old/src/org/jboss/cache/aop/InternalDelegate.java
  
  Index: InternalDelegate.java
  ===================================================================
  /*
   * JBoss, the OpenSource J2EE webOS
   *
   * Distributable under LGPL license.
   * See terms of license at gnu.org.
   */
  package org.jboss.cache.aop;
  
  import org.apache.commons.logging.Log;
  import org.apache.commons.logging.LogFactory;
  import org.jboss.cache.CacheException;
  import org.jboss.cache.DataNode;
  import org.jboss.cache.Fqn;
  import org.jboss.cache.aop.util.ObjectUtil;
  import org.jboss.cache.config.Option;
  
  import java.util.Iterator;
  import java.util.Map;
  
  /**
   * PojoCache delegation to handle internal cache sotre, that is, the portion that is not part of user's data.
   *
   * @author Ben Wang
   */
  public class InternalDelegate
  {
     static Log log = LogFactory.getLog(InternalDelegate.class.getName());
     public static final String CLASS_INTERNAL = "__jboss:internal:class__";
     public static final String SERIALIZED = "__SERIALIZED__";
     public static final Fqn JBOSS_INTERNAL = new Fqn("__JBossInternal__");
     public static final Fqn JBOSS_INTERNAL_MAP = new Fqn(JBOSS_INTERNAL, "__RefMap__");
     // This is an optimization flag to skip put lock when we are sure that it has been locked from
     // putObject. However, if later on there are transactional field updates, then we we will need
     // this off to protected the write lock.
     private boolean cacheOperationSkipLocking = true;
     private Option skipLockOption_;
     private Option gravitateOption_;
     private Option localModeOption_;
  
     protected PojoCache cache_;
  
     InternalDelegate(PojoCache cache)
     {
        cache_ = cache;
  
        skipLockOption_ = new Option();
        if (cacheOperationSkipLocking)
        {
           skipLockOption_.setSuppressLocking(true);
        }
        else
        {
           skipLockOption_.setSuppressLocking(false);
        }
  
        localModeOption_ = new Option();
        localModeOption_.setCacheModeLocal(true);
  
        gravitateOption_ = new Option();
        gravitateOption_.setForceDataGravitation(true);
     }
  
     Option getLockOption()
     {
        return skipLockOption_;
     }
  
     protected AOPInstance getAopInstance(Fqn fqn) throws CacheException
     {
        // Not very efficient now since we are peeking every single time.
        // Should have cache it without going to local cache.
        return (AOPInstance) get(fqn, AOPInstance.KEY, false);
     }
  
     protected AOPInstance getAopInstanceWithGravitation(Fqn fqn) throws CacheException
     {
        // Not very efficient now since we are peeking every single time.
        // Should have cache it without going to local cache.
        return (AOPInstance) get(fqn, AOPInstance.KEY, true);
     }
  
     AOPInstance initializeAopInstance(Fqn fqn) throws CacheException
     {
        AOPInstance aopInstance = new AOPInstance();
  
        aopInstance.incrementRefCount(null);
        return aopInstance;
     }
  
     /**
      * Increment reference count for the pojo. Note that this is not thread safe or atomic.
      */
     int incrementRefCount(Fqn originalFqn, Fqn referencingFqn) throws CacheException
     {
        AOPInstance aopInstance = getAopInstance(originalFqn);
        if (aopInstance == null)
           throw new RuntimeException("InternalDelegate.incrementRefCount(): null aopInstance for fqn: " + originalFqn);
  
        int count = aopInstance.incrementRefCount(referencingFqn);
        // need to update it.
        put(originalFqn, AOPInstance.KEY, aopInstance);
        return count;
     }
  
     /**
      * Has a delegate method so we can use the switch.
      */
  
     protected Object get(Fqn fqn, Object key) throws CacheException
     {
        return get(fqn, key, false);
     }
  
     protected Object get(Fqn fqn, Object key, boolean gravitate) throws CacheException
     {
        // TODO let's find a better way to decouple this.
        if (gravitate && cache_.getBuddyManager() != null)
        {
           cache_.getInvocationContext().getOptionOverrides().setForceDataGravitation(true);
           return cache_.get(fqn, key);
        }
        else if (cache_.getCacheLoader() != null)
        {
           // We have cache loader, we can't get it directly from the local get.
           cache_.getInvocationContext().getOptionOverrides().setSuppressLocking(cacheOperationSkipLocking);
           return cache_.get(fqn, key);
        }
        else
        {
           return cache_._get(fqn, key, false);
        }
     }
  
     protected void put(Fqn fqn, Object key, Object value) throws CacheException
     {
        // Use option to ski locking since we have parent lock already.
        cache_.getInvocationContext().getOptionOverrides().setSuppressLocking(cacheOperationSkipLocking);
        cache_.put(fqn, key, value);
  //      cache_.put(fqn, key, value);
     }
  
     protected void put(Fqn fqn, Map map) throws CacheException
     {
        // Use option to ski locking since we have parent lock already.
        cache_.getInvocationContext().getOptionOverrides().setSuppressLocking(cacheOperationSkipLocking);
        cache_.put(fqn, map);
  //      cache_.put(fqn, key, value);
     }
  
     protected void localPut(Fqn fqn, Object key, Object value) throws CacheException
     {
        // Use option to ski locking since we have parent lock already.
        // TODO Need to make sure there is no tx here otherwise it won't work.
        cache_.getInvocationContext().getOptionOverrides().setCacheModeLocal(true);
        cache_.put(fqn, key, value);
     }
  
  
     /**
      * decrement reference count for the pojo. Note that this is not thread safe or atomic.
      */
     int decrementRefCount(Fqn originalFqn, Fqn referencingFqn) throws CacheException
     {
        AOPInstance aopInstance = getAopInstance(originalFqn);
        if (aopInstance == null)
           throw new RuntimeException("InternalDelegate.decrementRefCount(): null aopInstance.");
  
        int count = aopInstance.decrementRefCount(referencingFqn);
  
        if (count < -1)  // can't dip below -1
           throw new RuntimeException("InternalDelegate.decrementRefCount(): null aopInstance.");
  
        // need to update it.
        put(originalFqn, AOPInstance.KEY, aopInstance);
        return count;
     }
  
     boolean isReferenced(AOPInstance aopInstance, Fqn fqn) throws CacheException
     {
        // If ref counter is greater than 0, we fqn is being referenced.
        return (aopInstance.getRefCount() > 0);
     }
  
     int getRefCount(Fqn fqn) throws CacheException
     {
        return getAopInstance(fqn).getRefCount();
     }
  
     String getRefFqn(Fqn fqn) throws CacheException
     {
        AOPInstance aopInstance = getAopInstance(fqn);
        return getRefFqn(aopInstance, fqn);
     }
  
     String getRefFqn(AOPInstance aopInstance, Fqn fqn) throws CacheException
     {
        if (aopInstance == null)
           return null;
  
        String aliasFqn = aopInstance.getRefFqn();
  
        if (aliasFqn == null || aliasFqn.length() == 0) return null;
  
        return getRefFqnFromAlias(aliasFqn);
     }
  
     void setRefFqn(Fqn fqn, String internalFqn) throws CacheException
     {
        AOPInstance aopInstance = getAopInstance(fqn);
        if (aopInstance == null)
           aopInstance = new AOPInstance();
  
        aopInstance.setRefFqn(internalFqn);
        put(fqn, AOPInstance.KEY, aopInstance);
     }
  
     void removeRefFqn(Fqn fqn) throws CacheException
     {
        AOPInstance aopInstance = getAopInstance(fqn);
        if (aopInstance == null)
           throw new RuntimeException("InternalDelegate.getRefFqn(): null aopInstance.");
  
        aopInstance.removeRefFqn();
        put(fqn, AOPInstance.KEY, aopInstance);
     }
  
     Object getPojo(Fqn fqn) throws CacheException
     {
        AOPInstance aopInstance = getAopInstance(fqn);
        if (aopInstance == null)
           return null;
  
        return aopInstance.get();
     }
  
     Object getPojoWithGravitation(Fqn fqn) throws CacheException
     {
        // This is for buddy replication
        AOPInstance aopInstance = getAopInstanceWithGravitation(fqn);
        if (aopInstance == null)
           return null;
  
        return aopInstance.get();
     }
  
     void setPojo(Fqn fqn, Object pojo) throws CacheException
     {
        AOPInstance aopInstance = getAopInstance(fqn);
        if (aopInstance == null)
        {
           aopInstance = new AOPInstance();
           put(fqn, AOPInstance.KEY, aopInstance);
        }
  
        aopInstance.set(pojo);
        // No need to do a cache put since pojo is transient anyway.
     }
  
     void setPojo(AOPInstance aopInstance, Object pojo) throws CacheException
     {
        // No need to do a cache put since pojo is transient anyway.
        aopInstance.set(pojo);
     }
  
     void setPojo(Fqn fqn, Object pojo, AOPInstance aopInstance) throws CacheException
     {
        if (aopInstance == null)
        {
           aopInstance = new AOPInstance();
           put(fqn, AOPInstance.KEY, aopInstance);
        }
  
        aopInstance.set(pojo);
        // No need to do a cache put since pojo is transient anyway.
     }
  
     /**
      * We store the class name in string.
      */
     void putAopClazz(Fqn fqn, Class clazz) throws CacheException
     {
        put(fqn, CLASS_INTERNAL, clazz);
     }
  
     /**
      * We store the class name in string and put it in map instead of directly putting
      * it into cache for optimization.
      */
     void putAopClazz(Fqn fqn, Class clazz, Map map) throws CacheException
     {
        map.put(CLASS_INTERNAL, clazz);
     }
  
     Class peekAopClazz(Fqn fqn) throws CacheException
     {
        return (Class) get(fqn, CLASS_INTERNAL);
     }
  
     boolean isAopNode(Fqn fqn) throws CacheException
     {
        // Use this API so it doesn't go thru the interceptor.
        DataNode node = cache_.peek(fqn);
        if (node == null) return false;
  
        if (node.get(AOPInstance.KEY) != null)
           return true;
        else
           return false;
     }
  
     void removeInternalAttributes(Fqn fqn) throws CacheException
     {
        cache_.remove(fqn, AOPInstance.KEY);
        cache_.remove(fqn, CLASS_INTERNAL);
     }
  
     void cleanUp(Fqn fqn, boolean evict) throws CacheException
     {
        // We can't do a brute force remove anymore?
        if (!evict)
        {
           if (!cache_._get(fqn).hasChildren())
           {
              // remove everything
              cache_.remove(fqn);
           }
           else
           {
              // Assume everything here is all PojoCache data for optimization
              cache_.removeData(fqn);
              if (log.isTraceEnabled())
              {
                 log.trace("cleanup(): fqn: " + fqn + " is not empty. That means it has sub-pojos. Will not remove node");
              }
           }
        }
        else
        {
           // This has to use plainEvict method otherwise it is recursively calling aop version of evict.
           cache_.plainEvict(fqn);
        }
     }
  
     String createIndirectFqn(String fqn) throws CacheException
     {
        String indirectFqn = getIndirectFqn(fqn);
        Fqn internalFqn = getInternalFqn(fqn);
        put(internalFqn, indirectFqn, fqn);
        return indirectFqn;
     }
  
     Fqn getInternalFqn(String fqn)
     {
        if (fqn == null || fqn.length() == 0)
           throw new IllegalStateException("InternalDelegate.getInternalFqn(). fqn is either null or empty!");
  
        String indirectFqn = getIndirectFqn(fqn);
        return new Fqn(JBOSS_INTERNAL_MAP, indirectFqn);
  //      return JBOSS_INTERNAL_MAP;
     }
  
     String getIndirectFqn(String fqn)
     {
        // TODO This is not unique. Will need to come up with a better one in the future.
        return ObjectUtil.getIndirectFqn(fqn);
     }
  
     void removeIndirectFqn(String oldFqn) throws CacheException
     {
        String indirectFqn = getIndirectFqn(oldFqn);
        cache_.remove(getInternalFqn(oldFqn), indirectFqn);
     }
  
     void setIndirectFqn(String oldFqn, String newFqn) throws CacheException
     {
        String indirectFqn = getIndirectFqn(oldFqn);
        Fqn tmpFqn = getInternalFqn(oldFqn);
        if (cache_.exists(tmpFqn, indirectFqn)) // No need to update if it doesn't exist.
        {
           put(tmpFqn, indirectFqn, newFqn);
        }
     }
  
     void updateIndirectFqn(Fqn originalFqn, Fqn newFqn) throws CacheException
     {
        put(getInternalFqn(originalFqn.toString()), getIndirectFqn(originalFqn.toString()), newFqn.toString());
     }
  
     String getRefFqnFromAlias(String aliasFqn) throws CacheException
     {
        return (String) get(getInternalFqn(aliasFqn), aliasFqn, true);
     }
  
     Fqn getNextFqnInLine(Fqn currentFqn) throws CacheException
     {
        AOPInstance ai = getAopInstance(currentFqn);
        return ai.getAndRemoveFirstFqnInList();
     }
  
     void relocate(Fqn thisFqn, Fqn newFqn) throws CacheException
     {
        /**
         DataNode node = cache_.get(thisFqn);
         DataNode newParent = (DataNode)cache_.get(newFqn).getParent();
         node.relocate(newParent, newFqn); // relocation
         updateIndirectFqn(thisFqn, newFqn);
         */
  
        // Let's do cache-wide copy then. It won't be fast and atomic but
        // at least it preserves the pojo structure and also do replication
        // TODO Can TreeCache provide a method to do this??
  
        // First do a recursive copy using the new base fqn
        DataNode node = cache_.get(thisFqn);
        Map value = node.getData();
        cache_.put(newFqn, value);
  
        Map children = node.getChildren();
        if (children == null || children.size() == 0)
        {
           cache_.remove(thisFqn);
           return; // we are done
        }
  
        Iterator it = children.keySet().iterator();
        while (it.hasNext())
        {
           Object key = it.next();
           Fqn thisChildFqn = new Fqn(thisFqn, key);
           Fqn newChildFqn = new Fqn(newFqn, key);
           relocate(thisChildFqn, newChildFqn);
        }
  
        // Finally do a remove
        cache_.remove(thisFqn);
     }
  
     /**
      * Test if this internal node.
      *
      * @param fqn
      */
     public static boolean isInternalNode(Fqn fqn)
     {
        // we ignore all the node events corresponding to JBOSS_INTERNAL
        if (fqn.isChildOrEquals(InternalDelegate.JBOSS_INTERNAL)) return true;
  
        return false;
     }
  }
  
  
  
  1.1      date: 2006/10/31 08:01:13;  author: bwang;  state: Exp;JBossCache/old/src/org/jboss/cache/aop/TreeCacheAopDelegate.java
  
  Index: TreeCacheAopDelegate.java
  ===================================================================
  /*
   * JBoss, the OpenSource J2EE webOS
   *
   * Distributable under LGPL license.
   * See terms of license at gnu.org.
   */
  package org.jboss.cache.aop;
  
  import org.apache.commons.logging.Log;
  import org.apache.commons.logging.LogFactory;
  import org.jboss.aop.Advised;
  import org.jboss.aop.Advisor;
  import org.jboss.aop.ClassInstanceAdvisor;
  import org.jboss.aop.InstanceAdvisor;
  import org.jboss.aop.advice.Interceptor;
  import org.jboss.aop.proxy.ClassProxy;
  import org.jboss.cache.CacheException;
  import org.jboss.cache.Fqn;
  import org.jboss.cache.GlobalTransaction;
  import org.jboss.cache.TreeNode;
  import org.jboss.cache.aop.collection.AbstractCollectionInterceptor;
  import org.jboss.cache.aop.references.FieldPersistentReference;
  import org.jboss.cache.aop.util.AopUtil;
  import org.jboss.cache.marshall.MethodCall;
  import org.jboss.cache.marshall.MethodCallFactory;
  import org.jboss.cache.marshall.MethodDeclarations;
  
  import java.lang.reflect.Field;
  import java.util.Collection;
  import java.util.HashMap;
  import java.util.Iterator;
  import java.util.List;
  import java.util.Map;
  import java.util.Set;
  
  /**
   * Delegate class for PojoCache.
   *
   * @author Ben Wang
   */
  public class TreeCacheAopDelegate
  {
     protected PojoCache cache_;
     protected final static Log log = LogFactory.getLog(TreeCacheAopDelegate.class);
     protected InternalDelegate internal_;
     protected ObjectGraphHandler graphHandler_;
     protected CollectionClassHandler collectionHandler_;
     protected SerializableObjectHandler serializableHandler_;
     // Use ThreadLocal to hold a boolean isBulkRemove
     protected ThreadLocal bulkRemove_ = new ThreadLocal();
     protected final String DETACH = "DETACH";
  
     public TreeCacheAopDelegate(PojoCache cache)
     {
        cache_ = cache;
        internal_ = new InternalDelegate(cache);
        graphHandler_ = new ObjectGraphHandler(cache_, internal_, this);
        collectionHandler_ = new CollectionClassHandler(cache_, internal_, graphHandler_);
        serializableHandler_ = new SerializableObjectHandler(cache_, internal_);
     }
  
     public void setBulkRemove(boolean bulk)
     {
        bulkRemove_.set(Boolean.valueOf(bulk));
     }
  
     public boolean getBulkRemove()
     {
        return ((Boolean) bulkRemove_.get()).booleanValue();
     }
  
     protected Object _getObject(Fqn fqn) throws CacheException
     {
        // TODO Must we really to couple with BR? JBCACHE-669
        Object pojo = internal_.getPojoWithGravitation(fqn);
        if (pojo != null)
        {
           // we already have an advised instance
           return pojo;
        }
  
        // OK. So we are here meaning that this is a failover or passivation since the transient
        // pojo instance is not around. Let's also make sure the right classloader is used
        // as well.
        ClassLoader prevCL = Thread.currentThread().getContextClassLoader();
        try
        {
           if (cache_.getRegionManager() != null)
           {
              cache_.getRegionManager().setContextClassLoaderAsCurrent(fqn);
           }
           return _getObjectInternal(fqn);
        }
        finally
        {
           Thread.currentThread().setContextClassLoader(prevCL);
        }
  
     }
  
     protected Object _getObjectInternal(Fqn fqn) throws CacheException
     {
        // the class attribute is implicitly stored as an immutable read-only attribute
        Class clazz = internal_.peekAopClazz(fqn);
        //  clazz and aopInstance can be not null if this node is the replicated brother node.
        if (clazz == null)
           return null;
  
        /**
         * Reconstruct the managed POJO
         */
        CachedType type = cache_.getCachedType(clazz);
        Object obj;
  
        // Check for both Advised and Collection classes for object graph.
        if ((obj = graphHandler_.objectGraphGet(fqn)) != null)
           return obj; // retrieved from internal ref node. We are done.
  
        AOPInstance aopInstance = internal_.getAopInstance(fqn);
        if (aopInstance == null)
        {
           throw new RuntimeException("TreeCacheAopDelegate._getObject(): null AOPInstance.");
        }
  
        if (Advised.class.isAssignableFrom(clazz))
        {
           try
           {
              obj = clazz.newInstance();
              // TODO Need to populate the object from the cache as well.
           }
           catch (Exception e)
           {
              throw new CacheException("failed creating instance of " + clazz.getName(), e);
           }
           // Insert interceptor at runtime
           InstanceAdvisor advisor = ((Advised) obj)._getInstanceAdvisor();
           CacheInterceptor interceptor = new CacheInterceptor(cache_, fqn, type);
           interceptor.setAopInstance(aopInstance);
           advisor.appendInterceptor(interceptor);
           cache_.addUndoInterceptor(advisor, interceptor, ModificationEntry.INTERCEPTOR_ADD);
  
        }
        else
        { // Must be Collection classes. We will use aop.ClassProxy instance instead.
           try
           {
              if ((obj = collectionHandler_.collectionObjectGet(fqn, clazz)) != null)
              {
              }
              else
              {
                 // Maybe it is just a serialized object.
                 obj = serializableHandler_.serializableObjectGet(fqn);
              }
           }
           catch (Exception e)
           {
              throw new CacheException("failure creating proxy", e);
           }
        }
  
        internal_.setPojo(aopInstance, obj);
        return obj;
     }
  
     /**
      * Note that caller of this method will take care of synchronization within the <code>fqn</code> sub-tree.
      *
      * @param fqn
      * @param obj
      * @return
      * @throws CacheException
      */
     protected Object _putObject(Fqn fqn, Object obj) throws CacheException
     {
        if (!cache_.isMarshallNonSerializable())
           AopUtil.checkObjectType(obj);
  
        if (obj == null)
        {
           return cache_._removeObject(fqn, true);
        }
        // Skip some un-necessary update if obj is the same class as the old one
        Object oldValue = internal_.getPojo(fqn);
        if (oldValue == obj) return obj;  // value already in cache. return right away.
  
        if (oldValue != null)
        {
           // Trigger bulk remove here for performance
           setBulkRemove(true);
           cache_._removeObject(fqn, true); // remove old value before overwriting it.
        }
  
        // Remember not to print obj here since it will trigger the CacheInterceptor.
        if (log.isDebugEnabled())
        {
           log.debug("putObject(): fqn: " + fqn);
        }
  
        // store object in cache
        if (obj instanceof Advised)
        {
           CachedType type = cache_.getCachedType(obj.getClass());
           // add interceptor
           InstanceAdvisor advisor = ((Advised) obj)._getInstanceAdvisor();
           if (advisor == null)
              throw new RuntimeException("_putObject(): InstanceAdvisor is null for: " + obj);
  
           // Step Check for cross references
           Interceptor interceptor = AopUtil.findCacheInterceptor(advisor);
           // Let's check for object graph, e.g., multiple and circular references first
           if (graphHandler_.objectGraphPut(fqn, interceptor, type, obj))
           { // found cross references
              return oldValue;
           }
  
           // We have a clean slate then.
           _regularPutObject(fqn, obj, advisor, type);
  
           /**
            * Handling collection classes here.
            * First check if obj has been aspectized? That is, if it is a ClassProxy or not.
            * If not, we will need to create a proxy first for the Collection classes
            */
        }
        else if (collectionHandler_.collectionObjectPut(fqn, obj))
        {
           //
        }
        else if (serializableHandler_.serializableObjectPut(fqn, obj))
        {
           // must be Serializable, including primitive types
        }
        else
        {
           // I really don't know what this is.
           throw new RuntimeException("putObject(): obj: " + obj + " type is not recognizable.");
        }
  
        return oldValue;
     }
  
     /**
      * Based on the pojo to perform a bulk remove recursively if there is no object graph
      * relationship for performance optimization.
      */
     protected boolean bulkRemove(Fqn fqn, Object obj) throws CacheException
     {
        // Check for cross-reference. If there is, we can't do bulk remove
        // map contains (pojo, cacheinterceptor) pair that needs to undo the the removal.
  //      return false;
        Map undoMap = new HashMap();
        if (pojoGraphMultipleReferenced(obj, undoMap))
        {
           undoInterceptorDetach(undoMap);
           return false;
        }
        else
        {
           cache_.remove(fqn); // interceptor has been removed so it is safe to do bulk remove now.
        }
        return true;
     }
  
     protected void detachInterceptor(InstanceAdvisor advisor, Interceptor interceptor,
                                      boolean detachOnly, Map undoMap)
     {
        if (!detachOnly)
        {
           advisor.removeInterceptor(interceptor.getName());
           undoMap.put(advisor, interceptor);
        }
        else
        {
           undoMap.put(DETACH, interceptor);
        }
     }
  
     protected void undoInterceptorDetach(Map undoMap)
     {
        for (Iterator it = undoMap.keySet().iterator(); it.hasNext();)
        {
           Object obj = it.next();
  
           if (obj instanceof InstanceAdvisor)
           {
              InstanceAdvisor advisor = (InstanceAdvisor) obj;
              BaseInterceptor interceptor = (BaseInterceptor) undoMap.get(advisor);
  
              if (interceptor == null)
              {
                 throw new IllegalStateException("TreeCacheAopDelegate.undoInterceptorDetach(): null interceptor");
              }
  
              advisor.appendInterceptor(interceptor);
           }
           else
           {
              BaseInterceptor interceptor = (BaseInterceptor) undoMap.get(obj);
              boolean copyToCache = false;
              ((AbstractCollectionInterceptor) interceptor).attach(null, copyToCache);
           }
        }
     }
  
     /**
      * Check recursively if the pojo and its graph is multiple referenced. If it is, we can't
      * do a bulk remove.
      */
     protected boolean pojoGraphMultipleReferenced(Object obj, Map undoMap) throws CacheException
     {
        // store object in cache
        if (obj instanceof Advised)
        {
           CachedType type = cache_.getCachedType(obj.getClass());
           // add interceptor
           InstanceAdvisor advisor = ((Advised) obj)._getInstanceAdvisor();
           if (advisor == null)
              throw new RuntimeException("pojoGraphMultipleReferenced(): InstanceAdvisor is null for: " + obj);
  
           BaseInterceptor interceptor = (BaseInterceptor) AopUtil.findCacheInterceptor(advisor);
           // just in case
           if (interceptor == null)
           {
              return false;
           }
           AOPInstance aopInstance = interceptor.getAopInstance();
           // Check if there is cross referenced.
           if (aopInstance.getRefCount() != 0) return true; // I have been referenced
           if (aopInstance.getRefFqn() != null) return true; // I am referencing others
  
           boolean hasFieldAnnotation = hasAnnotation(obj.getClass(), ((Advised) obj)._getAdvisor(), type);
           // Check the fields
           for (Iterator i = type.getFields().iterator(); i.hasNext();)
           {
              Field field = (Field) (((FieldPersistentReference) i.next())).get();
              Object value = null;
              try
              {
                 value = field.get(obj);
              }
              catch (IllegalAccessException e)
              {
                 throw new CacheException("field access failed", e);
              }
  
              CachedType fieldType = cache_.getCachedType(field.getType());
  
              // we simply treat field that has @Serializable as a primitive type.
              if (fieldType.isImmediate() ||
                      (hasFieldAnnotation &&
                              CachedType.hasSerializableAnnotation(field, ((Advised) obj)._getAdvisor())))
              {
                 continue;
              }
  
              // check for non-replicatable types
              if (CachedType.isPrimitiveNonReplicatable(field))
              {
                 continue;
              }
  
              if (!hasFieldAnnotation)
              {
                 if (CachedType.hasTransientAnnotation(field, ((Advised) obj)._getAdvisor()))
                 {
                    continue;
                 }
              }
  
              // Need to do a getObject just in case this is a failover removeObject.
              if (value == null)
                 value = _getObject(new Fqn(interceptor.getFqn(), field.getName()));
  
              if (value == null) continue; // this is no brainer.
  
              if (pojoGraphMultipleReferenced(value, undoMap)) return true;
           }
           boolean detachOnly = false;
           detachInterceptor(advisor, interceptor, detachOnly, undoMap);
        }
        else if (obj instanceof Map || obj instanceof List || obj instanceof Set)
        {
           // TODO Is this really necessary?
           if (!(obj instanceof ClassProxy)) return false;
  
           InstanceAdvisor advisor = ((ClassProxy) obj)._getInstanceAdvisor();
           BaseInterceptor interceptor = (BaseInterceptor) AopUtil.findCollectionInterceptor(advisor);
           AOPInstance aopInstance = interceptor.getAopInstance();
           if (aopInstance == null) return false; // safeguard
           // Check if there is cross referenced.
           if (aopInstance.getRefCount() != 0) return true; // I have been referenced
           if (aopInstance.getRefFqn() != null) return true; // I am referencing others
           // iterate thru the keys
           if (obj instanceof Map)
           {
              for (Iterator it = ((Map) obj).keySet().iterator(); it.hasNext();)
              {
                 Object subObj = ((Map) obj).get(it.next());
                 if (pojoGraphMultipleReferenced(subObj, undoMap)) return true;
              }
           }
           else if (obj instanceof List || obj instanceof Set)
           {
              for (Iterator it = ((Collection) obj).iterator(); it.hasNext();)
              {
                 Object subObj = it.next();
                 if (pojoGraphMultipleReferenced(subObj, undoMap)) return true;
              }
           }
           // Don't remove now.
           boolean removeFromCache = false;
           ((AbstractCollectionInterceptor) interceptor).detach(removeFromCache); // detach the interceptor. This will trigger a copy and remove.
           boolean detachOnly = true;
           detachInterceptor(advisor, interceptor, detachOnly, undoMap);
        }
  
        return false;
     }
  
     protected void _regularPutObject(Fqn fqn, Object obj, InstanceAdvisor advisor, CachedType type) throws CacheException
     {
        // TODO workaround for deserialiased objects
        if (advisor == null)
        {
           advisor = new ClassInstanceAdvisor(obj);
           ((Advised) obj)._setInstanceAdvisor(advisor);
        }
  
        // Let's do batch update via Map instead
        Map map = new HashMap();
        // Always initialize the ref count so we can mark this as an AopNode.
        AOPInstance aopInstance = internal_.initializeAopInstance(fqn);
        // Insert interceptor at runtime
        CacheInterceptor interceptor = new CacheInterceptor(cache_, fqn, type);
        interceptor.setAopInstance(aopInstance);
        advisor.appendInterceptor(interceptor);
        cache_.addUndoInterceptor(advisor, interceptor, ModificationEntry.INTERCEPTOR_ADD);
  
        map.put(AOPInstance.KEY, aopInstance);
        // This is put into map first.
        internal_.putAopClazz(fqn, type.getType(), map);
        // we will do it recursively.
        // Map of sub-objects that are non-primitive
        Map subPojoMap = new HashMap();
        boolean hasFieldAnnotation = hasAnnotation(obj.getClass(), ((Advised) obj)._getAdvisor(), type);
  
        for (Iterator i = type.getFields().iterator(); i.hasNext();)
        {
           Field field = (Field) (((FieldPersistentReference) i.next())).get();
           Object value = null;
           try
           {
              value = field.get(obj);
           }
           catch (IllegalAccessException e)
           {
              throw new CacheException("field access failed", e);
           }
           CachedType fieldType = cache_.getCachedType(field.getType());
           // check for non-replicatable types
           if (CachedType.isPrimitiveNonReplicatable(field))
           {
              continue;
           }
  
           if (hasFieldAnnotation)
           {
              if (CachedType.hasTransientAnnotation(field, ((Advised) obj)._getAdvisor()))
              {
                 continue;
              }
           }
  
           // we simply treat field that has @Serializable as a primitive type.
           if (fieldType.isImmediate() ||
                   (hasFieldAnnotation &&
                           CachedType.hasSerializableAnnotation(field, ((Advised) obj)._getAdvisor())))
           {
              // switched using batch update
              map.put(field.getName(), value);
           }
           else
           {
              subPojoMap.put(field, value);
           }
        }
  
        // Use option to skip locking since we have parent lock already.
  //      cache_.put(fqn, map, internal_.getLockOption());
        cache_.put(fqn, map);
        // This is in-memory operation only
        internal_.setPojo(aopInstance, obj);
  
        Iterator it = subPojoMap.keySet().iterator();
        while (it.hasNext())
        {
           Field field = (Field) it.next();
           Object value = subPojoMap.get(field);
           Fqn tmpFqn = new Fqn(fqn, field.getName());
           _putObject(tmpFqn, value);
           // If it is Collection classes, we replace it with dynamic proxy.
           // But we will have to ignore it if value is null
           collectionHandler_.collectionReplaceWithProxy(obj, value, field, tmpFqn);
        }
  
        // Need to make sure this is behind put such that obj.toString is done correctly.
        if (log.isDebugEnabled())
        {
           log.debug("_regularPutObject(): inserting with fqn: " + fqn);
        }
     }
  
     private boolean hasAnnotation(Class clazz, Advisor advisor, CachedType type)
     {
        return CachedType.hasAnnotation(clazz, advisor, type);
     }
  
     private void createNode(Fqn fqn, GlobalTransaction tx)
     {
        TreeNode n, child_node;
        Object child_name;
        Fqn tmp_fqn = Fqn.ROOT;
  
        if (fqn == null) return;
        int treeNodeSize = fqn.size();
        n = cache_.getRoot();
        for (int i = 0; i < treeNodeSize; i++)
        {
           child_name = fqn.get(i);
           tmp_fqn = new Fqn(tmp_fqn, child_name);
           child_node = n.getChild(child_name);
           if (child_node == null)
           {
              child_node = n.createChild(child_name, tmp_fqn, n);
              if (tx != null)
              {
                 MethodCall undo_op = MethodCallFactory.create(MethodDeclarations.removeNodeMethodLocal, tx, tmp_fqn, false);
                 cache_.addUndoOperation(tx, undo_op);
              }
           }
           n = child_node;
        }
     }
  
     /**
      * Note that caller of this method will take care of synchronization within the <code>fqn</code> sub-tree.
      *
      * @param fqn
      * @param removeCacheInterceptor
      * @param evict
      * @return
      * @throws CacheException
      */
     public Object _removeObject(Fqn fqn, boolean removeCacheInterceptor, boolean evict)
             throws CacheException
     {
        Class clazz = internal_.peekAopClazz(fqn);
        if (clazz == null)
        {
           if (log.isTraceEnabled())
           {
              log.trace("_removeObject(): clasz is null. fqn: " + fqn + " No need to remove.");
           }
           return null;
        }
  
        if (log.isDebugEnabled())
        {
           log.debug("_removeObject(): removing object from fqn: " + fqn);
        }
  
        Object result = cache_.getObject(fqn);
        if (result == null)
        {
           // This is not a *Pojo*. Must be regular cache stuffs
           if (cache_.exists(fqn))
           {
              // TODO What do we do here. It can still have children pojo though.
              if (!evict)
              {
                 cache_.remove(fqn);
              }
              else
              {
                 cache_._evict(fqn);
              }
           }
           return null;
        }
  
        // can check if we need to do any bulk remove. E.g., if there is no object graph.
        if (getBulkRemove())
        {
           if (bulkRemove(fqn, result))
           {
              // Remember not to print obj here since it will trigger the CacheInterceptor.
              if (log.isDebugEnabled())
              {
                 log.debug("_removeObject(): fqn: " + fqn + "removing exisiting object in bulk.");
              }
  
              return result;
           }
           setBulkRemove(false);
        }
  
        if (graphHandler_.objectGraphRemove(fqn, removeCacheInterceptor, result, evict))
        {
           return result;
        }
  
        // Not multi-referenced
        if (Advised.class.isAssignableFrom(clazz))
        {
           _regularRemoveObject(fqn, removeCacheInterceptor, result, clazz, evict);
        }
        else if (collectionHandler_.collectionObjectRemove(fqn, removeCacheInterceptor, evict))
        {
        }
        else
        { // Just Serializable objects. Do a brute force remove is ok.
           serializableHandler_.serializableObjectRemove(fqn);
        }
  
        internal_.cleanUp(fqn, evict);
  
        // remove the interceptor as well.
        return result;
     }
  
     protected void _regularRemoveObject(Fqn fqn, boolean removeCacheInterceptor, Object result, Class clazz,
                                         boolean evict) throws CacheException
     {
        InstanceAdvisor advisor = ((Advised) result)._getInstanceAdvisor();
        CachedType type = cache_.getCachedType(clazz);
        for (Iterator i = type.getFields().iterator(); i.hasNext();)
        {
           Field field = (Field) (((FieldPersistentReference) i.next())).get();
           CachedType fieldType = cache_.getCachedType(field.getType());
           if (!fieldType.isImmediate())
           {
              _removeObject(new Fqn(fqn, field.getName()), removeCacheInterceptor, evict);
           }
        }
  
        // batch remove
        cache_.removeData(fqn);
  
        // Determine if we want to keep the interceptor for later use.
        if (removeCacheInterceptor)
        {
           CacheInterceptor interceptor = (CacheInterceptor) AopUtil.findCacheInterceptor(advisor);
           // Remember to remove the interceptor from in-memory object but make sure it belongs to me first.
           if (interceptor != null)
           {
              if (log.isDebugEnabled())
              {
                 log.debug("regularRemoveObject(): removed cache interceptor fqn: " + fqn + " interceptor: " + interceptor);
              }
              advisor.removeInterceptor(interceptor.getName());
              cache_.addUndoInterceptor(advisor, interceptor, ModificationEntry.INTERCEPTOR_REMOVE);
           }
        }
  
     }
  
     boolean isAopNode(Fqn fqn)
     {
        try
        {
           return (internal_.isAopNode(fqn));
        }
        catch (Exception e)
        {
           log.warn("isAopNode(): cache get operation generated exception " + e);
           return false;
        }
     }
  
     protected Map _findObjects(Fqn fqn) throws CacheException
     {
  
        // Traverse from fqn to do getObject, if it return a pojo we then stop.
        Map map = new HashMap();
        Object pojo = _getObject(fqn);
        if (pojo != null)
        {
           map.put(fqn, pojo); // we are done!
           return map;
        }
  
        findChildObjects(fqn, map);
        if (log.isDebugEnabled())
        {
           log.debug("_findObjects(): Fqn: " + fqn + " size of pojos found: " + map.size());
        }
        return map;
     }
  
     protected void findChildObjects(Fqn fqn, Map map) throws CacheException
     {
        // We need to traverse then
        Set set = cache_.getChildrenNames(fqn);
        if (set == null) return; // We stop here.
        Iterator it = set.iterator();
        while (it.hasNext())
        {
           String obj = (String) it.next();
           Fqn newFqn = new Fqn(fqn, obj);
  
           Object pojo = _getObject(newFqn);
           if (pojo != null)
           {
              map.put(newFqn, pojo);
           }
           else
           {
              findChildObjects(newFqn, map);
           }
        }
     }
  }
  
  
  
  1.1      date: 2006/10/31 08:01:13;  author: bwang;  state: Exp;JBossCache/old/src/org/jboss/cache/aop/CachedAttribute.java
  
  Index: CachedAttribute.java
  ===================================================================
  package org.jboss.cache.aop;
  
  import java.lang.reflect.Method;
  
  /**
   * Class represent a class attribute. Currently not in use.
   * @author <a href="mailto:harald at gliebe.de">Harald Gliebe</a>
   * @author Ben Wang
   */
  
  public class CachedAttribute
  {
  
     protected String name;
     protected Class type;
     protected Method get, set;
  
     public CachedAttribute()
     {
     }
  
     public CachedAttribute(String name)
     {
        this.name = name;
     }
  
     public String getName()
     {
        return this.name;
     }
  
     public Class getType()
     {
        return this.type;
     }
  
     public void setType(Class type)
     {
        if (this.type != null && this.type != type) {
           // TODO: provide better info
           throw new IllegalArgumentException("get/set types differ");
        }
        this.type = type;
     }
  
     public Method getGet()
     {
        return this.get;
     }
  
     public void setGet(Method get)
     {
        this.get = get;
     }
  
     public Method getSet()
     {
        return this.set;
     }
  
     public void setSet(Method set)
     {
        this.set = set;
     }
  
  } // CachedAttribute
  
  
  
  1.1      date: 2006/10/31 08:01:13;  author: bwang;  state: Exp;JBossCache/old/src/org/jboss/cache/aop/AOPInstance.java
  
  Index: AOPInstance.java
  ===================================================================
  /*
   * JBoss, the OpenSource J2EE webOS
   *
   * Distributable under LGPL license.
   * See terms of license at gnu.org.
   */
  package org.jboss.cache.aop;
  
  import java.io.Serializable;
  import java.util.List;
  import java.util.ArrayList;
  import org.jboss.cache.Fqn;
  
  /**
   * Wrapper type for cached AOP instances.
   * When an object is looked up or put in TreeCacheAOP, this object will be advised with a CacheInterceptor.
   * The tree 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 wrapped into an AOPInstance.
   * In addition, this instance also serves as a metadata for PojoCache. E.g., it has a reference count for
   * multiple references and reference FQN.
   *
   * @author Harald Gliebe
   * @author Ben Wang
   */
  public class AOPInstance implements Serializable // Use Serializable since Externalizable is not smaller
  {
  //    protected static Log log=LogFactory.getLog(AOPInstance.class.getName());
     public static final Object KEY = "AOPInstance";
     public static final int INITIAL_COUNTER_VALUE = -1;
  
     static final long serialVersionUID = 6492134565825613209L;
  
     // The instance is transient to avoid reflection outside the VM
     protected transient Object instance_;
  
     // If not null, it signifies that this is a reference that points to this fqn.
     // Note that this will get replicated.
     protected String refFqn_ = null;
  
     // Reference counting. THis will get replicated as well. This keep track of number of other instances
     // that referenced this fqn.
     protected int refCount_ = INITIAL_COUNTER_VALUE;
  
     // List of fqns that reference this fqn. Assume list size is not big.
     protected List referencingFqnList_ = null;
  
     public AOPInstance()
     {
     }
  
     public AOPInstance(Object instance)
     {
        set(instance);
     }
  
     Object get()
     {
        return instance_;
     }
  
     void set(Object instance)
     {
        instance_ = instance;
     }
  
     String getRefFqn()
     {
        return refFqn_;
     }
  
     void setRefFqn(String refFqn)
     {
        refFqn_ = refFqn;
     }
  
     void removeRefFqn()
     {
        refFqn_ = null;
     }
  
     synchronized int incrementRefCount(Fqn referencingFqn)
     {
        if(referencingFqn != null)
        {
           if( referencingFqnList_ == null)
           {
              referencingFqnList_ = new ArrayList();
           }
  
           if(referencingFqnList_.contains(referencingFqn))
              throw new IllegalStateException("AOPInstance.incrementRefCount(): source fqn: " +
                      referencingFqn + " is already present.");
  
           referencingFqnList_.add(referencingFqn);
        }
  
        refCount_ += 1;
  //logger_.info("incrementRefCount(): current ref count " +refCount_);
        return refCount_;
     }
  
     synchronized int decrementRefCount(Fqn sourceFqn)
     {
  
        if(sourceFqn != null)
        {
           if(!referencingFqnList_.contains(sourceFqn))
              throw new IllegalStateException("AOPInstance.decrementRefCount(): source fqn: " +
                      sourceFqn + " is not present.");
  
           referencingFqnList_.remove(sourceFqn);
        }
  
        refCount_ -= 1;
  //logger_.info("decrementRefCount(): current ref count " +refCount_);
        return refCount_;
     }
  
     synchronized int getRefCount()
     {
        return refCount_;
     }
  
     synchronized Fqn getAndRemoveFirstFqnInList()
     {
        return (Fqn)referencingFqnList_.remove(0);
     }
  
     synchronized void addFqnIntoList(Fqn fqn)
     {
        referencingFqnList_.add(0, fqn);
     }
  }
  
  
  
  1.1      date: 2006/10/31 08:01:13;  author: bwang;  state: Exp;JBossCache/old/src/org/jboss/cache/aop/BaseInterceptor.java
  
  Index: BaseInterceptor.java
  ===================================================================
  /*
   * JBoss, the OpenSource J2EE webOS
   *
   * Distributable under LGPL license.
   * See terms of license at gnu.org.
   */
  package org.jboss.cache.aop;
  
  import org.jboss.cache.Fqn;
  
  
  /**
   *  Base cache interceptor
   * @author Ben Wang
   */
  
  public interface BaseInterceptor
        extends org.jboss.aop.advice.Interceptor
  {
     /**
      * Get the original fqn that is associated with this interceptor (or advisor).
      *
      */
     Fqn getFqn();
  
     void setFqn(Fqn fqn);
  
     AOPInstance getAopInstance();
  
     void setAopInstance(AOPInstance aopInstance);
  }
  
  
  



More information about the jboss-cvs-commits mailing list