Revision: 502
          http://svn.sourceforge.net/stripes/?rev=502&view=rev
Author:   bengunter
Date:     2007-03-30 06:37:45 -0700 (Fri, 30 Mar 2007)

Log Message:
-----------
Merged fix for STS-319 from trunk

Modified Paths:
--------------
    
branches/1.4.x/stripes/src/net/sourceforge/stripes/controller/FlashScope.java
    
branches/1.4.x/stripes/src/net/sourceforge/stripes/controller/StripesConstants.java
    
branches/1.4.x/stripes/src/net/sourceforge/stripes/controller/StripesFilter.java
    
branches/1.4.x/tests/src/net/sourceforge/stripes/controller/FlashScopeTests.java

Added Paths:
-----------
    
branches/1.4.x/stripes/src/net/sourceforge/stripes/controller/FlashRequest.java
    
branches/1.4.x/stripes/src/net/sourceforge/stripes/controller/FlashResponseInvocationHandler.java

Added: 
branches/1.4.x/stripes/src/net/sourceforge/stripes/controller/FlashRequest.java
===================================================================
--- 
branches/1.4.x/stripes/src/net/sourceforge/stripes/controller/FlashRequest.java 
                            (rev 0)
+++ 
branches/1.4.x/stripes/src/net/sourceforge/stripes/controller/FlashRequest.java 
    2007-03-30 13:37:45 UTC (rev 502)
