[jboss-cvs] JBossAS SVN: r74444 - trunk/tomcat/src/main/org/jboss/web/tomcat/service/session.

jboss-cvs-commits at lists.jboss.org jboss-cvs-commits at lists.jboss.org
Wed Jun 11 21:13:05 EDT 2008


Author: bstansberry at jboss.com
Date: 2008-06-11 21:13:05 -0400 (Wed, 11 Jun 2008)
New Revision: 74444

Modified:
   trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/CacheListener.java
   trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/CacheListenerBase.java
   trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/FieldBasedClusteredSession.java
   trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/FieldBasedJBossCacheService.java
   trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossCacheManager.java
   trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/Util.java
Log:
[JBAS-5620] Replace monitoring of Pojos via Observer pattern with using CacheListener

Modified: trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/CacheListener.java
===================================================================
--- trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/CacheListener.java	2008-06-12 01:03:02 UTC (rev 74443)
+++ trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/CacheListener.java	2008-06-12 01:13:05 UTC (rev 74444)
@@ -1,35 +1,31 @@
 /*
-* JBoss, Home of Professional Open Source
-* Copyright 2005, JBoss Inc., and individual contributors as indicated
-* by the @authors tag. See the copyright.txt in the distribution for a
-* full listing of individual contributors.
-*
-* This is free software; you can redistribute it and/or modify it
-* under the terms of the GNU Lesser General Public License as
-* published by the Free Software Foundation; either version 2.1 of
-* the License, or (at your option) any later version.
-*
-* This software is distributed in the hope that it will be useful,
-* but WITHOUT ANY WARRANTY; without even the implied warranty of
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-* Lesser General Public License for more details.
-*
-* You should have received a copy of the GNU Lesser General Public
-* License along with this software; if not, write to the Free
-* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
-* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
-*/
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
 package org.jboss.web.tomcat.service.session;
 
 import java.util.Map;
 
 import org.jboss.cache.Fqn;
-import org.jboss.cache.notifications.annotation.CacheStarted;
-import org.jboss.cache.notifications.annotation.CacheStopped;
 import org.jboss.cache.notifications.annotation.NodeModified;
 import org.jboss.cache.notifications.annotation.NodeRemoved;
-import org.jboss.cache.notifications.event.CacheStartedEvent;
-import org.jboss.cache.notifications.event.CacheStoppedEvent;
 import org.jboss.cache.notifications.event.NodeModifiedEvent;
 import org.jboss.cache.notifications.event.NodeRemovedEvent;
 import org.jboss.logging.Logger;
@@ -37,6 +33,12 @@
 import org.jboss.web.tomcat.service.session.ClusteredSession.SessionMetadata;
 import org.jboss.web.tomcat.service.session.ClusteredSession.SessionTimestamp;
 
+/**
+ * Listens for removals and modifications in the cache, notifying the 
+ * session manager of significant events.
+ * 
+ * @author Brian Stansberry
+ */
 @org.jboss.cache.notifications.annotation.CacheListener
 public class CacheListener extends CacheListenerBase
 {
@@ -44,8 +46,10 @@
    private static final int POJO_ATTRIBUTE_FQN_INDEX = SESSION_ID_FQN_INDEX + 1;
    // Element within an FQN that is the root of an individual Pojo attribute
    private static final int POJO_KEY_FQN_INDEX = POJO_ATTRIBUTE_FQN_INDEX + 1;
-   // Size of an Fqn that points to the root of a session
-   private static final int POJO_KEY_FQN_SIZE = POJO_KEY_FQN_INDEX + 1;
+   // Element within an FQN that is the root of a session's internal pojo storage area
+   private static final int POJO_INTERNAL_FQN_INDEX = SESSION_ID_FQN_INDEX + 1;
+   // Minimum size of an FQN that is below the root of a session's internal pojo storage area
+   private static final int POJO_INTERNAL_FQN_SIZE = POJO_INTERNAL_FQN_INDEX + 1;
    private static Logger log_ = Logger.getLogger(CacheListener.class);
    private boolean fieldBased_;
 
@@ -55,124 +59,144 @@
       fieldBased_ = (manager_.getReplicationGranularity() == ReplicationGranularity.FIELD);
    }
 
