[jboss-cvs] JBossAS SVN: r78731 - branches/Branch_4_2/tomcat/src/main/org/jboss/web/tomcat/service/session.

jboss-cvs-commits at lists.jboss.org jboss-cvs-commits at lists.jboss.org
Sat Sep 20 17:50:49 EDT 2008


Author: bstansberry at jboss.com
Date: 2008-09-20 17:50:48 -0400 (Sat, 20 Sep 2008)
New Revision: 78731

Modified:
   branches/Branch_4_2/tomcat/src/main/org/jboss/web/tomcat/service/session/ClusteredSession.java
   branches/Branch_4_2/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossCacheClusteredSession.java
   branches/Branch_4_2/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossCacheManager.java
Log:
[JBAS-5778] Add pluggable policy for deciding whether to emit servlet spec notifications around events affecting clustered sessions

Modified: branches/Branch_4_2/tomcat/src/main/org/jboss/web/tomcat/service/session/ClusteredSession.java
===================================================================
--- branches/Branch_4_2/tomcat/src/main/org/jboss/web/tomcat/service/session/ClusteredSession.java	2008-09-20 21:50:34 UTC (rev 78730)
+++ branches/Branch_4_2/tomcat/src/main/org/jboss/web/tomcat/service/session/ClusteredSession.java	2008-09-20 21:50:48 UTC (rev 78731)
@@ -50,6 +50,10 @@
 import org.apache.catalina.util.StringManager;
 import org.jboss.logging.Logger;
 import org.jboss.metadata.WebMetaData;
+import org.jboss.web.tomcat.service.session.notification.ClusteredSessionManagementStatus;
+import org.jboss.web.tomcat.service.session.notification.ClusteredSessionNotificationCause;
+import org.jboss.web.tomcat.service.session.notification.ClusteredSessionNotificationPolicy;
+import org.jboss.web.tomcat.service.session.notification.LegacyClusteredSessionNotificationPolicy;
 
 /**
  * Abstract base class for session clustering based on StandardSession. Different session
@@ -175,6 +179,13 @@
     * Has this session only been accessed once?
     */
    protected transient boolean firstAccess;