@@ -0,0 +1,377 @@
+package net.sourceforge.stripes.controller;
+
+import java.io.BufferedReader;
+import java.io.Serializable;
+import java.security.Principal;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+import javax.servlet.RequestDispatcher;
+import javax.servlet.ServletInputStream;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpSession;
+
+import net.sourceforge.stripes.exception.StripesRuntimeException;
+import net.sourceforge.stripes.exception.StripesServletException;
+
+/**
+ * Captures the state of an [EMAIL PROTECTED] 
javax.servlet.http.HttpServletRequest} so that the information
+ * contained therein can be carried over to the next request for use by the 
flash scope. There are
+ * several methods in here that cannot be faked and so must delegate to an 
active [EMAIL PROTECTED]
+ * javax.servlet.http.HttpServletRequest} object, the [EMAIL PROTECTED] 
#delegate}. If one of these methods is
+ * called and there is no delegate object set on the instance, they will throw 
a [EMAIL PROTECTED]
+ * net.sourceforge.stripes.exception.StripesRuntimeException}. Unless this 
class is used outside its
+ * intended context (during a live request processed through [EMAIL PROTECTED] 
StripesFilter}), you won't need
+ * to worry about that.
+ *
+ * @author Ben Gunter
+ * @since Stripes 1.4.3
+ */
+public class FlashRequest implements HttpServletRequest, Serializable {
+    private Cookie[] cookies;
+    private HttpServletRequest delegate;
+    private List<Locale> locales;
+    private Locale locale;
+    private Map<String, List<String>> headers = new HashMap<String, 
List<String>>();
+    private Map<String, Long> dateHeaders = new HashMap<String, Long>();
+    private Map<String, Object> attributes = new HashMap<String, Object>();
+    private Map<String, String[]> parameters = new HashMap<String, String[]>();
+    private String authType;
+    private String characterEncoding;
+    private String contentType;
+    private String contextPath;
+    private String localAddr;
+    private String localName;
+    private String method;
+    private String pathInfo;
+    private String pathTranslated;
+    private String protocol;
+    private String queryString;
+    private String remoteAddr;
+    private String remoteHost;
+    private String remoteUser;
+    private String requestURI;
+    private String requestedSessionId;
+    private String scheme;
+    private String serverName;
+    private String servletPath;
+    private StringBuffer requestURL;
+    private boolean requestedSessionIdFromCookie;
+    private boolean requestedSessionIdFromURL;
+    private boolean requestedSessionIdFromUrl;
+    private boolean requestedSessionIdValid;
+    private boolean secure;
+    private int localPort;
+    private int remotePort;
+    private int serverPort;
+    
+    public static StripesRequestWrapper wrapRequest(HttpServletRequest 
request) {
+        try {
+            return new StripesRequestWrapper(new FlashRequest(request));
+        }
+        catch (StripesServletException e) {
+            throw new StripesRuntimeException(e);
+        }
+    }
+
+    @SuppressWarnings({ "unchecked", "deprecation" })
+    public FlashRequest(HttpServletRequest prototype) {
+        // copy properties
+        authType = prototype.getAuthType();
+        characterEncoding = prototype.getCharacterEncoding();
+        contentType = prototype.getContentType();
+        contextPath = prototype.getContextPath();
+        cookies = prototype.getCookies();
+        localAddr = prototype.getLocalAddr();
+        localName = prototype.getLocalName();
+        localPort = prototype.getLocalPort();
+        locale = prototype.getLocale();
+        method = prototype.getMethod();
+        pathInfo = prototype.getPathInfo();
+        pathTranslated = prototype.getPathTranslated();
+        protocol = prototype.getProtocol();
+        queryString = prototype.getQueryString();
+        remoteAddr = prototype.getRemoteAddr();
+        remoteHost = prototype.getRemoteHost();
+        remotePort = prototype.getRemotePort();
+        remoteUser = prototype.getRemoteUser();
+        requestURI = prototype.getRequestURI();
+        requestURL = prototype.getRequestURL();
+        requestedSessionId = prototype.getRequestedSessionId();
+        requestedSessionIdFromCookie = 
prototype.isRequestedSessionIdFromCookie();
+        requestedSessionIdFromURL = prototype.isRequestedSessionIdFromURL();
+        requestedSessionIdFromUrl = prototype.isRequestedSessionIdFromUrl();
+        requestedSessionIdValid = prototype.isRequestedSessionIdValid();
+        scheme = prototype.getScheme();
+        secure = prototype.isSecure();
+        serverName = prototype.getServerName();
+        serverPort = prototype.getServerPort();
+        servletPath = prototype.getServletPath();
+
+        // copy attributes
+        for (String key : Collections.list((Enumeration<String>) 
prototype.getAttributeNames())) {
+            attributes.put(key, prototype.getAttribute(key));
+        }
+
+        // copy headers
+        for (String key : Collections.list((Enumeration<String>) 
prototype.getHeaderNames())) {
+            headers.put(key, Collections.list(prototype.getHeaders(key)));
+            try {
+                dateHeaders.put(key, prototype.getDateHeader(key));
+            }
+            catch (Exception e) {
+            }
+        }
+
+        // copy locales
+        locales = Collections.list(prototype.getLocales());
+
+        // copy parameters
+        parameters.putAll(prototype.getParameterMap());
+    }
+
+    protected HttpServletRequest getDelegate() {
+        if (delegate == null) {
+            throw new IllegalStateException(
+                    "Attempt to access a delegate method of " +
+                    FlashRequest.class.getName() +
+                    " but no delegate request has been set");
+        }
+        return delegate;
+    }
+
+    public void setDelegate(HttpServletRequest delegate) {
+        this.delegate = delegate;
+    }
+
+    public String getAuthType() {
+        return authType;
+    }
+
+    public Cookie[] getCookies() {
+        return cookies;
+    }
+
+    public long getDateHeader(String name) {
+        Long value = dateHeaders.get(name);
+        return value == null ? 0 : value;
+    }
+
+    public String getHeader(String name) {
+        List<String> values = headers.get(name);
+        return values != null && values.size() > 0 ? values.get(0) : null;
+    }
+
+    public Enumeration<String> getHeaders(String name) {
+        return Collections.enumeration(headers.get(name));
+    }
+
+    public Enumeration<String> getHeaderNames() {
+        return Collections.enumeration(headers.keySet());
+    }
+
+    public int getIntHeader(String name) {
+        try {
+            return Integer.parseInt(getHeader(name));
+        }
+        catch (Exception e) {
+            return 0;
+        }
+    }
+
+    public String getMethod() {
+        return method;
+    }
+
+    public String getPathInfo() {
+        return pathInfo;
+    }
+
+    public String getPathTranslated() {
+        return pathTranslated;
+    }
+
+    public String getContextPath() {
+        return contextPath;
+    }
+
+    public String getQueryString() {
+        return queryString;
+    }
+
+    public String getRemoteUser() {
+        return remoteUser;
+    }
+
+    public boolean isUserInRole(String role) {
+        return getDelegate().isUserInRole(role);
+    }
+
+    public Principal getUserPrincipal() {
+        return getDelegate().getUserPrincipal();
+    }
+
+    public String getRequestedSessionId() {
+        return requestedSessionId;
+    }
+
+    public String getRequestURI() {
+        return requestURI;
+    }
+
+    public StringBuffer getRequestURL() {
+        return new StringBuffer(requestURL.toString());
+    }
+
+    public String getServletPath() {
+        return servletPath;
+    }
+
+    public HttpSession getSession(boolean create) {
+        return getDelegate().getSession(create);
+    }
+
+    public HttpSession getSession() {
+        return getDelegate().getSession();
+    }
+
+    public boolean isRequestedSessionIdValid() {
+        return requestedSessionIdValid;
+    }
+
+    public boolean isRequestedSessionIdFromCookie() {
+        return requestedSessionIdFromCookie;
+    }
+
+    public boolean isRequestedSessionIdFromURL() {
+        return requestedSessionIdFromURL;
+    }
+
+    @Deprecated
+    public boolean isRequestedSessionIdFromUrl() {
+        return requestedSessionIdFromUrl;
+    }
+
+    public Object getAttribute(String name) {
+        return attributes.get(name);
+    }
+
+    public Enumeration<String> getAttributeNames() {
+        return Collections.enumeration(attributes.keySet());
+    }
+
+    public String getCharacterEncoding() {
+        return characterEncoding;
+    }
+
+    public void setCharacterEncoding(String characterEncoding) {
+        this.characterEncoding = characterEncoding;
+    }
+
+    public int getContentLength() {
+        return 0;
+    }
+
+    public String getContentType() {
+        return contentType;
+    }
+
+    public ServletInputStream getInputStream() {
+        return null;
+    }
+
+    public String getParameter(String name) {
+        String[] values = getParameterValues(name);
+        return values != null && values.length > 0 ? values[0] : null;
+    }
+
+    public Enumeration<String> getParameterNames() {
+        return Collections.enumeration(parameters.keySet());
+    }
+
+    public String[] getParameterValues(String name) {
+        return parameters.get(name);
+    }
+
+    public Map<String, String[]> getParameterMap() {
+        return Collections.unmodifiableMap(parameters);
+    }
+
+    public String getProtocol() {
+        return protocol;
+    }
+
+    public String getScheme() {
+        return scheme;
+    }
+
+    public String getServerName() {
+        return serverName;
+    }
+
+    public int getServerPort() {
+        return serverPort;
+    }
+
+    public BufferedReader getReader() {
+        return null;
+    }
+
+    public String getRemoteAddr() {
+        return remoteAddr;
+    }
+
+    public String getRemoteHost() {
+        return remoteHost;
+    }
+
+    public void setAttribute(String name, Object value) {
+        attributes.put(name, value);
+    }
+
+    public void removeAttribute(String name) {
+        attributes.remove(name);
+    }
+
+    public Locale getLocale() {
+        return locale;
+    }
+
+    public Enumeration<Locale> getLocales() {
+        return Collections.enumeration(locales);
+    }
+
+    public boolean isSecure() {
+        return secure;
+    }
+
+    public RequestDispatcher getRequestDispatcher(String name) {
+        return getDelegate().getRequestDispatcher(name);
+    }
+
+    @Deprecated
+    public String getRealPath(String name) {
+        return getDelegate().getRealPath(name);
+    }
+
+    public int getRemotePort() {
+        return remotePort;
+    }
+
+    public String getLocalName() {
+        return localName;
+    }
+
+    public String getLocalAddr() {
+        return localAddr;
+    }
+
+    public int getLocalPort() {
+        return localPort;
+    }
+}

