[jboss-cvs] JBossAS SVN: r72946 - in trunk: tomcat/src/main/org/jboss/web/tomcat/service/session and 1 other directory.

jboss-cvs-commits at lists.jboss.org jboss-cvs-commits at lists.jboss.org
Thu May 1 12:36:50 EDT 2008


Author: bstansberry at jboss.com
Date: 2008-05-01 12:36:49 -0400 (Thu, 01 May 2008)
New Revision: 72946

Added:
   trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossSerializationObjectStreamSource.java
Modified:
   trunk/testsuite/src/main/org/jboss/test/cluster/web/CacheHelper.java
   trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/AttributeBasedClusteredSession.java
   trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/ClusteredSession.java
   trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossCacheManager.java
   trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossCacheService.java
   trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossCacheWrapper.java
   trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/SessionBasedClusteredSession.java
   trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/SessionSerializationFactory.java
Log:
[JBAS-5448] Move ha-client to 1.1.0.Beta1
[JBAS-5449] Move ha-server-api to 1.1.0.Beta1
[JBAS-4639] Optimized replication of ClusteredSession metadata

Modified: trunk/testsuite/src/main/org/jboss/test/cluster/web/CacheHelper.java
===================================================================
--- trunk/testsuite/src/main/org/jboss/test/cluster/web/CacheHelper.java	2008-05-01 16:35:25 UTC (rev 72945)
+++ trunk/testsuite/src/main/org/jboss/test/cluster/web/CacheHelper.java	2008-05-01 16:36:49 UTC (rev 72946)
@@ -39,6 +39,7 @@
 import org.jboss.ha.framework.server.PojoCacheManagerLocator;
 import org.jboss.mx.util.ObjectNameFactory;
 import org.jboss.system.ServiceMBeanSupport;
+import org.jboss.web.tomcat.service.session.JBossCacheService;
 
 /**
  * Helper class to locate and invoke methods on the cache mbeans used by JBossWeb.
@@ -58,7 +59,7 @@
    public static final ObjectName OBJECT_NAME = 
       ObjectNameFactory.create("jboss.test:service=WebTestCacheHelper");
    
-   private static final String VERSION_KEY = "VERSION";   
+   private static final String VERSION_KEY = JBossCacheService.VERSION_KEY;   
    
    private String cacheConfigName;
    private Cache cache;

Modified: trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/AttributeBasedClusteredSession.java
===================================================================
--- trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/AttributeBasedClusteredSession.java	2008-05-01 16:35:25 UTC (rev 72945)
+++ trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/AttributeBasedClusteredSession.java	2008-05-01 16:36:49 UTC (rev 72946)
@@ -26,7 +26,6 @@
 import java.util.Iterator;
 import java.util.Map;
 import java.util.Set;
-import java.util.Map.Entry;
 
 /**
  * Implementation of a clustered session for the JBossCacheManager. The replication granularity
@@ -62,7 +61,7 @@
    protected static final String info = "AttributeBasedClusteredSession/1.0";
 
    // Transient map to store attr changes for replication.
-   private transient Map attrModifiedMap_ = new HashMap();
+   private transient Map<Object, Object> attrModifiedMap_ = new HashMap<Object, Object>();
    // Note that the removed attr is intentionally stored in a map 
    // instead of a Set so it is faster to lookup and remove.
    private transient Map attrRemovedMap_ = new HashMap();
@@ -126,15 +125,14 @@
 
       // Go thru the attribute change list
       
-      if (getSessionAttributesDirty())
+      if (isSessionAttributeMapDirty())
       {
          // Go thru the modified attr list first
          int modCount = attrModifiedMap_.size();
          if (modCount == 1)
          {
-            for (Iterator it = attrModifiedMap_.entrySet().iterator(); it.hasNext(); )
+            for (Map.Entry entry : attrModifiedMap_.entrySet())
             {
-               Map.Entry entry = (Entry) it.next();
                proxy_.putAttribute(realId, (String) entry.getKey(), entry.getValue());
             }
          }

Modified: trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/ClusteredSession.java
===================================================================
--- trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/ClusteredSession.java	2008-05-01 16:35:25 UTC (rev 72945)
+++ trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/ClusteredSession.java	2008-05-01 16:36:49 UTC (rev 72946)
@@ -97,14 +97,6 @@
    protected ReplicationTrigger invalidationPolicy;
 
    /**
-    * If true, means the local in-memory session data contains
-    * changes that have not been published to the distributed cache.
-    * 
-    * @deprecated not used
-    */
-   protected transient boolean isSessionModifiedSinceLastSave;
-   
-   /**
     * If true, means the local in-memory session data contains metadata
     * changes that have not been published to the distributed cache. 
     */