-   // --------------- TreeCacheListener methods ------------------------------------
+   // --------------- CacheListener methods ------------------------------------
 
    @NodeRemoved
    public void nodeRemoved(NodeRemovedEvent event)
    {      
-      if (event.isPre() || event.isOriginLocal())
+      if (event.isPre())
          return;
       
+      boolean local = event.isOriginLocal();
+      if (!fieldBased_ && local)
+         return;
+      
       Fqn fqn = event.getFqn();
       boolean isBuddy = isBuddyFqn(fqn);
       
-      // Potential removal of a Pojo where we need to unregister as an Observer.
-      if (fieldBased_ 
-            && isFqnPojoKeySized(fqn, isBuddy)
+      if (!local 
+            && isFqnSessionRootSized(fqn, isBuddy) 
             && isFqnForOurWebapp(fqn, isBuddy))
       {
+         // A session has been invalidated from another node;
+         // need to inform manager
          String sessId = getIdFromFqn(fqn, isBuddy);
-         String attrKey = getPojoKeyFromFqn(fqn, isBuddy);
-         manager_.processRemoteAttributeRemoval(sessId, attrKey);
+         manager_.notifyRemoteInvalidation(sessId);
       }
-      else if(isFqnSessionRootSized(fqn, isBuddy) 
+      else if (local && !isBuddy
+                  && isPossibleInternalPojoFqn(fqn) 
                   && isFqnForOurWebapp(fqn, isBuddy))
       {
-         // A session has been invalidated from another node;
-         // need to inform manager
+         // One of our sessions' pojos is modified; need to inform
+         // the manager so it can mark the session dirty
          String sessId = getIdFromFqn(fqn, isBuddy);
-         manager_.processRemoteInvalidation(sessId);
+         manager_.notifyLocalAttributeModification(sessId);
       }
    }
    
    @NodeModified
    public void nodeModified(NodeModifiedEvent event)
-   {          
-      if (event.isPre() || event.isOriginLocal())
+   {      
+      if (event.isPre())
          return;
       
+      boolean local = event.isOriginLocal();
+      if (!fieldBased_ && local)
+         return;
+      
       Fqn fqn = event.getFqn();
       boolean isBuddy = isBuddyFqn(fqn);      
-      // We only care if there is a chance this is for a session root
-      if (!isFqnSessionRootSized(fqn, isBuddy))
-         return;
       
-      // We only care if this is for our webapp
-      if (!isFqnForOurWebapp(fqn, isBuddy))
-         return;
-
-      // Query if we have version value in the distributed cache. 
-      // If we have a version value, compare the version and invalidate if necessary.
-      Map data = event.getData();
-      Integer version = (Integer) data.get(JBossCacheService.VERSION_KEY);
-      if(version != null)
+      if (isFqnSessionRootSized(fqn, isBuddy)
+             &&isFqnForOurWebapp(fqn, isBuddy))
       {
-         String realId = getIdFromFqn(fqn, isBuddy);
-      
-         ClusteredSession session = manager_.findLocalSession(realId);
-         if (session == null)
+         // Query if we have version value in the distributed cache. 
+         // If we have a version value, compare the version and invalidate if necessary.
+         Map data = event.getData();
+         Integer version = (Integer) data.get(JBossCacheService.VERSION_KEY);
+         if(version != null)
          {
-            String owner = isBuddy ? getBuddyOwner(fqn) : null;
-            // Notify the manager that an unloaded session has been updated
-            manager_.unloadedSessionChanged(realId, owner, 
-                                            (SessionTimestamp) data.get(JBossCacheService.TIMESTAMP_KEY), 
-                                            (SessionMetadata) data.get(JBossCacheService.METADATA_KEY));
-         }
-         else if (session.isNewData(version.intValue()))
-         {
-            // Need to invalidate the loaded session
-            session.setOutdatedVersion(version.intValue());
-            if(log_.isTraceEnabled())
+            String realId = getIdFromFqn(fqn, isBuddy);
+         
+            ClusteredSession session = manager_.findLocalSession(realId);
+            if (session == null)
             {
-               log_.trace("nodeDirty(): session in-memory data is " +
-                          "invalidated with id: " + realId + " and version: " +
-                          version.intValue());
+               String owner = isBuddy ? getBuddyOwner(fqn) : null;
+               // Notify the manager that an unloaded session has been updated
+               manager_.unloadedSessionChanged(realId, owner, 
+                                               (SessionTimestamp) data.get(JBossCacheService.TIMESTAMP_KEY), 
+                                               (SessionMetadata) data.get(JBossCacheService.METADATA_KEY));
             }
+            else if (session.isNewData(version.intValue()))
+            {
+               // Need to invalidate the loaded session
+               session.setOutdatedVersion(version.intValue());
+               if(log_.isTraceEnabled())
+               {
+                  log_.trace("nodeDirty(): session in-memory data is " +
+                             "invalidated with id: " + realId + " and version: " +
+                             version.intValue());
+               }
+            }
+            else if (!isBuddy)
+            {
+               log_.warn("Possible concurrency problem: Replicated version id " + 
+                         version + " matches in-memory version for session " + realId); 
+            }
+            /*else 
+            {
+               We have a local session but got a modification for the buddy tree.
+               This means another node is in the process of taking over the session;
+               we don't worry about it
+            }
+             */
          }
-         else if (!isBuddy)
+         else
          {
-            log_.warn("Possible concurrency problem: Replicated version id " + 
-                      version + " matches in-memory version for session " + realId); 
+            log_.warn("No VERSION_KEY attribute found in " + fqn);
          }
-         /*else 
-         {
-            We have a local session but got a modification for the buddy tree.
-            This means another node is in the process of taking over the session;
-            we don't worry about it
-         }
-          */
       }
-      /* else if (fieldBased_)
+      else if (local && !isBuddy
+            && isPossibleInternalPojoFqn(fqn) 
+            && isFqnForOurWebapp(fqn, isBuddy))
       {
-         // could be for the __JBossInternal__ fqn, which we want to ignore
+         // One of our sessions' pojos is modified; need to inform
+         // the manager so it can mark the session dirty
+         String sessId = getIdFromFqn(fqn, isBuddy);
+         manager_.notifyLocalAttributeModification(sessId);
       }
-      else
-      {
-         log_.warn("No VERSION_KEY attribute found in " + fqn);
-      } */
    }
-
-   @CacheStarted
-   public void cacheStarted(CacheStartedEvent event)
-   {
-      // TODO will need to synchronize this with local sessions
-      // BES -- 2007/07/03 Not sure what this means
-   }
-
-   @CacheStopped
-   public void cacheStopped(CacheStoppedEvent event)
-   {
-      // TODO will need to synchronize this with local sessions
-      // BES -- 2007/07/03 Not sure what this means
-   }
    
-   public static boolean isFqnPojoKeySized(Fqn fqn, boolean isBuddy)
-   {
-      return fqn.size() == (isBuddy ? BUDDY_BACKUP_ROOT_OWNER_SIZE + POJO_KEY_FQN_SIZE : POJO_KEY_FQN_SIZE);
-   }
-   
    public static String getPojoKeyFromFqn(Fqn fqn, boolean isBuddy)
    {
       return (String) fqn.get(isBuddy ? BUDDY_BACKUP_ROOT_OWNER_SIZE + POJO_KEY_FQN_INDEX: POJO_KEY_FQN_INDEX);
    }
+   
+   /**
+    * Check if the fqn is big enough to be in the internal pojo area but
+    * isn't in the regular attribute area.
+    * 
+    * Structure in the cache is:
+    * 
+    * /JSESSION
+    * ++ /hostname
+    * ++++ /contextpath
+    * ++++++ /sessionid
+    * ++++++++ /ATTRIBUTE
+    * ++++++++ /_JBossInternal_
+    * ++++++++++ etc etc
+    * 
+    * If the Fqn size is big enough to be "etc etc" or lower, but the 4th
+    * level is "ATTRIBUTE", it must be under _JBossInternal_. We discriminate
+    * based on != ATTRIBUTE to avoid having to code to the internal PojoCache
+    * _JBossInternal_ name.
+    * 
+    * @param fqn
+    * @return
+    */
+   public static boolean isPossibleInternalPojoFqn(Fqn fqn)
+   {      
+      return (fqn.size() > POJO_INTERNAL_FQN_SIZE 
+            && JBossCacheService.ATTRIBUTE.equals(fqn.get(POJO_INTERNAL_FQN_INDEX)) == false);
+   }
 }

Modified: trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/CacheListenerBase.java
===================================================================
--- trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/CacheListenerBase.java	2008-06-12 01:03:02 UTC (rev 74443)
+++ trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/CacheListenerBase.java	2008-06-12 01:13:05 UTC (rev 74444)
@@ -1,3 +1,24 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
 package org.jboss.web.tomcat.service.session;
 
 import org.jboss.cache.Fqn;
@@ -3,4 +24,9 @@
 import org.jboss.cache.buddyreplication.BuddyManager;
 
+/**
+ * Base class for JBC cache listener impls.
+ * 
+ * @author Brian Stansberry
+ */
 public class CacheListenerBase
 {

Modified: trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/FieldBasedClusteredSession.java
===================================================================
--- trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/FieldBasedClusteredSession.java	2008-06-12 01:03:02 UTC (rev 74443)
+++ trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/FieldBasedClusteredSession.java	2008-06-12 01:13:05 UTC (rev 74444)
@@ -21,9 +21,6 @@
 */
 package org.jboss.web.tomcat.service.session;
 
-import org.jboss.aspects.patterns.observable.Observer;
-import org.jboss.aspects.patterns.observable.Subject;
-
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
@@ -34,6 +31,8 @@
 
 import javax.servlet.http.HttpSessionActivationListener;
 
+import org.jboss.aop.Advised;
+
 /**
  * <p>
  * Implementation of a clustered session for JBossCacheManager. The replication granularity
@@ -69,7 +68,7 @@
  * @version $Revision: 58586 $
  */
 class FieldBasedClusteredSession
-   extends JBossCacheClusteredSession implements Observer
+   extends JBossCacheClusteredSession
 {
    /** The serialVersionUID */
    private static final long serialVersionUID = 8347544395334247623L;
@@ -216,21 +215,10 @@
          {
             String name = (String) it.next();
             
-            Object oldAttrib = null;
             Object newAttrib = fieldProxy_.getPojo(realId, name);
             if (newAttrib != null)
             {
-               oldAttrib = attributes_.put(name, newAttrib);
-            
-               if (oldAttrib != newAttrib)
-               {
-                  // Need to observe this pojo as well
-                  // for any modification events.
-                  fieldProxy_.addObserver(this, newAttrib);
-                  
-                  // Stop observing the old pojo
-                  fieldProxy_.removeObserver(this, oldAttrib); // null pojo OK :)
-               }
+               attributes_.put(name, newAttrib);
                
                // Check if we have a listener
                if (newAttrib instanceof HttpSessionActivationListener)
@@ -238,12 +226,8 @@
             }
             else
             {
-               // This shouldn't happen -- if we had a key, newAttrib s/b not null
-               
-               oldAttrib = attributes_.remove(name);
-               // Stop observing this pojo
-               fieldProxy_.removeObserver(this, oldAttrib); // null pojo OK :)                 
-               
+               // This shouldn't happen -- if we had a key, newAttrib s/b not null               
+               attributes_.remove(name);                            
             }
          }
       }
@@ -251,11 +235,9 @@
       hasActivationListener = hasListener ? Boolean.TRUE : Boolean.FALSE;
       
       // Cycle through remaining old keys and remove them 
-      // and also remove ourself as Observer
       for (Iterator it = oldKeys.iterator(); it.hasNext(); )
       {
-         Object oldAttrib = attributes_.remove(it.next());
-         fieldProxy_.removeObserver(this, oldAttrib); 
+         attributes_.remove(it.next());
       }
       
       // Restore any excluded attributes
@@ -289,7 +271,7 @@
     */
    protected boolean isMutable(Object attribute)
    {
-      boolean pojo = (attribute instanceof Subject);
+      boolean pojo = (attribute instanceof Advised);
       boolean mutable = (!pojo && super.isMutable(attribute));
       return mutable;
    }
@@ -312,7 +294,6 @@
          log.warn("removeJBossInternalAttribute(): null value to remove with key: "+ name);
          return null;
       }
-      fieldProxy_.removeObserver(this, result);
          
       return result;
    }
@@ -358,10 +339,6 @@
       if (!replicationExcludes.contains(key))
       {   
          oldVal = fieldProxy_.setPojo(realId, key, value, this);
-         if(oldVal != null)
-         {  // We are done with the old one.
-            fieldProxy_.removeObserver(this, oldVal);
-         }
    
          if(value != null)
          {
@@ -371,9 +348,6 @@
                // We need to obtain the proxy first.
                value = fieldProxy_.getPojo(realId, key);
             }
-
-            // Need to use obj since it can return as a proxy.
-            fieldProxy_.addObserver(this, value);
          }
 
          // Only mark session dirty if we can replicate the attribute
@@ -385,20 +359,4 @@
       
       return oldVal;
    }
