Revision: 907
          http://stripes.svn.sourceforge.net/stripes/?rev=907&view=rev
Author:   bengunter
Date:     2008-05-15 09:13:22 -0700 (Thu, 15 May 2008)

Log Message:
-----------
Fix for STS-563. Each flash scope contains a semaphore that is used to 
synchronized the cleanup at the end of one request and the stuff at the 
beginning of the next request.

Modified Paths:
--------------
    trunk/stripes/src/net/sourceforge/stripes/controller/FlashScope.java
    trunk/stripes/src/net/sourceforge/stripes/controller/StripesFilter.java

Modified: trunk/stripes/src/net/sourceforge/stripes/controller/FlashScope.java
===================================================================
--- trunk/stripes/src/net/sourceforge/stripes/controller/FlashScope.java        
2008-05-14 17:44:40 UTC (rev 906)
+++ trunk/stripes/src/net/sourceforge/stripes/controller/FlashScope.java        
2008-05-15 16:13:22 UTC (rev 907)
@@ -16,6 +16,7 @@
 
 import net.sourceforge.stripes.action.ActionBean;
 import net.sourceforge.stripes.action.ActionBeanContext;
+import net.sourceforge.stripes.exception.StripesRuntimeException;
 import net.sourceforge.stripes.util.Log;
 
 import javax.servlet.http.HttpServletRequest;
@@ -30,6 +31,8 @@
 import java.util.Map;
 import java.util.Random;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
 
 /**
  * <p>A FlashScope is an object that can be used to store objects and make 
them available as
@@ -90,6 +93,7 @@
     private int timeout = DEFAULT_TIMEOUT_IN_SECONDS;
     private HttpServletRequest request;
     private Integer key;
+    private Semaphore semaphore;
 
     /**
      * Protected constructor to prevent random creation of FlashScopes. Uses 
the request
@@ -102,6 +106,8 @@
     protected FlashScope(HttpServletRequest request, Integer key) {
         this.request = request;
         this.key = key;
+        this.semaphore = new Semaphore(1);
+        this.semaphore.acquireUninterruptibly();
     }
 
     /** Returns the timeout in seconds after which the flash scope will be 
discarded. */
@@ -118,6 +124,22 @@
     }
 
     /**
+     * Get the semaphore that is used to synchronize the calls to [EMAIL 
PROTECTED] #completeRequest()} and
+     * [EMAIL PROTECTED] #beginRequest(HttpServletRequest)} made by [EMAIL 
PROTECTED] StripesFilter}.
+     */
+    protected Semaphore getSemaphore() {
+        return semaphore;
+    }
+
+    /**
+     * Renamed to [EMAIL PROTECTED] #completeRequest()}.
+     */
+    @Deprecated
+    public void requestComplete() {
+        completeRequest();
+    }
+
+    /**
      * <p>Used by the StripesFilter to notify the flash scope that the request 
for which
      * it is used has been completed. The FlashScope uses this notification to 
start a
      * timer, and also to null out it's reference to the request so that it 
can be
@@ -126,7 +148,7 @@
      * <p>The timer is used to determine if a flash scope has been orphaned 
(i.e. the subsequent
      * request was not made) after a period of time, so that it can be removed 
from session.</p>
      */
