[seam-commits] Seam SVN: r9515 - in trunk/src: test/integration/src/org/jboss/seam/test/integration and 1 other directory.

seam-commits at lists.jboss.org seam-commits at lists.jboss.org
Thu Nov 6 01:31:45 EST 2008


Author: shane.bryzak at jboss.com
Date: 2008-11-06 01:31:45 -0500 (Thu, 06 Nov 2008)
New Revision: 9515

Modified:
   trunk/src/main/org/jboss/seam/core/Conversation.java
   trunk/src/main/org/jboss/seam/core/Manager.java
   trunk/src/test/integration/src/org/jboss/seam/test/integration/ConversationTest.java
Log:
JBSEAM-164

Modified: trunk/src/main/org/jboss/seam/core/Conversation.java
===================================================================
--- trunk/src/main/org/jboss/seam/core/Conversation.java	2008-11-06 06:01:47 UTC (rev 9514)
+++ trunk/src/main/org/jboss/seam/core/Conversation.java	2008-11-06 06:31:45 UTC (rev 9515)
@@ -34,6 +34,14 @@
    private Integer concurrentRequestTimeout;
    String description;
    String viewId;
+   
+   /**
+    * Kills all conversations except the current one
+    */
+   public void killAllOthers()
+   {
+      Manager.instance().killAllOtherConversations();
+   }
 
    /**
     * Get the timeout for this conversation instance.

Modified: trunk/src/main/org/jboss/seam/core/Manager.java
===================================================================
--- trunk/src/main/org/jboss/seam/core/Manager.java	2008-11-06 06:01:47 UTC (rev 9514)
+++ trunk/src/main/org/jboss/seam/core/Manager.java	2008-11-06 06:31:45 UTC (rev 9515)
@@ -11,6 +11,7 @@
 import java.io.UnsupportedEncodingException;
 import java.net.URLEncoder;
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
 import java.util.ListIterator;
 import java.util.Map;
@@ -45,6 +46,10 @@
 @BypassInterceptors
 public class Manager
 {
+   public static final String EVENT_CONVERSATION_TIMEOUT = "org.jboss.seam.conversationTimeout";
+   public static final String EVENT_CONVERSATION_DESTROYED = "org.jboss.seam.conversationDestroyed";
+   public static final String EVENT_CONVERSATION_BEGIN = "org.jboss.seam.beginConversation";
+   public static final String EVENT_CONVERSATION_END = "org.jboss.seam.endConversation";
    
    private static final LogProvider log = Logging.getLogProvider(Manager.class);
    
@@ -72,8 +77,99 @@
    private String URIEncoding = DEFAULT_ENCODING;
    
    private FlushModeType defaultFlushMode;
+
+   /**
+    * Kills all conversations except the current one 
+    */
+   public void killAllOtherConversations()
+   {
+      ConversationEntries conversationEntries = ConversationEntries.instance();
+      Events events = Events.exists() ? Events.instance() : null;
+
+      if (conversationEntries != null)
+      {
+         List<ConversationEntry> entries = new ArrayList<ConversationEntry>(
+               conversationEntries.getConversationEntries());
+
+         for (ConversationEntry conversationEntry : entries)
+         {
+            // kill all entries expect the current one
+            // current conversation entry will be null if , kill-all is called
+            // inside a new @Begin
+            if (getCurrentConversationEntry() == null
+                  || !getCurrentConversationIdStack().contains(
+                        conversationEntry.getId()))
+            {
+               log.info("Kill all other conversations, executed: kill conversation id = "
+                           + conversationEntry.getId());
+
+               boolean locked = conversationEntry.lockNoWait(); // we had better
+               // not wait for it, or we would be waiting for ALL other requests
+               try
+               {
+                  if (locked)
+                  {
+                     if (log.isDebugEnabled())
+                     {
+                        log.debug("conversation killed manually: " + conversationEntry.getId());
+                     }
+                  } 
+                  else
+                  {
+                     // if we could not acquire the lock, someone has left a
+                     // garbage lock lying around
+                     // the reason garbage locks can exist is that we don't
+                     // require a servlet filter to
+                     // exist - but if we do use SeamExceptionFilter, it will
+                     // clean up garbage and this
+                     // case should never occur
+
+                     // NOTE: this is slightly broken - in theory there is a
+                     // window where a new request
+                     // could have come in and got the lock just before us but
+                     // called touch() just
+                     // after we check the timeout - but in practice this would
+                     // be extremely rare,
+                     // and that request will get an
+                     // IllegalMonitorStateException when it tries to
+                     // unlock() the CE
+                     log.debug("kill conversation with garbage lock: "
+                           + conversationEntry.getId());
+                  }
+                  if (events != null)
+                  {
+                     events.raiseEvent(EVENT_CONVERSATION_DESTROYED);
+                  }
+                  destroyConversation(conversationEntry.getId(), getSessionMap());
+               } 
+               finally
+               {
+                  if (locked)
+                  {
+                     conversationEntry.unlock();
+                  }
+               }
+            }
+         }
+      }      
+   }
    