Added: 
branches/1.4.x/stripes/src/net/sourceforge/stripes/controller/FlashResponseInvocationHandler.java
===================================================================
--- 
branches/1.4.x/stripes/src/net/sourceforge/stripes/controller/FlashResponseInvocationHandler.java
                           (rev 0)
+++ 
branches/1.4.x/stripes/src/net/sourceforge/stripes/controller/FlashResponseInvocationHandler.java
   2007-03-30 13:37:45 UTC (rev 502)
@@ -0,0 +1,23 @@
+package net.sourceforge.stripes.controller;
+
+import java.io.Serializable;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+
+/**
+ * Used as the [EMAIL PROTECTED] java.lang.reflect.InvocationHandler} for a 
dynamic proxy that replaces the
+ * [EMAIL PROTECTED] javax.servlet.http.HttpServletResponse} on [EMAIL 
PROTECTED]
+ * net.sourceforge.stripes.action.ActionBeanContext}s in the flash scope after 
the current request
+ * cycle has completed.
+ * 
+ * @author Ben Gunter
+ * @since Stripes 1.4.3
+ */
+public class FlashResponseInvocationHandler implements InvocationHandler, 
Serializable {
+    public Object invoke(Object object, Method method, Object[] objects) 
throws Throwable {
+        throw new IllegalStateException(
+                "Attempt to call " + method + " after the request cycle has 
completed. " +
+                "This is most likely due to misuse of a flashed ActionBean or 
ActionBeanContext " +
+                "on the ensuing request.");
+    }
+}