+   
+   /**
+    * Policy that drives whether we issue servlet spec notifications.
+    */
+   protected transient ClusteredSessionNotificationPolicy notificationPolicy;
+   
+   protected transient ClusteredSessionManagementStatus clusterStatus;
 
    /**
     * The string manager for this package.
@@ -200,6 +211,7 @@
       invalidationPolicy = manager.getInvalidateSessionPolicy();
       this.useJK = useJK;
       this.firstAccess = true;
+      this.notificationPolicy = new LegacyClusteredSessionNotificationPolicy();
       checkAlwaysReplicateMetadata();
    }
 
@@ -555,11 +567,14 @@
          throw new IllegalArgumentException
             (sm.getString("clusteredSession.setAttribute.iae"));
 
+      ClusteredSessionNotificationPolicy policy = getNotificationPolicy();
+      
       // Construct an event with the new value
       HttpSessionBindingEvent event = null;
 
       // Call the valueBound() method if necessary
-      if (value instanceof HttpSessionBindingListener)
+      if (value instanceof HttpSessionBindingListener
+            && policy.isHttpSessionBindingListenerInvocationAllowed(this.clusterStatus, ClusteredSessionNotificationCause.MODIFY, name, true))
       {
          event = new HttpSessionBindingEvent(getSession(), name, value);
          try
@@ -577,7 +592,8 @@
 
       // Call the valueUnbound() method if necessary
       if ((unbound != null) && (unbound != value) &&
-         (unbound instanceof HttpSessionBindingListener))
+         (unbound instanceof HttpSessionBindingListener) &&
+         policy.isHttpSessionBindingListenerInvocationAllowed(this.clusterStatus, ClusteredSessionNotificationCause.MODIFY, name, true))
       {
          try
          {
@@ -591,71 +607,74 @@
       }
 
       // Notify interested application event listeners
-      Context context = (Context) manager.getContainer();
-      Object listeners[] = context.getApplicationEventListeners();
-      if (listeners == null)
-         return;
-      for (int i = 0; i < listeners.length; i++)
+      if (policy.isHttpSessionAttributeListenerInvocationAllowed(this.clusterStatus, ClusteredSessionNotificationCause.MODIFY, name, true))
       {
-         if (!(listeners[i] instanceof HttpSessionAttributeListener))
-            continue;
-         HttpSessionAttributeListener listener =
-            (HttpSessionAttributeListener) listeners[i];
-         try
+         Context context = (Context) manager.getContainer();
+         Object lifecycleListeners[] = context.getApplicationEventListeners();
+         if (lifecycleListeners == null)
+            return;
+         for (int i = 0; i < lifecycleListeners.length; i++)
          {
-            if (unbound != null)
-            {
-               fireContainerEvent(context,
-                  "beforeSessionAttributeReplaced",
-                  listener);
-               if (event == null)
-               {
-                  event = new HttpSessionBindingEvent
-                     (getSession(), name, unbound);
-               }
-               listener.attributeReplaced(event);
-               fireContainerEvent(context,
-                  "afterSessionAttributeReplaced",
-                  listener);
-            }
-            else
-            {
-               fireContainerEvent(context,
-                  "beforeSessionAttributeAdded",
-                  listener);
-               if (event == null)
-               {
-                  event = new HttpSessionBindingEvent
-                     (getSession(), name, value);
-               }
-               listener.attributeAdded(event);
-               fireContainerEvent(context,
-                  "afterSessionAttributeAdded",
-                  listener);
-            }
-         }
-         catch (Throwable t)
-         {
+            if (!(lifecycleListeners[i] instanceof HttpSessionAttributeListener))
+               continue;
+            HttpSessionAttributeListener listener =
+               (HttpSessionAttributeListener) lifecycleListeners[i];
             try
             {
                if (unbound != null)
                {
                   fireContainerEvent(context,
+                     "beforeSessionAttributeReplaced",
+                     listener);
+                  if (event == null)
+                  {
+                     event = new HttpSessionBindingEvent
+                        (getSession(), name, unbound);
+                  }
+                  listener.attributeReplaced(event);
+                  fireContainerEvent(context,
                      "afterSessionAttributeReplaced",
                      listener);
                }
                else
                {
                   fireContainerEvent(context,
+                     "beforeSessionAttributeAdded",
+                     listener);
+                  if (event == null)
+                  {
+                     event = new HttpSessionBindingEvent
+                        (getSession(), name, value);
+                  }
+                  listener.attributeAdded(event);
+                  fireContainerEvent(context,
                      "afterSessionAttributeAdded",
                      listener);
                }
             }
-            catch (Exception e)
+            catch (Throwable t)
             {
-               ;
+               try
+               {
+                  if (unbound != null)
+                  {
+                     fireContainerEvent(context,
+                        "afterSessionAttributeReplaced",
+                        listener);
+                  }
+                  else
+                  {
+                     fireContainerEvent(context,
+                        "afterSessionAttributeAdded",
+                        listener);
+                  }
+               }
+               catch (Exception e)
+               {
+                  ;
+               }
+               manager.getContainer().getLogger().error(sm.getString("standardSession.attributeEvent"), t);
             }
-            manager.getContainer().getLogger().error(sm.getString("standardSession.attributeEvent"), t);
          }
       }
    }
@@ -692,7 +711,7 @@
       boolean notify = true;
       boolean localCall = true;
       boolean localOnly = false;
-      expire(notify, localCall, localOnly);
+      expire(notify, localCall, localOnly, ClusteredSessionNotificationCause.INVALIDATE);
    }
     
     
@@ -757,7 +776,7 @@
    {
       boolean localCall = true;
       boolean localOnly = true;
-      expire(notify, localCall, localOnly);
+      expire(notify, localCall, localOnly, ClusteredSessionNotificationCause.TIMEOUT);
    }
 
    /**
@@ -782,8 +801,9 @@
     *                   cluster nodes should be made aware of the expiration.
     *                   Only meaningful if <code>localCall</code> is
     *                   <code>true</code>.
+    * @param cause the cause of the expiration
     */