+   /**
+    * @return Map session
+    */
+   private Map<String, Object> getSessionMap()
+   {
+      // this method could be moved to a utility class
+      Map<String, Object> session = new HashMap<String, Object>();
+      String[] sessionAttributeNames = Contexts.getSessionContext().getNames();
    
+      for (String attributeName : sessionAttributeNames)
+      {
+         session.put(attributeName, Contexts.getSessionContext().get(attributeName));
+      }
+      return session;
+   }   
+   
    // DONT BREAK, icefaces uses this
    public String getCurrentConversationId()
    {
@@ -320,7 +416,7 @@
                   }
                   if ( Events.exists() ) 
                   {
-                     Events.instance().raiseEvent("org.jboss.seam.conversationTimeout", conversationEntry.getId());
+                     Events.instance().raiseEvent(EVENT_CONVERSATION_TIMEOUT, conversationEntry.getId());
                   }
                   destroyConversation( conversationEntry.getId(), session );
                }
@@ -589,7 +685,7 @@
          createConversationEntry();
          Conversation.instance(); //force instantiation of the Conversation in the outer (non-nested) conversation
          storeConversationToViewRootIfNecessary();
-         if ( Events.exists() ) Events.instance().raiseEvent("org.jboss.seam.beginConversation");
+         if ( Events.exists() ) Events.instance().raiseEvent(EVENT_CONVERSATION_BEGIN);
       }
    }
 
@@ -610,7 +706,7 @@
       createCurrentConversationIdStack(id).addAll(oldStack);
       createConversationEntry();
       storeConversationToViewRootIfNecessary();
-      if ( Events.exists() ) Events.instance().raiseEvent("org.jboss.seam.beginConversation");
+      if ( Events.exists() ) Events.instance().raiseEvent(EVENT_CONVERSATION_BEGIN);
    }
    
    /**
@@ -621,7 +717,7 @@
       if ( isLongRunningConversation() )
       {
          log.debug("Ending long-running conversation");
-         if ( Events.exists() ) Events.instance().raiseEvent("org.jboss.seam.endConversation");
+         if ( Events.exists() ) Events.instance().raiseEvent(EVENT_CONVERSATION_END);
          setLongRunningConversation(false);
          destroyBeforeRedirect = beforeRedirect;
          endNestedConversations( getCurrentConversationId() );

Modified: trunk/src/test/integration/src/org/jboss/seam/test/integration/ConversationTest.java
===================================================================
--- trunk/src/test/integration/src/org/jboss/seam/test/integration/ConversationTest.java	2008-11-06 06:01:47 UTC (rev 9514)
+++ trunk/src/test/integration/src/org/jboss/seam/test/integration/ConversationTest.java	2008-11-06 06:31:45 UTC (rev 9515)
@@ -5,6 +5,7 @@
 
 import javax.faces.model.SelectItem;
 
+import org.jboss.seam.core.ConversationEntries;
 import org.jboss.seam.core.ConversationEntry;
 import org.jboss.seam.core.Manager;
 import org.jboss.seam.faces.Switcher;
@@ -336,4 +337,105 @@
         }.run();
     }
 
+   @Test
+   public void killAllOthers() throws Exception
+   {
+      new FacesRequest("/pageWithAnotherDescription.xhtml") {
+         @Override
+         protected void invokeApplication() throws Exception
+         {
+            Manager.instance().beginConversation();
+         }
+
+         @Override
+         protected void renderResponse() throws Exception
+         {
+            assert ConversationEntries.instance().size() == 1;
+         }
+      }.run();
+
+      new FacesRequest("/pageWithoutDescription.xhtml") {
+         @Override
+         protected void invokeApplication() throws Exception
+         {
+            Manager.instance().beginConversation();
+         }
+
+         @Override
+         protected void renderResponse() throws Exception
+         {
+            assert ConversationEntries.instance().size() == 2;
+         }
+      }.run();
+
+      new FacesRequest("/pageWithDescription.xhtml") {
+         @Override
+         protected void invokeApplication() throws Exception
+         {
+            Manager.instance().beginConversation();
+            Manager.instance().killAllOtherConversations();
+         }
+
+         @Override
+         protected void renderResponse() throws Exception
+         {
+            assert ConversationEntries.instance().size() == 1;
+         }
+      }.run();
+
+   }
+
+   @Test
+   public void nestedKillAllOthers() throws Exception
+   {
+
+      final String unrelated = new FacesRequest("/pageWithoutDescription.xhtml") {
+         @Override
+         protected void invokeApplication() throws Exception
+         {
+            Manager.instance().beginConversation();
+         }
+
+         @Override
+         protected void renderResponse() throws Exception
+         {
+            assert ConversationEntries.instance().size() == 1;
+         }
+      }.run();
+
+      String root = new FacesRequest("/pageWithDescription.xhtml") {
+         @Override
+         protected void invokeApplication() throws Exception
+         {
+            Manager.instance().beginConversation();
+         }
+
+         @Override
+         protected void renderResponse() throws Exception
+         {
+            assert ConversationEntries.instance().size() == 2;
+         }
+      }.run();
+
+      // nested conversation
+      new FacesRequest("/pageWithDescription.xhtml", root) {
+         @Override
+         protected void invokeApplication() throws Exception
+         {
+            Manager.instance().beginNestedConversation();
+         }
+
+         @Override
+         protected void renderResponse() throws Exception
+         {
+            assert ConversationEntries.instance().size() == 3;
+
+            Manager.instance().killAllOtherConversations();
+            assert ConversationEntries.instance().size() == 2;
+            assert ConversationEntries.instance().getConversationIds()
+                  .contains(unrelated) == false;
+         }
+
+      }.run();
+   }
 }




More information about the seam-commits mailing list