-
-   /**
-    * Call back handler for the aop Subject/Observer pattern. 
-    * We subscribe to the event of field write and mark ourself dirty.
-    * 
-    * @param subject  the object we are Observing
-    */
-   public void fireChange(Subject subject)
-   {
-      // Currently we don't care who is modified, we will simply mark session is dirty for replication purpose.
-      if(log.isTraceEnabled())
-      {
-         log.trace("fireChange(): subject has changed: " +subject);
-      }
-      sessionAttributesDirty();
-   }
 }

Modified: trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/FieldBasedJBossCacheService.java
===================================================================
--- trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/FieldBasedJBossCacheService.java	2008-06-12 01:03:02 UTC (rev 74443)
+++ trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/FieldBasedJBossCacheService.java	2008-06-12 01:13:05 UTC (rev 74444)
@@ -22,23 +22,14 @@
 
 package org.jboss.web.tomcat.service.session;
 
-import java.lang.reflect.Field;
 import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.Iterator;
 import java.util.List;
-import java.util.Map;
 import java.util.Set;
 import java.util.StringTokenizer;
-import java.util.WeakHashMap;
 
-import org.jboss.aspects.patterns.observable.Observer;
-import org.jboss.aspects.patterns.observable.Subject;
 import org.jboss.cache.CacheException;
 import org.jboss.cache.Fqn;
 import org.jboss.cache.pojo.PojoCache;