-   public void expire(boolean notify, boolean localCall, boolean localOnly)
+   public void expire(boolean notify, boolean localCall, boolean localOnly, ClusteredSessionNotificationCause cause)
    {
       if (log.isDebugEnabled())
       {
@@ -810,18 +830,20 @@
          // Notify interested application event listeners
          // FIXME - Assumes we call listeners in reverse order
          Context context = (Context) manager.getContainer();
-         Object listeners[] = context.getApplicationLifecycleListeners();
-         if (notify && (listeners != null))
+         Object lifecycleListeners[] = context.getApplicationLifecycleListeners();
+         if (notify 
+               && (lifecycleListeners != null) 
+               && getNotificationPolicy().isHttpSessionListenerInvocationAllowed(this.clusterStatus, cause, localCall))
          {
             HttpSessionEvent event =
                new HttpSessionEvent(getSession());
-            for (int i = 0; i < listeners.length; i++)
+            for (int i = 0; i < lifecycleListeners.length; i++)
             {
-               int j = (listeners.length - 1) - i;
-               if (!(listeners[j] instanceof HttpSessionListener))
+               int j = (lifecycleListeners.length - 1) - i;
+               if (!(lifecycleListeners[j] instanceof HttpSessionListener))
                   continue;
                HttpSessionListener listener =
-                  (HttpSessionListener) listeners[j];
+                  (HttpSessionListener) lifecycleListeners[j];
                try
                {
                   fireContainerEvent(context,
@@ -848,6 +870,7 @@
                }
             }
          }
+         
          if (ACTIVITY_CHECK) {
              accessCount.set(0);
          }
@@ -861,7 +884,7 @@
          // JBAS-1360 -- Unbind any objects associated with this session
          String keys[] = keys();
          for (int i = 0; i < keys.length; i++)
-             removeAttributeInternal(keys[i], localCall, localOnly, notify);
+             removeAttributeInternal(keys[i], localCall, localOnly, notify, cause);
 
          // Remove this session from our manager's active sessions
          removeFromManager(localCall, localOnly);
@@ -1034,6 +1057,8 @@
       lastReplicated = 0;
       maxUnreplicatedInterval = 0;
       this.alwaysReplicateMetadata = true;
+      this.notificationPolicy = null;
+      this.clusterStatus = null;
    }
    
    /**
@@ -1057,7 +1082,20 @@
       // Parse the real id first, as super.setId() calls add(),
       // which depends on having the real id
       parseRealId(id);
-      super.setId(id);
+      
+      // TODO -- should we bypass this if realId hasn't changed? We're removing
+      // and readding every time we fail over, when all we want is a 
+      // jvmRoute change to the session id
+      
+      if ((this.id != null) && (manager != null))
+          manager.remove(this);
+
+      this.id = id;
+      
+      this.clusterStatus = new ClusteredSessionManagementStatus(this.realId, true, null, null);
+
+      if (manager != null)
+          manager.add(this);
    }
 
    /**
@@ -1099,6 +1137,53 @@
       sessionMetadataDirty();
    }
 
+   @Override
+   public void tellNew() 
+   {
+      tellNew(ClusteredSessionNotificationCause.CREATE);
+   }
+
+   public void tellNew(ClusteredSessionNotificationCause cause)
+   {
+      // Notify interested session event listeners
+      fireSessionEvent(Session.SESSION_CREATED_EVENT, null);
+
+      // Notify interested application event listeners
+      if (getNotificationPolicy().isHttpSessionListenerInvocationAllowed(this.clusterStatus, cause, true))
+      {
+         Context context = (Context) manager.getContainer();
+         Object lifecycleListeners[] = context.getApplicationLifecycleListeners();
+         if (lifecycleListeners != null)
+         {
+            HttpSessionEvent event = new HttpSessionEvent(getSession());
+            for (int i = 0; i < lifecycleListeners.length; i++)
+            {
+               if (!(lifecycleListeners[i] instanceof HttpSessionListener))
+                  continue;
+               HttpSessionListener listener = (HttpSessionListener) lifecycleListeners[i];
+               try
+               {
+                  fireContainerEvent(context, "beforeSessionCreated", listener);
+                  listener.sessionCreated(event);
+                  fireContainerEvent(context, "afterSessionCreated", listener);
+               }
+               catch (Throwable t)
+               {
+                  try
+                  {
+                     fireContainerEvent(context, "afterSessionCreated", listener);
+                  }
+                  catch (Exception e)
+                  {
+                     ;
+                  }
+                  manager.getContainer().getLogger().error(sm.getString("standardSession.sessionEvent"), t);
+               }
+            }
+         }
+      }
+   }
+
    public String toString()
    {
       StringBuffer buf = new StringBuffer();
@@ -1156,6 +1241,10 @@
          // as a proxy for when replication occurred
          this.lastReplicated = this.thisAccessedTime;
          
+         this.notificationPolicy = new LegacyClusteredSessionNotificationPolicy();
+         
+         this.clusterStatus = new ClusteredSessionManagementStatus(this.realId, true, null, null);
+         
          checkAlwaysReplicateMetadata();
          
          // TODO uncomment when work on JBAS-1900 is completed      
@@ -1257,9 +1346,20 @@
       
       return excluded;      
    }
+
+   protected ClusteredSessionNotificationPolicy getNotificationPolicy()
+   {
+      return notificationPolicy;
+   }
+
+   protected void setNotificationPolicy(ClusteredSessionNotificationPolicy notificationPolicy)
+   {
+      this.notificationPolicy = notificationPolicy;
+   } 
    
+   
    // -------------------------------------- Internal protected method override
-
+   
    /**
     * Method inherited from Tomcat. Return zero-length based string if not found.
     */
@@ -1278,7 +1378,7 @@
    {
       boolean localCall = true;
       boolean localOnly = false;
-      removeAttributeInternal(name, localCall, localOnly, notify);
+      removeAttributeInternal(name, localCall, localOnly, notify, ClusteredSessionNotificationCause.MODIFY);
    }
    
    /**
@@ -1294,11 +1394,13 @@
     * @param localOnly <code>true</code> if the removal should not be
     *                  replicated around the cluster
     * @param notify    <code>true</code> if listeners should be notified
+    * @param cause the cause of the removal
     */
    protected void removeAttributeInternal(String name, 
                                           boolean localCall, 
                                           boolean localOnly,
-                                          boolean notify)
+                                          boolean notify, 
+                                          ClusteredSessionNotificationCause cause)
    {
 
       // Remove this attribute from our collection
@@ -1310,53 +1412,59 @@
          return;
       }
 
+      ClusteredSessionNotificationPolicy policy = getNotificationPolicy();
+      
       // Call the valueUnbound() method if necessary
       HttpSessionBindingEvent event = null;
-      if (value instanceof HttpSessionBindingListener)
+      if (value instanceof HttpSessionBindingListener
+            && policy.isHttpSessionBindingListenerInvocationAllowed(this.clusterStatus, cause, name, localCall))
       {
          event = new HttpSessionBindingEvent(getSession(), name, value);
          ((HttpSessionBindingListener) value).valueUnbound(event);
       }
 
       // Notify interested application event listeners
-      Context context = (Context) manager.getContainer();
-      Object listeners[] = context.getApplicationEventListeners();
-      if (listeners == null)
-         return;
-      for (int i = 0; i < listeners.length; i++)
+      if (policy.isHttpSessionAttributeListenerInvocationAllowed(this.clusterStatus, cause, name, localCall))
       {
-         if (!(listeners[i] instanceof HttpSessionAttributeListener))
-            continue;
-         HttpSessionAttributeListener listener =
-            (HttpSessionAttributeListener) listeners[i];
-         try
+         Context context = (Context) manager.getContainer();
+         Object lifecycleListeners[] = context.getApplicationEventListeners();
+         if (lifecycleListeners == null)
+            return;
+         for (int i = 0; i < lifecycleListeners.length; i++)
          {
-            fireContainerEvent(context,
-               "beforeSessionAttributeRemoved",
-               listener);
-            if (event == null)
-            {
-               event = new HttpSessionBindingEvent
-                  (getSession(), name, value);
-            }
-            listener.attributeRemoved(event);
-            fireContainerEvent(context,
-               "afterSessionAttributeRemoved",
-               listener);
-         }
-         catch (Throwable t)
-         {
+            if (!(lifecycleListeners[i] instanceof HttpSessionAttributeListener))
+               continue;
+            HttpSessionAttributeListener listener =
+               (HttpSessionAttributeListener) lifecycleListeners[i];
             try
             {
                fireContainerEvent(context,
+                  "beforeSessionAttributeRemoved",
+                  listener);
+               if (event == null)
+               {
+                  event = new HttpSessionBindingEvent
+                     (getSession(), name, value);
+               }
+               listener.attributeRemoved(event);
+               fireContainerEvent(context,
                   "afterSessionAttributeRemoved",
                   listener);
             }
-            catch (Exception e)
+            catch (Throwable t)
             {
-               ;
+               try
+               {
+                  fireContainerEvent(context,
+                     "afterSessionAttributeRemoved",
+                     listener);
+               }
+               catch (Exception e)
+               {
+                  ;
+               }
+               manager.getContainer().getLogger().error(sm.getString("standardSession.attributeEvent"), t);
             }
-            manager.getContainer().getLogger().error(sm.getString("standardSession.attributeEvent"), t);
          }
       }
 

Modified: branches/Branch_4_2/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossCacheClusteredSession.java
===================================================================
--- branches/Branch_4_2/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossCacheClusteredSession.java	2008-09-20 21:50:34 UTC (rev 78730)
+++ branches/Branch_4_2/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossCacheClusteredSession.java	2008-09-20 21:50:48 UTC (rev 78731)
@@ -47,6 +47,7 @@
       super(manager, manager.getUseJK());
       int maxUnrep = manager.getMaxUnreplicatedInterval() * 1000;
       setMaxUnreplicatedInterval(maxUnrep);
+      establishNotificationPolicy();
       establishProxy();
    }
 
