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