-import org.jboss.cache.pojo.PojoCacheAlreadyDetachedException;
 
 /**
  * Adds PojoCache-specific capabilities to JBossCacheService.
@@ -49,7 +40,6 @@
 public class FieldBasedJBossCacheService extends JBossCacheService
 {
    private final PojoCache pojoCache_;
-   private WeakHashMap typeMap = new WeakHashMap();
    
    /**
     * Create a new FieldBasedJBossCacheService.
@@ -248,270 +238,4 @@
       }
    }
 
-   /**
-    * Recursively adds session as observer to the pojo graph. Assumes the 
-    * whole object graph has Subject "introduction" declared. If a portion
-    * of the graph isn't a Subject, the recursion does not continue below
-    * that part of the graph.
-    *  
-    * @param session  the session
-    * @param pojo     the pojo.  Can be <code>null</code>.
-    */
-   public void addObserver(Observer session, Object pojo)
-   {
-      addObserver(session, pojo, new HashSet());
-   }
-   
-   private void addObserver(Observer session, Object pojo, Set processed)
-   {
-      if ( pojo instanceof Collection )
-      {
-         if(log_.isTraceEnabled())
-         {
-            log_.trace("addObserver(): pojo of type " +pojo.getClass().getName() + " is a Collection; trying to observe elements");
-         }
-         Collection col = (Collection)pojo;
-         for (Iterator i = col.iterator(); i.hasNext();) {
-            // If not a managed pojo, will return anyway
-            addObserver(session, i.next(), processed);
-         }
-      } 
-      else if (pojo instanceof Map)
-      {
-         if(log_.isTraceEnabled())
-         {
-            log_.trace("addObserver(): pojo of type " +pojo.getClass().getName() + " is a Map; trying to observe entries");
-         }
-         for (Iterator i = ((Map)pojo).entrySet().iterator(); i.hasNext();) 
-         {
-            Map.Entry entry = (Map.Entry) i.next();
-
-            // Walk thru key and value
-            addObserver(session, entry.getKey(), processed);
-            addObserver(session, entry.getValue(), processed);
-         }
-      }
-
-      if(! (pojo instanceof Subject) )
-      {
-         if(log_.isTraceEnabled())
-         {
-            log_.trace("addObserver(): pojo of type " +pojo.getClass().getName() + " is not a Subject");
-         }
-         return;  // No need to add observer since it is primitive.
-      }
-
-      Subject subject = (Subject)pojo;
-      subject.addObserver(session);
-      
-      if(log_.isTraceEnabled())
-      {
-         log_.trace("addObserver(): session: " +session + " pojo name: " +pojo.getClass().getName());
-      }
-      
-      // Examine each field of the type and its superclasses to see if
-      // we need to add the observer to the pojo held by that field
-      // Traverse recursively
-      
-      // First identify and cache the names of all the class' 
-      // non-immediate fields 
-      Class type = pojo.getClass();      
-      Set complexFields = (Set) typeMap.get(type);
-      if (complexFields == null)
-      {
-         complexFields = Util.parseComplexFields(type);
-         typeMap.put(type, complexFields);
-      }
-      
-      if (complexFields.size() == 0)
-         return;
-
-      // Store a ref to the pojo to avoid cyclic additions
-      processed.add(pojo);
-      
-      for (Iterator iter = complexFields.iterator(); iter.hasNext();)
-      {
-         String fieldName = (String) iter.next();
-         Class curType = type;
-         while (curType != null)
-         {
-            try
-            {
-               Field field = curType.getDeclaredField(fieldName);
-               boolean accessible = field.isAccessible();
-               Object value = null;
-               try 
-               {
-                  field.setAccessible(true);
-                  
-                  value=field.get(pojo);
-                  // Continue recursively unless we've already handled this value
-                  if (value != null && !processed.contains(value))
-                     addObserver(session, value, processed);
-                  break;
-               }
-               catch(IllegalAccessException e) 
-               {
-                  throw new RuntimeException("field access failed", e);
-               }
-               finally
-               {
-                  field.setAccessible(accessible);
-               }
-            }
-            catch (NoSuchFieldException e)
-            {
-               // Check if the field is declared in a superclass
-               curType = curType.getSuperclass();
-               if (curType == null)
-                  throw new RuntimeException("Field "  + fieldName + 
-                        " does not exist", e);
-            }
-         }
-      }
-   }
-
-   /**
-    * Recursively removes session as observer to the pojo graph. Assumes the 
-    * whole object graph has Subject "introduction" declared. If a portion
-    * of the graph isn't a Subject, the recursion does not continue below
-    * that part of the graph.
-    *  
-    * @param session  the session
-    * @param pojo the pojo to stop observing.  Can be <code>null</code>.
-    */
-   public void removeObserver(Observer session, Object pojo)
-   {
-      removeObserver(session, pojo, new HashSet());
-   }
-   
-   private void removeObserver(Observer session, Object pojo, Set stack)
-   {
-      if ( pojo instanceof Collection )
-      {
-         Collection col = (Collection)pojo;
-         for (Iterator i = col.iterator(); i.hasNext();) {
-            Object obj = i.next();
-            // If not a managed pojo, will return anyway
-            removeObserver(session, obj, stack);
-         }
-   
-         return;
-      } 
-      else if (pojo instanceof Map)
-      {
-         Map map = (Map)pojo;
-         for (Iterator i = map.keySet().iterator(); i.hasNext();) {
-            Object key = i.next();
-            Object value = map.get(key);
-   
-            // Walk thru key and value
-            removeObserver(session, key, stack);
-            removeObserver(session, value, stack);
-         }
-   
-         return;
-      }
-      // BRIAN 3/14 changed this from checking Advised to checking Subject
-      // since that is what we cast to below
-      if(! (pojo instanceof Subject) )
-      {
-         return;  // No need to add observer since it is primitive.
-      }
-
-      Subject subject = (Subject)pojo;
-      try
-      {
-         subject.removeObserver(session);
-      }
-      catch (PojoCacheAlreadyDetachedException e)
-      {
-         // We've hit a stale pojo; can't continue further
-         // This will regularly happen when we handle notifications
-         // of remote attribute removals and remote invalidations
-         if(log_.isTraceEnabled())
-         {
-            log_.trace("removeObserver(): found detached in session: " +session + " pojo name: " +pojo.getClass().getName());
-         }
-         return;
-      }
-      
-      if(log_.isTraceEnabled())
-      {
-         log_.trace("removeObserver(): session: " +session + " pojo name: " +pojo.getClass().getName());
-      }
-      
-      // Examine each field of the type and its superclasses to see if
-      // we need to remove the observer from the pojo held by that field
-      // Traverse recursively
-      
-      // First identify and cache the names of all the class' 
-      // non-immediate fields 
-      Class type = pojo.getClass();
-      Set complexFields = (Set) typeMap.get(type);
-      if (complexFields == null)
-      {
-         complexFields = Util.parseComplexFields(type);
-         typeMap.put(type, complexFields);
-      }
-
-      if (complexFields.size() == 0)
-         return;
-      
-      // Store a ref to the pojo to avoid cyclic removals
-      stack.add(pojo);
-      
-      for (Iterator iter = complexFields.iterator(); iter.hasNext();)
-      {
-         String fieldName = (String) iter.next();
-         Class curType = type;
-         while (curType != null)
-         {
-            try
-            {
-               Field field = curType.getDeclaredField(fieldName);
-               boolean accessible = field.isAccessible();
-               Object value = null;
-               try 
-               {
-                  field.setAccessible(true);
-                  
-                  value=field.get(pojo);
-                  // Continue recursively unless we've already handled this value
-                  if (value != null && !stack.contains(value))
-                     removeObserver(session, value, stack);
-                  break;
-               }
-               catch (PojoCacheAlreadyDetachedException e)
-               {
-                  // We've hit a stale proxy; can't continue further
-                  // This will regularly happen when we handle notifications
-                  // of remote attribute removals and remote invalidations
-                  if(log_.isTraceEnabled())
-                  {
-                     log_.trace("removeObserver(): found detached pojo in field " + field.getName() + " in object graph under session: " +session + " pojo name: " +pojo.getClass().getName());
-                  }
-                  break;
-               }
-               catch(IllegalAccessException e) 
-               {
-                  throw new RuntimeException("field access failed", e);
-               }
-               finally
-               {
-                  field.setAccessible(accessible);
-               }
-            }
-            catch (NoSuchFieldException e)
-            {
-               // Check if the field is declared in a superclass
-               curType = curType.getSuperclass();
-               if (curType == null)
-                  throw new RuntimeException("Field "  + fieldName + 
-                        " does not exist", e);
-            }
-         }
-      }
-   }
-
 }