Modified: 
branches/1.4.x/stripes/src/net/sourceforge/stripes/controller/FlashScope.java
===================================================================
--- 
branches/1.4.x/stripes/src/net/sourceforge/stripes/controller/FlashScope.java   
    2007-03-30 11:32:41 UTC (rev 501)
+++ 
branches/1.4.x/stripes/src/net/sourceforge/stripes/controller/FlashScope.java   
    2007-03-30 13:37:45 UTC (rev 502)
@@ -15,15 +15,23 @@
 package net.sourceforge.stripes.controller;
 
 import net.sourceforge.stripes.action.ActionBean;
+import net.sourceforge.stripes.action.ActionBeanContext;
+import net.sourceforge.stripes.exception.StripesRuntimeException;
+import net.sourceforge.stripes.exception.StripesServletException;
 import net.sourceforge.stripes.util.Log;
 
 import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
 import javax.servlet.http.HttpSession;
 import java.io.Serializable;
+import java.lang.reflect.Proxy;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.Iterator;
 import java.util.Map;
+import java.util.Random;
+import java.util.concurrent.ConcurrentHashMap;
 
 /**
  * <p>A FlashScope is an object that can be used to store objects and make 
them available as
@@ -77,19 +85,45 @@
     public static final int DEFAULT_TIMEOUT_IN_SECONDS = 120;
 
     private static final Log log = Log.getInstance(FlashScope.class);
+    private static final Random random = new Random();
     private long startTime;
     private int timeout = DEFAULT_TIMEOUT_IN_SECONDS;
     private HttpServletRequest request;
+    private Integer key;
 
     /**
+     * <p>
+     * Protected constructor to prevent random creation of FlashScopes. Uses 
the request to generate
+     * a key under which the flash scope will be stored, and can be identified 
by later.
+     * </p>
+     * <p>
+     * This constructor is deprecated. [EMAIL PROTECTED] 
#FlashScope(HttpServletRequest, Integer)} is the
+     * preferred constructor.
+     * </p>
+     * 
+     * @param request the request for which this flash scope will be used.
+     */
+    @Deprecated
+    protected FlashScope(HttpServletRequest request) {
+        this.request = request;
+        StripesRequestWrapper wrapper = 
StripesRequestWrapper.findStripesWrapper(request);
+        if (wrapper == null)
+            throw new StripesRuntimeException(
+                    "No StripesRequestWrapper was found for the given 
request");
+        this.key = wrapper.hashCode();
+    }
+
+    /**
      * Protected constructor to prevent random creation of FlashScopes. Uses 
the request
      * to generate a key under which the flash scope will be stored, and can 
be identified
      * by later.
      *
      * @param request the request for which this flash scope will be used.
+     * @param key the key by which this flash scope can be looked up in the map
      */
-    protected FlashScope(HttpServletRequest request) {
+    protected FlashScope(HttpServletRequest request, Integer key) {
         this.request = request;
+        this.key = key;
     }
 
     /** Returns the timeout in seconds after which the flash scope will be 
discarded. */
@@ -102,7 +136,7 @@
      * Returns the key used to store this flash scope in the colleciton of 
flash scopes.
      */
     public Integer key() {
-        return this.request.hashCode();
+        return key;
     }
 
     /**
@@ -115,6 +149,35 @@
      * request was not made) after a period of time, so that it can be removed 
from session.</p>
      */
     public void requestComplete() {
+        // Clean up any old-age flash scopes
+        Map<Integer, FlashScope> scopes = getContainer(request, false);
+        if (scopes != null && !scopes.isEmpty()) {
+            Iterator<FlashScope> iterator = scopes.values().iterator();
+            while (iterator.hasNext()) {
+                if (iterator.next().isExpired()) {
+                    iterator.remove();
+                }
+            }
+        }
+
+        // Replace the request and response objects for the request cycle that 
is ending
+        // with objects that are safe to use on the ensuing request.
+        HttpServletRequest flashRequest = FlashRequest.wrapRequest(request);
+        HttpServletResponse flashResponse = (HttpServletResponse) 
Proxy.newProxyInstance(
+                getClass().getClassLoader(),
+                new Class<?>[] { HttpServletResponse.class },
+                new FlashResponseInvocationHandler());
+        for (Object o : this.values()) {
+            if (o instanceof ActionBean) {
+                ActionBeanContext context = ((ActionBean) o).getContext();
+                if (context != null) {
+                    context.setRequest(flashRequest);
+                    context.setResponse(flashResponse);
+                }
+            }
+        }
+
+        // start timer, clear request
         this.startTime = System.currentTimeMillis();
         this.request = null;
     }
@@ -213,15 +276,28 @@
             return null;
         }
         else {
-            Integer id = new Integer(keyString);
-            Map<Integer,FlashScope> scopes = getContainer(req, false);
-            return (scopes == null) ? null : scopes.remove(id);
+            try {
+                Integer id = new Integer(keyString);
+                Map<Integer, FlashScope> scopes = getContainer(req, false);
+                return scopes == null ? null : scopes.remove(id);
+            }
+            catch (NumberFormatException e) {
+                return null;
+            }
         }
     }
 
     /**
-     * Gets the current flash scope into which items can be stored temporarily.
-     *
+     * <p>
+     * Gets the current flash scope into which items can be stored 
temporarily. If
+     * <code>create</code> is true, then a new one will be created.
+     * </p>
+     * <p>
+     * It is assumed that the request object will be used by only one thread 
so access to the
+     * request is not synchronized. Access to the scopes map that is stored in 
the session and the
+     * static [EMAIL PROTECTED] Random} that is used to generate the keys for 
the map is synchronized.
+     * </p>
+     * 
      * @param req the current request
      * @param create if true then the FlashScope will be created when it does 
not exist already
      * @return the current FlashScope, or null if it does not exist and create 
is false
@@ -233,11 +309,21 @@
             return null;
         }
         else {
-            FlashScope scope = scopes.get(req.hashCode());
-            if (scope == null && create) {
-                scope = new FlashScope(req);
-                scopes.put(req.hashCode(), scope);
+            FlashScope scope = null;
+            Integer key = (Integer) 
req.getAttribute(StripesConstants.REQ_ATTR_CURRENT_FLASH_SCOPE);
+            if (key != null) {
+                scope = scopes.get(key);
             }
+            else if (create) {
+                synchronized (random) {
+                    do {
+                        key = random.nextInt();
+                    } while (scopes.containsKey(key));
+                    scope = new FlashScope(req, key);
+                    scopes.put(scope.key(), scope);
+                }
+                
req.setAttribute(StripesConstants.REQ_ATTR_CURRENT_FLASH_SCOPE, key);
+            }
 
             return scope;
         }
@@ -258,12 +344,19 @@
             HttpSession session =  req.getSession(create);
             Map<Integer,FlashScope> scopes = null;
             if (session != null) {
-                 scopes = (Map<Integer,FlashScope>)
-                        
session.getAttribute(StripesConstants.REQ_ATTR_FLASH_SCOPE_LOCATION);
+                scopes = getContainer(session);
 
                 if (scopes == null && create) {
-                    scopes = new HashMap<Integer,FlashScope>();
-                    
req.getSession().setAttribute(StripesConstants.REQ_ATTR_FLASH_SCOPE_LOCATION, 
scopes);
+                    synchronized 
(StripesConstants.REQ_ATTR_FLASH_SCOPE_LOCATION) {
+                        // after obtaining a lock, try looking it up again
+                        scopes = getContainer(session);
+
+                        // if still not there, then create and save it
+                        if (scopes == null) {
+                            scopes = new ConcurrentHashMap<Integer, 
FlashScope>();
+                            
session.setAttribute(StripesConstants.REQ_ATTR_FLASH_SCOPE_LOCATION, scopes);
+                        }
+                    }
                 }
             }
 
@@ -279,4 +372,19 @@
             return null;
         }
     }
+    
+    /**
+     * Internal helper method to retrieve the container for all the flash 
scopes. Will return null
+     * if the container does not exist.
+     * 
+     * @param session
+     * @return a Map of integer keys to FlashScope objects
+     * @throws IllegalStateException if the session has been invalidated
+     */
+    @SuppressWarnings("unchecked")
+    private static Map<Integer, FlashScope> getContainer(HttpSession session)
+            throws IllegalStateException {
+        return (Map<Integer, FlashScope>) session
+                .getAttribute(StripesConstants.REQ_ATTR_FLASH_SCOPE_LOCATION);
+    }
 }