@@ -116,6 +108,20 @@
     */
    protected transient boolean sessionAttributesDirty;
    
+   /** 
+    * Object wrapping thisAccessedTime. Create once and mutate so
+    * we can store it in JBoss Cache w/o concern that a transaction
+    * rollback will revert the cached ref to an older object.
+    */
+   protected transient SessionTimestamp timestamp = new SessionTimestamp();
+   
+   /** 
+    * Object wrapping other metadata for this session. Create once and mutate so
+    * we can store it in JBoss Cache w/o concern that a transaction
+    * rollback will revert the cached ref to an older object.
+    */
+   protected transient SessionMetadata metadata = new SessionMetadata();
+   
    /**
     * The last version that was passed to {@link #setOutdatedVersion} or
     * <code>0</code> if <code>setIsOutdated(false)</code> was subsequently called.
@@ -213,22 +219,6 @@
    {
       return thisAccessedTime < outdatedTime;
    }
-
-   /**
-    * Marks this session as outdated or up-to-date vis-a-vis the distributed
-    * cache.
-    * 
-    * @param outdated
-    * 
-    * @deprecated use {@link #setOutdatedVersion(int)} and {@link #clearOutdated()}
-    */
-   public void setIsOutdated(boolean outdated)
-   {
-      if (outdated)
-         outdatedTime = System.currentTimeMillis();
-      else
-         clearOutdated();
-   }
    
    public void setOutdatedVersion(int version)
    {
@@ -415,9 +405,9 @@
    
    public boolean getExceedsMaxUnreplicatedInterval()
    {
-      boolean result = false;
+      boolean result = (invalidationPolicy == ReplicationTrigger.ACCESS);
       
-      if (maxUnreplicatedInterval > 0) // -1 means ignore; 0 means expire now
+      if (!result && maxUnreplicatedInterval > 0) // -1 means ignore; 0 means expire now
       {
          result = ((System.currentTimeMillis() - lastReplicated) >= maxUnreplicatedInterval);
       }      
@@ -435,6 +425,29 @@
          maxUnreplicatedInterval = maxInactiveInterval * maxUnreplicatedFactor * 10;
       }
    }
