SWF-1114 - Consider making ViewActionStateHolder and ViewRootHolder put in flash scope Serializable

This commit is contained in:
Jeremy Grelle
2009-06-24 22:12:49 +00:00
parent 534c0c06da
commit 9b64bac5a8
7 changed files with 99 additions and 9 deletions

View File

@@ -15,6 +15,8 @@
*/
package org.springframework.webflow.engine.support;
import java.io.Serializable;
import org.springframework.web.util.WebUtils;
import org.springframework.webflow.execution.Action;
import org.springframework.webflow.execution.ActionExecutor;
@@ -79,7 +81,7 @@ public class ActionExecutingViewFactory implements ViewFactory {
userEventProcessed = true;
}
public Object getUserEventState() {
public Serializable getUserEventState() {
return null;
}

View File

@@ -16,6 +16,7 @@
package org.springframework.webflow.execution;
import java.io.IOException;
import java.io.Serializable;
import org.springframework.webflow.engine.ViewState;
@@ -24,6 +25,7 @@ import org.springframework.webflow.engine.ViewState;
* and handle the resulting event once the client responds.
*
* @author Keith Donald
* @author Jeremy Grelle
* @see ViewFactory
*/
public interface View {
@@ -74,10 +76,10 @@ public interface View {
/**
* A memento holding the results of processing a user event. Used to allow transient view state such as binding and
* validation errors to survive a flow execution redirect.
* @return the user event state object, or null if no event state needs managing
* @return the serializable user event state object, or null if no event state needs managing
* @see #processUserEvent()
*/
public Object getUserEventState();
public Serializable getUserEventState();
/**
* Saves any state associated with this view out to view scope. Called when exiting a {@link ViewState} to allow for

View File

@@ -16,6 +16,7 @@
package org.springframework.webflow.mvc.view;
import java.io.IOException;
import java.io.Serializable;
import java.lang.reflect.Array;
import java.util.HashMap;
import java.util.Iterator;
@@ -224,7 +225,7 @@ public abstract class AbstractMvcView implements View {
userEventProcessed = true;
}
public Object getUserEventState() {
public Serializable getUserEventState() {
return new ViewActionStateHolder(eventId, userEventProcessed, mappingResults);
}

View File

@@ -15,6 +15,8 @@
*/
package org.springframework.webflow.mvc.view;
import java.io.Serializable;
import org.springframework.binding.mapping.MappingResults;
import org.springframework.core.style.ToStringCreator;
@@ -23,7 +25,7 @@ import org.springframework.core.style.ToStringCreator;
*
* @author Scott Andrews
*/
public class ViewActionStateHolder {
public class ViewActionStateHolder implements Serializable {
public static final String KEY = "webflowViewActionStateHolder";
@@ -31,7 +33,7 @@ public class ViewActionStateHolder {
private boolean userEventProcessed;
private MappingResults mappingResults;
private transient MappingResults mappingResults;
public ViewActionStateHolder(String eventId, boolean userEventProcessed, MappingResults mappingResults) {
this.eventId = eventId;

View File

@@ -16,6 +16,7 @@
package org.springframework.webflow.test;
import java.io.IOException;
import java.io.Serializable;
import org.springframework.binding.convert.ConversionService;
import org.springframework.binding.expression.Expression;
@@ -107,7 +108,7 @@ class MockViewFactoryCreator implements ViewFactoryCreator {
// TODO - implement me as appropriate for a test environment
}
public Object getUserEventState() {
public Serializable getUserEventState() {
return null;
}

View File

@@ -15,6 +15,8 @@
*/
package org.springframework.webflow.engine;
import java.io.Serializable;
import org.springframework.webflow.execution.Event;
import org.springframework.webflow.execution.RequestContext;
import org.springframework.webflow.execution.View;
@@ -22,7 +24,8 @@ import org.springframework.webflow.execution.ViewFactory;
public class StubViewFactory implements ViewFactory {
public static Object USER_EVENT_STATE = new Object();
public static Serializable USER_EVENT_STATE = new Serializable() {
};
public View getView(RequestContext context) {
return new NullView(context);
@@ -47,7 +50,7 @@ public class StubViewFactory implements ViewFactory {
}
public Object getUserEventState() {
public Serializable getUserEventState() {
return USER_EVENT_STATE;
}

View File

@@ -1,6 +1,12 @@
package org.springframework.webflow.mvc.view;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.security.Principal;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
@@ -289,6 +295,79 @@ public class MvcViewTests extends TestCase {
assertEquals("bogus 2", bm.getFieldValue("dateProperty"));
}
public void testResumeEventBindingErrorsRedirectToReplicatedSessionAfterPost() throws Exception {
MockRequestControlContext context = new MockRequestControlContext();
context.putRequestParameter("_eventId", "submit");
context.putRequestParameter("integerProperty", "bogus 1");
context.putRequestParameter("dateProperty", "bogus 2");
BindBean bindBean = new BindBean();
StaticExpression modelObject = new StaticExpression(bindBean);
modelObject.setExpressionString("bindBean");
context.getCurrentState().getAttributes().put("model", modelObject);
context.getFlowScope().put("bindBean", bindBean);
context.getMockExternalContext().setNativeContext(new MockServletContext());
context.getMockExternalContext().setNativeRequest(new MockHttpServletRequest());
context.getMockExternalContext().setNativeResponse(new MockHttpServletResponse());
context.getMockFlowExecutionContext().setKey(new MockFlowExecutionKey("c1v1"));
org.springframework.web.servlet.View mvcView = new MockView();
AbstractMvcView view = new MockMvcView(mvcView, context);
view.setExpressionParser(DefaultExpressionParserFactory.getExpressionParser());
view.setMessageCodesResolver(new WebFlowMessageCodesResolver());
context.setAlwaysRedirectOnPause(true);
assertTrue(view.userEventQueued());
view.processUserEvent();
assertFalse(view.userEventQueued());
assertFalse(view.hasFlowEvent());
Object viewActionState = view.getUserEventState();
assertNotNull(viewActionState);
viewActionState = saveAndRestoreViewActionState(viewActionState);
MockRequestControlContext context2 = new MockRequestControlContext();
context2.getFlashScope().put(org.springframework.webflow.execution.View.USER_EVENT_STATE_ATTRIBUTE,
viewActionState);
BindBean bindBean2 = new BindBean();
StaticExpression modelObject2 = new StaticExpression(bindBean2);
modelObject2.setExpressionString("bindBean");
context2.getCurrentState().getAttributes().put("model", modelObject);
context2.getFlowScope().put("bindBean", bindBean);
context2.getMockExternalContext().setNativeContext(new MockServletContext());
context2.getMockExternalContext().setNativeRequest(new MockHttpServletRequest());
context2.getMockExternalContext().setNativeResponse(new MockHttpServletResponse());
context2.getMockFlowExecutionContext().setKey(new MockFlowExecutionKey("c1v1"));
AbstractMvcView view2 = new MockMvcView(mvcView, context2);
view2.setExpressionParser(DefaultExpressionParserFactory.getExpressionParser());
view2.setMessageCodesResolver(new WebFlowMessageCodesResolver());
view2.restoreState((ViewActionStateHolder) viewActionState);
assertFalse(view2.userEventQueued());
view2.render();
assertEquals(context2.getFlowScope().get("bindBean"), model.get("bindBean"));
BindingModel bm = (BindingModel) model.get(BindingResult.MODEL_KEY_PREFIX + "bindBean");
assertNotNull(bm);
assertEquals(new Integer(3), bm.getFieldValue("integerProperty"));
assertEquals(new SimpleDateFormat("MM-dd-yyyy").parse("01-01-2008"), bm.getFieldValue("dateProperty"));
}
private Object saveAndRestoreViewActionState(Object viewActionState) throws Exception {
File tempFile = new File("serializable.tmp");
FileOutputStream fos = new FileOutputStream(tempFile);
ObjectOutputStream objOut = new ObjectOutputStream(fos);
objOut.writeObject(viewActionState);
objOut.close();
FileInputStream fis = new FileInputStream(tempFile);
ObjectInputStream objIn = new ObjectInputStream(fis);
Object restoredState = objIn.readObject();
objIn.close();
tempFile.delete();
assertNotSame(viewActionState, restoredState);
return restoredState;
}
public void testResumeEventModelBindingAllowedFields() throws Exception {
MockRequestContext context = new MockRequestContext();
context.putRequestParameter("_eventId", "submit");