@@ -58,9 +59,10 @@
     */
    public void initAfterLoad(AbstractJBossManager manager)
    {
-      // Our manager and proxy may have been lost if we were recycled,
+      // Our manager, notification policy and proxy may have been lost if we were replicated,
       // so reestablish them
       setManager(manager);
+      establishNotificationPolicy();
       establishProxy();
 
       // Since attribute map may be transient, we may need to populate it 
@@ -158,4 +160,8 @@
                                                           boolean localCall, 
                                                           boolean localOnly);
 
+   protected void establishNotificationPolicy()
+   {
+      setNotificationPolicy(((JBossCacheManager)manager).getNotificationPolicy());
+   }
 }

Modified: branches/Branch_4_2/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossCacheManager.java
===================================================================
--- branches/Branch_4_2/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossCacheManager.java	2008-09-20 21:50:34 UTC (rev 78730)
+++ branches/Branch_4_2/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossCacheManager.java	2008-09-20 21:50:48 UTC (rev 78731)
@@ -49,6 +49,10 @@
 import org.jboss.metadata.WebMetaData;
 import org.jboss.mx.util.MBeanServerLocator;
 import org.jboss.web.tomcat.service.JBossWeb;
+import org.jboss.web.tomcat.service.session.notification.ClusteredSessionNotificationCapability;
+import org.jboss.web.tomcat.service.session.notification.ClusteredSessionNotificationCause;
+import org.jboss.web.tomcat.service.session.notification.ClusteredSessionNotificationPolicy;
+import org.jboss.web.tomcat.service.session.notification.LegacyClusteredSessionNotificationPolicy;
 
 /**
  * Implementation of a clustered session manager for
@@ -62,7 +66,7 @@
 public class JBossCacheManager
    extends JBossManager
    implements JBossCacheManagerMBean
-{  
+{     
    /**
     * Informational name for this Catalina component
     */