+   
+   public SessionTimestamp getSessionTimestamp()
+   {
+      this.timestamp.timestamp = this.thisAccessedTime;
+      return this.timestamp;
+   }
+   
+   public SessionMetadata getSessionMetadata()
+   {
+      this.metadata.id = id;
+      this.metadata.creationTime = creationTime;
+      this.metadata.maxInactiveInterval = maxInactiveInterval;
+      this.metadata.invalidationPolicy = invalidationPolicy;
+      this.metadata.isNew = isNew;
+      this.metadata.isValid = isValid;
+      
+      return this.metadata;
+   }
+   
+   public Map<String, Object> getSessionAttributeMap()
+   {
+      return null;
+   }
 
    /**
     * This is called after loading a session to initialize the transient values.
@@ -464,18 +477,13 @@
    public void access()
    {
       super.access();
-
+      
       // JBAS-3528. If it's not the first access, make sure
       // the 'new' flag is correct
       if (!firstAccess && isNew)
       {
          setNew(false);
-      }
-
-      if (invalidationPolicy == ReplicationTrigger.ACCESS)
-      {
-         this.sessionMetadataDirty();
-      }
+      }      
    }
    
    
@@ -1238,70 +1246,63 @@
       return excluded;      
    }
    
-   /**
-    * Reads all non-transient state from the ObjectOutput <i>except
-    * the attribute map</i>.  Subclasses that wish the attribute map
-    * to be read should override this method and 
-    * {@link #writeExternal(ObjectOutput) writeExternal()}.
-    * 
-    * <p>
-    * This method is deliberately public so it can be used to reset
-    * the internal state of a session object using serialized
-    * contents replicated from another JVM via JBossCache.
-    * </p>
-    * 
-    * @see java.io.Externalizable#readExternal(java.io.ObjectInput)
-    */
-   protected void update(ClusteredSession replicated) 
+   protected void update(Integer version, SessionTimestamp timestamp, 
+                         SessionMetadata metadata, Map attributes)
    {
-      synchronized (this)
-      {
-         //    From StandardSession
-         id                  = replicated.id;
-         creationTime        = replicated.creationTime;
-         lastAccessedTime    = replicated.lastAccessedTime;
-         maxInactiveInterval = replicated.maxInactiveInterval;
-         isNew               = replicated.isNew;
-         isValid             = replicated.isValid;
-         thisAccessedTime    = replicated.thisAccessedTime;
-         
-         // From ClusteredSession
-         invalidationPolicy  = replicated.invalidationPolicy;
-         version             = replicated.version;
+      assert version != null : "version is null";
+      assert timestamp != null : "timestamp is null";
+      assert metadata != null : "metadata is null";
+      
+      this.version = version.intValue();
+      
+      this.lastAccessedTime = this.thisAccessedTime = timestamp.timestamp;
+      this.timestamp = timestamp;
+      
+      this.id = metadata.id;
+      this.creationTime = metadata.creationTime;
+      this.maxInactiveInterval = metadata.maxInactiveInterval;
+      this.isNew = metadata.isNew;
+      this.isValid = metadata.isValid;
+      this.invalidationPolicy = metadata.invalidationPolicy;
+      this.metadata = metadata;
+      
+      // Get our id without any jvmRoute appended
+      parseRealId(id);
+      
+      // We no longer know if we have an activationListener
+      hasActivationListener = null;
+      
+      // If the session has been replicated, any subsequent
+      // access cannot be the first.
+      this.firstAccess = false;
+      
+      // TODO uncomment when work on JBAS-1900 is completed      
+//      // Session notes -- for FORM auth apps, allow replicated session 
+//      // to be used without requiring a new login
+//      // We use the superclass set/removeNote calls here to bypass
+//      // the custom logic we've added      
+//      String username     = (String) in.readObject();
+//      if (username != null)
+//      {
+//         super.setNote(Constants.SESS_USERNAME_NOTE, username);
+//      }
+//      else
+//      {
+//         super.removeNote(Constants.SESS_USERNAME_NOTE);
+//      }
+//      String password     = (String) in.readObject();
+//      if (password != null)
+//      {
+//         super.setNote(Constants.SESS_PASSWORD_NOTE, password);
+//      }
+//      else
+//      {
+//         super.removeNote(Constants.SESS_PASSWORD_NOTE);
+//      }
+      
+      // we ignore the attributes
+   }   
    
-         // Get our id without any jvmRoute appended
-         parseRealId(id);
-         
-         // We no longer know if we have an activationListener
-         hasActivationListener = null;
-         
-         // TODO uncomment when work on JBAS-1900 is completed      
-//         // Session notes -- for FORM auth apps, allow replicated session 
-//         // to be used without requiring a new login
-//         // We use the superclass set/removeNote calls here to bypass
-//         // the custom logic we've added      
-//         String username     = (String) in.readObject();
-//         if (username != null)
-//         {
-//            super.setNote(Constants.SESS_USERNAME_NOTE, username);
-//         }
-//         else
-//         {
-//            super.removeNote(Constants.SESS_USERNAME_NOTE);
-//         }
-//         String password     = (String) in.readObject();
-//         if (password != null)
-//         {
-//            super.setNote(Constants.SESS_PASSWORD_NOTE, password);
-//         }
-//         else
-//         {
-//            super.removeNote(Constants.SESS_PASSWORD_NOTE);
-//         }
-      }
-   }
-   
-   
    // -------------------------------------- Internal protected method override
 
    /**
@@ -1318,6 +1319,7 @@
     * @param name      the attribute name 
     * @param notify    <code>true</code> if listeners should be notified
     */
+   @Override
    protected void removeAttributeInternal(String name, boolean notify)
    {
       boolean localCall = true;
@@ -1459,16 +1461,11 @@
    protected void sessionAttributesDirty()
    {
       if (!sessionAttributesDirty && log.isTraceEnabled())
-         log.trace("Marking session attributes dirty" + id);
+         log.trace("Marking session attributes dirty " + id);
       
       sessionAttributesDirty = true;
    }
    
-   protected boolean getSessionAttributesDirty()
-   {
-      return sessionAttributesDirty;
-   }
-   
    protected void sessionMetadataDirty()
    {
       if (!sessionMetadataDirty && !isNew && log.isTraceEnabled())
@@ -1476,31 +1473,19 @@
       sessionMetadataDirty = true;
    }
    
-   protected boolean getSessionMetadataDirty()
+   public boolean isSessionMetadataDirty()
    {
       return sessionMetadataDirty;
    }
-   
-   /**
-    * Calls {@link #sessionAttributesDirty()} and 
-    * {@link #sessionMetadataDirty()}.
-    *
-    * @deprecated use one of the more fine-grained methods.
-    */
-   protected void sessionDirty()
-   {
-      sessionAttributesDirty();
-      sessionMetadataDirty();
-   }
 
    public boolean isSessionDirty()
    {
       return sessionAttributesDirty || sessionMetadataDirty;
    }
    
-   public boolean getReplicateSessionBody()
+   public boolean isSessionAttributeMapDirty()
    {
-      return sessionMetadataDirty || getExceedsMaxUnreplicatedInterval();
+      return sessionAttributesDirty;
    }
 
    protected boolean isGetDirty(Object attribute)
@@ -1528,5 +1513,40 @@
                   attribute instanceof Character ||
                   attribute instanceof Boolean);
    }