Modified: trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossCacheManager.java
===================================================================
--- trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossCacheManager.java	2008-06-12 01:03:02 UTC (rev 74443)
+++ trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossCacheManager.java	2008-06-12 01:13:05 UTC (rev 74444)
@@ -1530,40 +1530,14 @@
          }
       }
    }
-   
-   public void processRemoteAttributeRemoval(String realId, String attrKey)
-   {
-      
-      ClusteredSession session = findLocalSession(realId);
-      if (session != null)
-      {
-         boolean localCall = false; // call is due to remote event
-         boolean localOnly = true;  // don't call back into cache
-         boolean notify = false;    // SRV.10.7 gives us leeway
-                                    // not to notify listeners, 
-                                    // which is safer
-         
-         // Ensure the correct TCL is in place
-         ClassLoader prevTcl = Thread.currentThread().getContextClassLoader();
-         try
-         {
-            Thread.currentThread().setContextClassLoader(tcl_);
-            synchronized (session)
-            {
-               session.removeAttributeInternal(attrKey, localCall, localOnly, notify);
-            }
-            if (log_.isTraceEnabled())
-               log_.trace("processRemoteAttributeRemoval: removed attribute " + 
-                          attrKey + " from " + realId);
-         }
-         finally
-         {
-            Thread.currentThread().setContextClassLoader(prevTcl);
-         }
-      }      
-   }
 