@@ -132,6 +136,9 @@
    private boolean trace;
    
    private int maxUnreplicatedInterval_ = WebMetaData.DEFAULT_MAX_UNREPLICATED_INTERVAL;
+   
+   private String notificationPolicyClass_;
+   private ClusteredSessionNotificationPolicy notificationPolicy_ = new LegacyClusteredSessionNotificationPolicy();
 
    //  ----------------------------------------------------------  Constructors
 
@@ -173,6 +180,12 @@
          this.maxUnreplicatedInterval_ = maxUnrep.intValue();
       }
       
+      this.notificationPolicyClass_ = webMetaData.getClusteredSessionNotificationPolicy();
+      if (this.notificationPolicyClass_ == null || this.notificationPolicyClass_.length() == 0)
+      {
+         this.notificationPolicyClass_ = System.getProperty("jboss.web.clustered.session.notification.policy");
+      }
+      
       if (proxy_ == null)
          proxy_ = new JBossCacheService(cacheObjectNameString_);
 
@@ -408,8 +421,18 @@
       this.maxUnreplicatedInterval_ = maxUnreplicatedInterval;
    }
 
+   public ClusteredSessionNotificationPolicy getNotificationPolicy()
+   {
+      return notificationPolicy_;
+   }
+
    // JBossCacheManagerMBean-methods -------------------------------------
 