+   
+   /**
+    * Encapsulates the "thisAccessedTime" timestamp. The wrapped timestamp long
+    * can be mutated, allowing the same object to always be stored in 
+    * JBoss Cache. Always storing the same object avoids an earlier, no
+    * longer accurate, object being reverted into the cache during a 
+    * transaction rollback.
+    */
+   public static class SessionTimestamp implements Serializable
+   {
+      /** The serialVersionUID */
+      private static final long serialVersionUID = 2317131983552715467L;
+      
+      public long timestamp = 0L;
+   }
+   
+   /**
+    * Encapsulates the replicated metadata for a session. The wrapped data
+    * can be mutated, allowing the same object to always be stored in 
+    * JBoss Cache. Always storing the same object avoids an earlier, no
+    * longer accurate, object being reverted into the cache during a 
+    * transaction rollback.
+    */   
+   public static class SessionMetadata implements Serializable
+   {
+    /** The serialVersionUID */
+      private static final long serialVersionUID = -6845914023373746866L;
+      
+      public String id;
+      public long creationTime;
+      public int maxInactiveInterval;
+      public boolean isNew;
+      public boolean isValid;
+      public ReplicationTrigger invalidationPolicy;      
+   }
 
 }

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-05-01 16:35:25 UTC (rev 72945)
+++ trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossCacheManager.java	2008-05-01 16:36:49 UTC (rev 72946)
@@ -958,12 +958,13 @@
    // createEmptyClusteredSession to avoid a cast
    public Session createEmptySession()
    {
+      log_.trace("Creating an empty ClusteredSession");
+      
       return createEmptyClusteredSession();
    }
 
    private ClusteredSession createEmptyClusteredSession()