-   public void processRemoteInvalidation(String realId)
+   /**
+    * Notifies the manager that a session in the distributed cache has
+    * been invalidated
+    * 
+    * @param realId the session id excluding any jvmRoute
+    */
+   public void notifyRemoteInvalidation(String realId)
    {
       // Remove the session from our local map
       ClusteredSession session = (ClusteredSession) sessions_.remove(realId);
@@ -1609,6 +1583,26 @@
       }
    }
    
+   /**
+    * Callback from the distributed cache notifying of a local modification
+    * to a session's attributes.  Meant for use with FIELD granularity,
+    * where the session may not be aware of modifications.
+    * 
+    * @param realId the session id excluding any jvmRoute
+    */
+   public void notifyLocalAttributeModification(String realId)
+   {
+      ClusteredSession session = (ClusteredSession) sessions_.get(realId);
+      if (session != null)
+      {
+         session.sessionAttributesDirty();
+      }
+      else
+      {
+         log_.warn("");
+      }
+   }
+   
    private void sessionPassivated()
    {
       int pc = passivatedCount_.incrementAndGet();

Modified: trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/Util.java
===================================================================
--- trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/Util.java	2008-06-12 01:03:02 UTC (rev 74443)
+++ trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/Util.java	2008-06-12 01:13:05 UTC (rev 74444)
@@ -23,8 +23,6 @@
 package org.jboss.web.tomcat.service.session;
 
 import java.io.Serializable;
-import java.lang.reflect.Field;
-import java.lang.reflect.Modifier;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.HashSet;
@@ -179,49 +177,8 @@
               || (pojo instanceof Advised)
               || (immediates.contains(pojo.getClass())));
    }
-   
-   public static Set parseComplexFields(Class clazz)
-   {
-      Set result = new HashSet();
-      
-      while (clazz != null)
-      {
-         Field[] fields = clazz.getDeclaredFields();
-         for (int i = 0; i < fields.length; i++)
-         {
-            if (!immediates.contains(fields[i].getType()) 
-                  && isReplicatable(fields[i]))
-            {
-               result.add(fields[i].getName());
-            }
-         }
-         
-         clazz = clazz.getSuperclass();
-      }
-      return result;
-   }
 
    /**
-    * Returns false if the given field is static, transient or final.
-    * 
-    * @param f the field
-    * @return
-    */
-   public static boolean isReplicatable(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 false;
-      }
-      return true;
-   }
-
-   /**
     * Prevent instantiation.
     */
    private Util() {}




More information about the jboss-cvs-commits mailing list