Modified: 
branches/1.4.x/stripes/src/net/sourceforge/stripes/controller/StripesConstants.java
===================================================================
--- 
branches/1.4.x/stripes/src/net/sourceforge/stripes/controller/StripesConstants.java
 2007-03-30 11:32:41 UTC (rev 501)
+++ 
branches/1.4.x/stripes/src/net/sourceforge/stripes/controller/StripesConstants.java
 2007-03-30 13:37:45 UTC (rev 502)
@@ -74,6 +74,9 @@
      * hashcode of the request that generated them.
      */
     String REQ_ATTR_FLASH_SCOPE_LOCATION = "__flash_scopes";
+    
+    /** The name of a request attribute that holds the lookup key of the 
current flash scope. */
+    String REQ_ATTR_CURRENT_FLASH_SCOPE = "__current_flash_scope";
 
     /**
      * Request attribute key defined by the servlet spec for storing the 
included servlet

Modified: 
branches/1.4.x/stripes/src/net/sourceforge/stripes/controller/StripesFilter.java
===================================================================
--- 
branches/1.4.x/stripes/src/net/sourceforge/stripes/controller/StripesFilter.java
    2007-03-30 11:32:41 UTC (rev 501)
+++ 
branches/1.4.x/stripes/src/net/sourceforge/stripes/controller/StripesFilter.java
    2007-03-30 13:37:45 UTC (rev 502)
@@ -14,6 +14,7 @@
  */
 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;