-    public void requestComplete() {
+    public void completeRequest() {
         // Clean up any old-age flash scopes
         Map<Integer, FlashScope> scopes = getContainer(request, false);
         if (scopes != null && !scopes.isEmpty()) {
@@ -158,9 +180,63 @@
         // start timer, clear request
         this.startTime = System.currentTimeMillis();
         this.request = null;
+        this.semaphore.release();
     }
 
     /**
+     * <p>
+     * Called by [EMAIL PROTECTED] StripesFilter} to copy all the attributes 
from this flash scope to the given
+     * [EMAIL PROTECTED] request}. [EMAIL PROTECTED] 
#beginRequest(HttpServletRequest)} must never be called before
+     * [EMAIL PROTECTED] #completeRequest()} is called. Since the two methods 
are normally called by different
+     * threads, synchronization of the calls is accomplished through use of a 
[EMAIL PROTECTED] Semaphore}.
+     * </p>
+     * 
+     * @param request The request to copy the flash scope attributes to
+     */
+    public void beginRequest(HttpServletRequest request) {
+        boolean acquired = false;
+        try {
+            // Acquire the permit from the semaphore with a 1 second timeout 
for safety
+            acquired = getSemaphore().tryAcquire(1, TimeUnit.SECONDS);
+
+            // If no permit was acquired, then that's bad so log it as an error
+            if (!acquired) {
+                log.error("Something is amiss! A timeout occurred while trying 
to copy a flash "
+                        + "scope to a new request. Only StripesFilter should 
call "
+                        + "FlashScope.completeRequest() and 
FlashScope.beginRequest(), and the "
+                        + "calls must be properly synchronized. The timeout 
likely means that "
+                        + "completeRequest() was never called or did not 
complete successfully "
+                        + "on this flash scope.");
+            }
+
+            // Copy all the attributes from this scope to the request scope
+            for (Map.Entry<String, Object> entry : entrySet()) {
+                Object value = entry.getValue();
+                if (value instanceof ActionBean) {
+                    HttpServletRequest tmp = ((ActionBean) 
value).getContext().getRequest();
+                    if (tmp != null) {
+                        tmp = StripesRequestWrapper.findStripesWrapper(tmp);
+                        if (tmp != null) {
+                            tmp = (HttpServletRequest) 
((StripesRequestWrapper) tmp).getRequest();
+                            if (tmp instanceof FlashRequest)
+                                ((FlashRequest) tmp).setDelegate(request);
+                        }
+                    }
+                }
+                request.setAttribute(entry.getKey(), value);
+            }
+        }
+        catch (InterruptedException e) {
+            throw new StripesRuntimeException(e);
+        }
+        finally {
+            // Make sure the semaphore permit gets released
+            if (acquired)
+                getSemaphore().release();
+        }
+    }
+
+    /**
      * Returns the time in seconds since the request that generated this flash 
scope
      * completed.  Will return 0 if this flash scope has not yet started to 
age.
      */

Modified: 
trunk/stripes/src/net/sourceforge/stripes/controller/StripesFilter.java
===================================================================
--- trunk/stripes/src/net/sourceforge/stripes/controller/StripesFilter.java     
2008-05-14 17:44:40 UTC (rev 906)
+++ trunk/stripes/src/net/sourceforge/stripes/controller/StripesFilter.java     
2008-05-15 16:13:22 UTC (rev 907)
@@ -14,7 +14,6 @@
  */
 package net.sourceforge.stripes.controller;
 
-import net.sourceforge.stripes.action.ActionBean;
 import net.sourceforge.stripes.config.BootstrapPropertyResolver;
 import net.sourceforge.stripes.config.Configuration;
 import net.sourceforge.stripes.config.RuntimeConfiguration;
@@ -38,7 +37,6 @@
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.Locale;
-import java.util.Map;
 import java.util.Set;
 
 /**
@@ -290,23 +288,10 @@
      * back to request attributes.</p>
      */
     protected void flashInbound(HttpServletRequest req) {
+        // Copy the attributes from the previous flash scope to the new request
         FlashScope flash = FlashScope.getPrevious(req);
-
         if (flash != null) {
-            for (Map.Entry<String, Object> entry : flash.entrySet()) {
-                Object value = entry.getValue();
-                if (value instanceof ActionBean) {
-                    HttpServletRequest tmp = ((ActionBean) 
value).getContext().getRequest();
-                    if (tmp != null) {
-                        tmp = StripesRequestWrapper.findStripesWrapper(tmp);
-                        if (tmp != null) {
-                            tmp = (HttpServletRequest) 
((StripesRequestWrapper) tmp).getRequest();
-                            ((FlashRequest) tmp).setDelegate(req);
-                        }
-                    }
-                }
-                req.setAttribute(entry.getKey(), value);
-            }
+            flash.beginRequest(req);
         }
     }
 
@@ -320,7 +305,7 @@
         // Start the timer on the current flash scope
         FlashScope flash = FlashScope.getCurrent(req, false);
         if (flash != null) {
-            flash.requestComplete();
+            flash.completeRequest();
         }
     }
 


This was sent by the SourceForge.net collaborative development platform, the 
world's largest Open Source development site.

-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft 
Defy all challenges. Microsoft(R) Visual Studio 2008. 
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/
_______________________________________________
Stripes-development mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/stripes-development

Reply via email to