+   public void setNotificationPolicy_(ClusteredSessionNotificationPolicy notificationPolicy_)
+   {
+      this.notificationPolicy_ = notificationPolicy_;
+   }
+
    public void expireSession(String sessionId)
    {
       Session session = findSession(sessionId);
@@ -550,7 +573,7 @@
          boolean localOnly = true;
          try
          {
-            ses.expire(notify, localCall, localOnly);
+            ses.expire(notify, localCall, localOnly, ClusteredSessionNotificationCause.UNDEPLOY);
          }
          catch (Throwable t)
          {
@@ -637,6 +660,7 @@
       }
 
       session.setId(sessionId); // Setting the id leads to a call to add()
+      session.tellNew(ClusteredSessionNotificationCause.CREATE);
 
       if (log_.isDebugEnabled())
       {
@@ -814,8 +838,11 @@
          if (session != null)
          {
             add(session);
-            // TODO should we advise of a new session?
-            //tellNew();
+            // We now notify, since we've added a policy to allow listeners 
+            // to discriminate. But the default policy will not allow the 
+            // notification to be emitted for FAILOVER, so the standard
+            // behavior is unchanged.
+            session.tellNew(ClusteredSessionNotificationCause.FAILOVER);
          }
       }
       else if (session != null && session.isOutdated())
@@ -1331,7 +1358,7 @@
             Thread.currentThread().setContextClassLoader(tcl_);
             synchronized (session)
             {
-               session.removeAttributeInternal(attrKey, localCall, localOnly, notify);
+               session.removeAttributeInternal(attrKey, localCall, localOnly, notify, ClusteredSessionNotificationCause.MODIFY);
             }
             if (trace)
                log_.trace("processRemoteAttributeRemoval: removed attribute " + 
@@ -1378,7 +1405,7 @@
          try
          {
             Thread.currentThread().setContextClassLoader(tcl_);
-            session.expire(notify, localCall, localOnly);
+            session.expire(notify, localCall, localOnly, ClusteredSessionNotificationCause.TIMEOUT);
          }
          finally
          {
@@ -1454,6 +1481,8 @@
    {
       super.start();
       
+      initClusteredSessionNotificationPolicy();
+      
       // Start the JBossCacheService
       // Will need to pass the classloader that is associated with this 
       //web app so de-serialization will work correctly.
@@ -1521,8 +1550,10 @@
             log_.error(msg, e);
             throw new LifecycleException(msg, e);
          }
-      }
+      }      
       
+      initClusteredSessionNotificationPolicy();
+      
       // Validate attributes
       
       if ("SET_AND_GET".equalsIgnoreCase(replTriggerString_))         
@@ -1683,6 +1714,29 @@
       }
       return (mserver_);
    }
+
+   private void initClusteredSessionNotificationPolicy()
+   {
+      if (this.notificationPolicyClass_ != null && this.notificationPolicyClass_.length() == 0)
+      {      
+         try
+         {
+            this.notificationPolicy_ = (ClusteredSessionNotificationPolicy) Thread.currentThread().getContextClassLoader().loadClass(this.notificationPolicyClass_).newInstance();
+         }
+         catch (RuntimeException e)
+         {
+            throw e;
+         }
+         catch (Exception e)
+         {
+            throw new RuntimeException("Failed to instantiate " + 
+                  ClusteredSessionNotificationPolicy.class.getName() + 
+                  " " + this.notificationPolicyClass_, e);
+         }
+         
+         this.notificationPolicy_.setClusteredSessionExpriationNotificationCapability(new ClusteredSessionNotificationCapability());
+      }
+   }
    
    /**
     * Gets the ids of all sessions in the distributed cache and adds




More information about the jboss-cvs-commits mailing list