-   {
-      log_.trace("Creating an empty ClusteredSession");      
+   {     
 
       ClusteredSession session = null;
       switch (replicationGranularity_)

Modified: trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossCacheService.java
===================================================================
--- trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossCacheService.java	2008-05-01 16:35:25 UTC (rev 72945)
+++ trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossCacheService.java	2008-05-01 16:36:49 UTC (rev 72946)
@@ -21,10 +21,8 @@
 */
 package org.jboss.web.tomcat.service.session;
 
-import java.io.ByteArrayOutputStream;
 import java.io.IOException;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
+import java.io.Serializable;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.Map;
@@ -44,9 +42,12 @@
 import org.jboss.cache.config.CacheLoaderConfig;
 import org.jboss.cache.pojo.impl.InternalConstant;
 import org.jboss.cache.transaction.BatchModeTransactionManager;
-import org.jboss.invocation.MarshalledValue;
+import org.jboss.ha.framework.interfaces.CachableMarshalledValue;
+import org.jboss.ha.framework.server.MarshalledValueHelper;
+import org.jboss.ha.framework.server.SimpleCachableMarshalledValue;
 import org.jboss.logging.Logger;
-import org.jboss.serial.io.MarshalledObject;
+import org.jboss.web.tomcat.service.session.ClusteredSession.SessionMetadata;
+import org.jboss.web.tomcat.service.session.ClusteredSession.SessionTimestamp;
 
 /**
  * A wrapper class to JBossCache. This is currently needed to handle various operations such as
@@ -66,7 +67,11 @@
    public static final String SESSION = "JSESSION";
    public static final String ATTRIBUTE = "ATTRIBUTE";
    // Needed for cache invalidation
-   static final String VERSION_KEY = "VERSION";
+   public static final String VERSION_KEY = "V";
+   public static final String TIMESTAMP_KEY = "T";
+   public static final String METADATA_KEY = "M";
+   public static final String ATTRIBUTE_KEY = "A";
+      
    static final String FQN_DELIMITER = "/";
    
    private Cache plainCache_;
@@ -264,83 +269,53 @@
    public ClusteredSession loadSession(String realId, ClusteredSession toLoad)
    {
       Fqn fqn = getSessionFqn(realId);
-      Object sessionData =  cacheWrapper_.get(fqn, realId, true);
+      Map sessionData =  cacheWrapper_.getData(fqn, true);
       
       if (sessionData == null) {
          // Requested session is no longer in the cache; return null
          return null;
       }
       
-      boolean firstLoad = (toLoad.getVersion() == 0);
+      Integer version = (Integer) sessionData.get(VERSION_KEY);
+      SessionTimestamp timestamp = (SessionTimestamp) sessionData.get(TIMESTAMP_KEY);
+      SessionMetadata metadata = (SessionMetadata) sessionData.get(METADATA_KEY);
+      Map attrs = (Map) getUnMarshalledValue(sessionData.get(ATTRIBUTE_KEY));
+      toLoad.update(version, timestamp, metadata, attrs);
       
-//    if (useTreeCacheMarshalling_)
-//    {
-//       toLoad.update((ClusteredSession) sessionData);
-//    }
-//    else
-//    {
-      byte[] sessionBytes = (byte[]) sessionData;
-       
-      // Swap in/out the webapp classloader so we can deserialize
-      // attributes whose classes are only available to the webapp
-      ClassLoader prevTCL = Thread.currentThread().getContextClassLoader();
-      Thread.currentThread().setContextClassLoader(manager_.getWebappClassLoader());
-      try
-      {
-         // JBAS-2921 - replaced MarshalledValue calls with SessionSerializationFactory calls
-         // ByteArrayInputStream bais = new ByteArrayInputStream(sessionBytes);
-         // Use MarshalledValueInputStream instead of superclass ObjectInputStream
-         // or else there are problems finding classes with scoped loaders
-         // MarshalledValueInputStream input = new MarshalledValueInputStream(bais);
-         ObjectInputStream input = SessionSerializationFactory.createObjectInputStream(sessionBytes);
-         toLoad.readExternal(input);
-         input.close();
-      }
-      catch (Exception e)
-      {
-         log_.error("loadSession(): id: " + realId + " exception occurred during deserialization", e);
-         return null;
-      }
-      finally {
-         Thread.currentThread().setContextClassLoader(prevTCL);
-      }
-//    }
-      
-      // The internal version of the serialized session may be less than the
-      // real one due to not replicating metadata.  If our listener hasn't 
-      // been keeping the outdatedVersion of the session up to date because
-      // the session has never been loaded into the JBCManager cache, we 
-      // need to fix the version
-      if (firstLoad)
-      {         
-         Integer ver = (Integer) cacheWrapper_.get(fqn, VERSION_KEY);
-         if (ver != null)
-            toLoad.setVersion(ver.intValue());
-      }
-      
       return toLoad;
    }
 
    public void putSession(String realId, ClusteredSession session)
-   {
-      Fqn fqn = getSessionFqn(realId);
-      
-      if (session.getReplicateSessionBody())
+   { 
+      if (log_.isTraceEnabled())
       {
-         Map map = new HashMap();
-//       if (useTreeCacheMarshalling_)
-//          map.put(realId, session);
-//       else
-         map.put(realId, externalizeSession(session));
-         // Put in (VERSION_KEY, version) after the real put for cache invalidation
-         map.put(VERSION_KEY, new Integer(session.getVersion()));
-         cacheWrapper_.put(fqn, map);
+         log_.trace("putSession(): putting session " + session.getIdInternal());
+      }     
+      
+      Map map = new HashMap();
+      map.put(VERSION_KEY, new Integer(session.getVersion()));
+      map.put(TIMESTAMP_KEY, session.getSessionTimestamp());
+      
+      if (session.isSessionMetadataDirty())
+      {   
+         map.put(METADATA_KEY, session.getSessionMetadata());         
       }
-      else
+     
+      if (session.isSessionAttributeMapDirty())
       {
-         // Invalidate the remote caches
-         cacheWrapper_.put(fqn, VERSION_KEY, new Integer(session.getVersion()));
+         Map attrs = session.getSessionAttributeMap();
+         // May be null if the session type doesn't use this mechanism to store
+         // attributes (i.e. isn't SessionBasedClusteredSession)
+         if (attrs != null)
+         {
+//            if (useTreeCacheMarshalling_)
+//               map.put(ATTRIBUTE_KEY, attrs);
+//            else
+            map.put(ATTRIBUTE_KEY, getMarshalledValue(attrs));
+         }
       }
+      
+      cacheWrapper_.put(getSessionFqn(realId), map);
    }
 
    public void removeSession(String realId)
@@ -630,42 +605,31 @@
 //      }
 //      else
 //      {
-         try
+         
+         // JBAS-2921 - replaced MarshalledValue calls with SessionSerializationFactory calls
+         // to allow for switching between JBossSerialization and JavaSerialization using
+         // system property -D=session.serialization.jboss=true / false
+         // MarshalledValue mv = new MarshalledValue(value);
+         if  (MarshalledValueHelper.isTypeExcluded(value.getClass()))
          {
-            // JBAS-2921 - replaced MarshalledValue calls with SessionSerializationFactory calls
-            // to allow for switching between JBossSerialization and JavaSerialization using
-            // system property -D=session.serialization.jboss=true / false
-            // MarshalledValue mv = new MarshalledValue(value);
-            if  (SessionSerializationFactory.useJBossSerialization())
+            return value;               
+         }
+         else 
+         {
+            try
             {
-               MarshalledObject mo = SessionSerializationFactory.createMarshalledObject(value);
-               if (log_.isTraceEnabled())
-               {
-                  log_.trace("JBoss Marshalled Object to size ");
-               }
-               return mo;
-               
+               CachableMarshalledValue mv = SessionSerializationFactory.createMarshalledValue((Serializable) value);
+               return mv;
             }
-            else 
+            catch (ClassCastException e)
             {
-               MarshalledValue mv = SessionSerializationFactory.createMarshalledValue(value);
-               if (log_.isTraceEnabled())
-               {
-                  log_.trace("marshalled object to size " + mv.size() + " bytes");
-               }
-               return mv; 
+               throw new IllegalArgumentException(value + " does not implement java.io.Serializable");
             }
-            
          }
-         catch (IOException e)
-         {
-            log_.error("IOException occurred marshalling value ", e);
-            return null;
-         }
 //      }
    }
 
-   private Object getUnMarshalledValue(Object mv)
+   private Object getUnMarshalledValue(Object obj)
    {
       // JBAS-2920.  For now, continue using MarshalledValue, as 
       // it allows lazy deserialization of the attribute on remote nodes
@@ -677,24 +641,17 @@
 //      }
 //      else
 //      {
-         if (mv == null) return null;
+         if (!(obj instanceof SimpleCachableMarshalledValue))
+            return obj;
+         
          // Swap in/out the tcl for this web app. Needed only for un marshalling.
          ClassLoader prevTCL = Thread.currentThread().getContextClassLoader();
          Thread.currentThread().setContextClassLoader(manager_.getWebappClassLoader());
          try
          {
-            // JBAS-2921 - replaced MarshalledValue calls with SessionSerializationFactory calls
-            // to allow for switching between JBossSerialization and JavaSerialization using
-            // system property -D=session.serialization.jboss=true / false
-
-            if (SessionSerializationFactory.useJBossSerialization())
-            {
-               return ((MarshalledObject)mv).get();
-            }
-            else 
-            {
-               return ((MarshalledValue) mv).get();
-            }
+            SimpleCachableMarshalledValue mv = (SimpleCachableMarshalledValue) obj;
+            mv.setObjectStreamSource(SessionSerializationFactory.getObjectStreamSource());
+            return mv.get();
          }
          catch (IOException e)
          {
@@ -713,40 +670,4 @@
 //      }
    }
 
-   private byte[] externalizeSession(ClusteredSession session)
-   {
-      try
-      {
-         // Write the contents of session to a byte array and store that
-         ByteArrayOutputStream baos = new ByteArrayOutputStream();
-         // Use MarshalledValueOutputStream instead of superclass ObjectOutputStream
-         // or else there are problems finding classes with scoped loaders
-         
-         // JBAS-2921 - replaced MarshalledValue calls with SessionSerializationFactory calls
-         // to allow for switching between JBossSerialization and JavaSerialization using
-         // system property -D=session.serialization.jboss=true / false
-         
-         // MarshalledValueOutputStream oos = new MarshalledValueOutputStream(baos);
-         
-         ObjectOutputStream oos = SessionSerializationFactory.createObjectOutputStream(baos);
-         session.writeExternal(oos);
-         oos.close(); // flushes bytes to baos
-         
-         byte[] bytes = baos.toByteArray();
-         
-         if (log_.isTraceEnabled())
-         {
-            log_.trace("Serialized Object to size " + bytes.length + " bytes");
-         }
-
-         return bytes;
-      }
-      catch (Exception e)
-      {
-         log_.error("externalizeSession(): exception occurred externalizing session " + session, e);
-         return null;
-      }
-      
-   }
-
 }

Modified: trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossCacheWrapper.java
===================================================================
--- trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossCacheWrapper.java	2008-05-01 16:35:25 UTC (rev 72945)
+++ trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossCacheWrapper.java	2008-05-01 16:36:49 UTC (rev 72946)
@@ -42,6 +42,28 @@
    {
       plainCache_ = cache;
    }
+   
+   Map getData(Fqn fqn, boolean gravitate)
+   {
+      TimeoutException ex = null;
+      for (int i = 0; i < RETRY; i++)
+      {
+         try
+         {            
+            if (gravitate)
+            {            
+               plainCache_.getInvocationContext().getOptionOverrides()
+                                                 .setForceDataGravitation(true);
+            }
+            return plainCache_.getData(fqn);
+         }
+         catch (TimeoutException e)
+         {
+            ex = e;
+         }
+      }      
+      throw new RuntimeException(RETRY_FAIL_MSG, ex);      
+   }
 
    /**
     * Wrapper to embed retry logic.
@@ -69,18 +91,12 @@
       {
          try
          {            
-            Object value = null;            
             if (gravitate)
             {            
                plainCache_.getInvocationContext().getOptionOverrides()
                                                  .setForceDataGravitation(true);
-               value = plainCache_.get(fqn, id);
             }
-            else
-            {
-               value = plainCache_.get(fqn, id);
-            }
-            return value;
+            return plainCache_.get(fqn, id);
          }
          catch (TimeoutException e)
          {

Added: trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossSerializationObjectStreamSource.java
===================================================================
--- trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossSerializationObjectStreamSource.java	                        (rev 0)
+++ trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossSerializationObjectStreamSource.java	2008-05-01 16:36:49 UTC (rev 72946)
@@ -0,0 +1,54 @@
+/*
+ * 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.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.io.OutputStream;
+
+import org.jboss.ha.framework.interfaces.ObjectStreamSource;
+import org.jboss.serial.io.JBossObjectInputStreamSharedTree;
+import org.jboss.serial.io.JBossObjectOutputStreamSharedTree;
+
+/**
+ * {@link ObjectStreamSource} implementation that provides 
+ * {@link JBossObjectInputStreamSharedTree} and {@link JBossObjectOutputStreamSharedTree}.
+ * 
+ * @author Brian Stansberry
+ */
+public class JBossSerializationObjectStreamSource implements ObjectStreamSource
+{
+
+   public ObjectInput getObjectInput(InputStream input) throws IOException
+   {
+      return new JBossObjectInputStreamSharedTree(input);
+   }
+
+   public ObjectOutput getObjectOutput(OutputStream output) throws IOException
+   {
+      return new JBossObjectOutputStreamSharedTree(output);
+   }
+
+}

Modified: trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/SessionBasedClusteredSession.java
===================================================================
--- trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/SessionBasedClusteredSession.java	2008-05-01 16:35:25 UTC (rev 72945)
+++ trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/SessionBasedClusteredSession.java	2008-05-01 16:36:49 UTC (rev 72946)
@@ -24,6 +24,7 @@
 import java.io.IOException;
 import java.io.ObjectInput;
 import java.io.ObjectOutput;
+import java.util.HashMap;
 import java.util.Map;
 
 
@@ -133,6 +134,14 @@
       return attributes.put(name, value);
    }
 
+   @Override
+   public Map<String, Object> getSessionAttributeMap()
+   {
+      Map attrs = new HashMap(attributes);
+      removeExcludedAttributes(attrs);
+      return attrs;
+   }
+
    /**
     * Overrides the superclass version by additionally reading the 
     * attributes map.
@@ -149,6 +158,10 @@
    {
       synchronized (this)
       {
+         
+         // If the session has been replicated, any subsequent
+         // access cannot be the first.
+         this.firstAccess = false;
          // Let superclass read in everything but the attribute map
          super.readExternal(in);
       
@@ -178,27 +191,25 @@
          // Restore any excluded attributes
          if (excluded != null)
             attributes.putAll(excluded);
-      }   
-   
+      }      
    }
 
-   protected void update(ClusteredSession replicated)
+   protected void update(Integer version, SessionTimestamp timestamp, 
+         SessionMetadata metadata, Map updatedAttrs)
    {
-      SessionBasedClusteredSession other = (SessionBasedClusteredSession) replicated;
+      // A new session may not have sent over any attributes
+      if (updatedAttrs == null)
+      {
+         updatedAttrs = new HashMap();
+      }
+
+      super.update(version, timestamp, metadata, updatedAttrs);
       
-      super.update(other);
+      Map excluded = removeExcludedAttributes(attributes);
+      if (excluded != null)
+         updatedAttrs.putAll(excluded);
       
-      attributes = other.attributes;
+      this.attributes = updatedAttrs;
    }
-   
 
-   /**
-    * Overrides the superclass version to return <code>true</code> if either
-    * the metadata or the attributes are dirty.
-    */
-   public boolean getReplicateSessionBody()
-   {
-      return isSessionDirty() || getExceedsMaxUnreplicatedInterval();
-   }
-
 }