@@ -212,8 +213,19 @@
         FlashScope flash = FlashScope.getPrevious(req);
 
         if (flash != null) {
-            for (Map.Entry<String,Object> entry : flash.entrySet()) {
-                req.setAttribute(entry.getKey(), entry.getValue());
+            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);
             }
         }
     }
@@ -230,16 +242,6 @@
         if (flash != null) {
             flash.requestComplete();
         }
-
-        // Clean up any old-age flash scopes
-        Collection<FlashScope> flashes = FlashScope.getAllFlashScopes(req);
-        Iterator<FlashScope> iterator = flashes.iterator();
-        while (iterator.hasNext()) {
-            FlashScope f = iterator.next();
-            if (f.isExpired()) {
-                iterator.remove();
-            }
-        }
     }
 
     /** Does nothing. */

Modified: 
branches/1.4.x/tests/src/net/sourceforge/stripes/controller/FlashScopeTests.java
===================================================================
--- 
branches/1.4.x/tests/src/net/sourceforge/stripes/controller/FlashScopeTests.java
    2007-03-30 11:32:41 UTC (rev 501)
+++ 
branches/1.4.x/tests/src/net/sourceforge/stripes/controller/FlashScopeTests.java
    2007-03-30 13:37:45 UTC (rev 502)
@@ -15,6 +15,9 @@
 import net.sourceforge.stripes.action.HandlesEvent;
 
 import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import java.lang.reflect.Proxy;
 import java.util.Map;
 import java.util.regex.Pattern;
 import java.util.regex.Matcher;
