SWF-1114 - Consider making ViewActionStateHolder and ViewRootHolder put in flash scope Serializable
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user