Modified: trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/SessionSerializationFactory.java
===================================================================
--- trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/SessionSerializationFactory.java	2008-05-01 16:35:25 UTC (rev 72945)
+++ trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/SessionSerializationFactory.java	2008-05-01 16:36:49 UTC (rev 72946)
@@ -21,20 +21,13 @@
 */
 package org.jboss.web.tomcat.service.session;
 
-import org.jboss.invocation.MarshalledValueInputStream;
-import org.jboss.invocation.MarshalledValueOutputStream;
-import org.jboss.invocation.MarshalledValue;
+import java.io.Serializable;
+
+import org.jboss.ha.framework.interfaces.ObjectStreamSource;
+import org.jboss.ha.framework.server.MarshalledValueObjectStreamSource;
+import org.jboss.ha.framework.server.SimpleCachableMarshalledValue;
 import org.jboss.logging.Logger;
-import org.jboss.serial.io.JBossObjectInputStreamSharedTree;
-import org.jboss.serial.io.JBossObjectOutputStreamSharedTree;
-import org.jboss.serial.io.MarshalledObject;
 
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
-import java.io.OutputStream;
-
 /**
  * Factory class for creating object output and input streams, 
  * switching between JDK Serialization and JBoss Serialization classes. 
@@ -44,16 +37,25 @@
  *  
  * 
  * @author <a href="hmesha at novell.com">Hany Mesha</a>
+ * @author Brian Stansberry
  */
 public class SessionSerializationFactory
 {
-   static Logger log_ = Logger.getLogger(SessionSerializationFactory.class);
-   static boolean useJBossSerialization = false;
+   /** 
+    * System property that, if set to <code>true</code>, indicates that 
+    * JBoss Serialization should be used for session serialization.
+    */
+   public static final String JBOSS_SERIALIZATION_SYS_PROP = "session.serialization.jboss";
+   private static Logger log_ = Logger.getLogger(SessionSerializationFactory.class);
+   private static boolean useJBossSerialization = false;
+   private static ObjectStreamSource objectStreamSource; 
 
    static
    {
-       String useJBossSerializationStr = System.getProperty("session.serialization.jboss", "false");
+       String useJBossSerializationStr = System.getProperty(JBOSS_SERIALIZATION_SYS_PROP, "false");
        useJBossSerialization = Boolean.valueOf(useJBossSerializationStr).booleanValue();
+       objectStreamSource = useJBossSerialization ? new JBossSerializationObjectStreamSource()
+                                                  : new MarshalledValueObjectStreamSource(); 
        try
        {
           if (useJBossSerialization)
@@ -66,26 +68,15 @@
           // we don't fail a static initializer due to a debug log stmt
        }
    }
-
-   public static ObjectOutputStream createObjectOutputStream(OutputStream out) throws IOException
-   {
-      return useJBossSerialization ? new JBossObjectOutputStreamSharedTree(out) : new MarshalledValueOutputStream(out);
-   }
-
-   public static ObjectInputStream createObjectInputStream(byte[] bytes) throws IOException
-   {
-      ByteArrayInputStream in = new ByteArrayInputStream(bytes);
-      return useJBossSerialization ? new JBossObjectInputStreamSharedTree(in) : new MarshalledValueInputStream(in);
-   }
    
-   public static MarshalledValue createMarshalledValue(Object o) throws IOException
+   public static SimpleCachableMarshalledValue createMarshalledValue(Serializable o)
    {
-      return new MarshalledValue (o);
+      return new SimpleCachableMarshalledValue(o, objectStreamSource);
    }
    
-   public static MarshalledObject createMarshalledObject(Object o) throws IOException
+   public static ObjectStreamSource getObjectStreamSource()
    {
-      return new MarshalledObject(o);
+      return objectStreamSource;
    }
 
    public static boolean useJBossSerialization()




More information about the jboss-cvs-commits mailing list