@@ -27,7 +30,7 @@
 @UrlBinding("/FlashScopeTests.action")
 public class FlashScopeTests implements ActionBean {
     static final Pattern FLASH_ID_REGEX =
-            Pattern.compile(".*" + StripesConstants.URL_KEY_FLASH_SCOPE_ID + 
"=(\\d+).*");
+            Pattern.compile(".*" + StripesConstants.URL_KEY_FLASH_SCOPE_ID + 
"=(-?\\d+).*");
 
     private ActionBeanContext context;
     public ActionBeanContext getContext() { return context; }
@@ -46,6 +49,11 @@
 
         return new RedirectResolution("/FlashScopeTests.action");
     }
+    
+    @HandlesEvent("FlashBean")
+    public Resolution flashBean() {
+        return new RedirectResolution("/FlashScopeTests.action").flash(this);
+    }
 
     /** A do-nothing test handler. */
     @HandlesEvent("DoNothing")
@@ -84,5 +92,28 @@
 
         
Assert.assertEquals(FlashScope.getAllFlashScopes(trip2.getRequest()).size(), 0,
                             "FlashScope should have been removed from session 
after use.");
+        
+        // Test flashing an ActionBean
+        MockRoundtrip trip3 = new MockRoundtrip(ctx, FlashScopeTests.class, 
(MockHttpSession) trip
+                .getRequest().getSession());
+
+        // Get the flash scope ID from the redirect URL and add it back as a 
parameter
+        trip3.addParameter(StripesConstants.URL_KEY_FLASH_SCOPE_ID, id);
+        trip3.execute("FlashBean");
+
+        try {
+            ActionBeanContext tmp = 
trip3.getActionBean(getClass()).getContext();
+            HttpServletResponse response = tmp.getResponse();
+            HttpServletRequest request = tmp.getRequest();
+            Assert.assertNotNull(request);
+            Assert.assertNotNull(response);
+            
Assert.assertTrue(Proxy.class.isAssignableFrom(response.getClass()));
+            Assert.assertEquals(StripesRequestWrapper.class, 
request.getClass());
+            response.isCommitted();
+            Assert.fail(
+                    "Response should have thrown IllegalStateException after 
request cycle complete");
+        }
+        catch (IllegalStateException e) {
+        }
     }
 }


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

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys-and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
_______________________________________________
Stripes-development mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/stripes-development

Reply via email to