view polishing

This commit is contained in:
Keith Donald
2008-04-02 15:36:30 +00:00
parent 49732977d7
commit bba2b4ed95
13 changed files with 110 additions and 76 deletions

View File

@@ -81,7 +81,7 @@ public class JsfView implements View {
}
}
public void resume() {
public void processUserEvent() {
FacesContext facesContext = FlowFacesContext.newInstance(context, facesLifecycle);
facesContext.setViewRoot(viewRoot);
try {
@@ -95,11 +95,11 @@ public class JsfView implements View {
}
public boolean eventSignaled() {
public boolean hasFlowEvent() {
return context.getExternalContext().getRequestMap().contains(EVENT_KEY);
}
public Event getEvent() {
public Event getFlowEvent() {
String eventId = (String) context.getExternalContext().getRequestMap().get(EVENT_KEY);
return new Event(this, eventId);
}

View File

@@ -107,7 +107,7 @@ public class JsfViewFactoryTests extends TestCase {
assertNotNull("A View was not created", newView);
assertTrue("A JsfView was expected", newView instanceof JsfView);
assertEquals("View name did not match", VIEW_ID, ((JsfView) newView).getViewRoot().getViewId());
assertFalse("An unexpected event was signaled,", newView.eventSignaled());
assertFalse("An unexpected event was signaled,", newView.hasFlowEvent());
}
/**
@@ -130,7 +130,7 @@ public class JsfViewFactoryTests extends TestCase {
assertNotNull("A View was not restored", restoredView);
assertTrue("A JsfView was expected", restoredView instanceof JsfView);
assertEquals("View name did not match", VIEW_ID, ((JsfView) restoredView).getViewRoot().getViewId());
assertFalse("An unexpected event was signaled,", restoredView.eventSignaled());
assertFalse("An unexpected event was signaled,", restoredView.hasFlowEvent());
}
/**
@@ -159,7 +159,7 @@ public class JsfViewFactoryTests extends TestCase {
assertTrue("A JsfView was expected", restoredView instanceof JsfView);
assertTrue("An AjaxViewRoot was not set", ((JsfView) restoredView).getViewRoot() instanceof AjaxViewRoot);
assertEquals("View name did not match", VIEW_ID, ((JsfView) restoredView).getViewRoot().getViewId());
assertFalse("An unexpected event was signaled,", restoredView.eventSignaled());
assertFalse("An unexpected event was signaled,", restoredView.hasFlowEvent());
}
/**
@@ -184,7 +184,7 @@ public class JsfViewFactoryTests extends TestCase {
assertTrue("A JsfView was expected", newView instanceof JsfView);
assertEquals("View name did not match", VIEW_ID, ((JsfView) newView).getViewRoot().getViewId());
assertSame("View root was not the third party instance", newRoot, ((JsfView) newView).getViewRoot());
assertFalse("An unexpected event was signaled,", newView.eventSignaled());
assertFalse("An unexpected event was signaled,", newView.hasFlowEvent());
}
private class NoExecutionLifecycle extends FlowLifecycle {

View File

@@ -152,9 +152,9 @@ public class JsfViewTests extends TestCase {
JsfView restoredView = new JsfView(existingRoot, lifecycle, context);
restoredView.setRestored(true);
restoredView.resume();
restoredView.processUserEvent();
assertFalse("An unexpected event was signaled,", restoredView.eventSignaled());
assertFalse("An unexpected event was signaled,", restoredView.hasFlowEvent());
assertTrue("The lifecycle should have been invoked", ((NoEventLifecycle) lifecycle).executed);
}
@@ -182,9 +182,9 @@ public class JsfViewTests extends TestCase {
JsfView restoredView = new JsfView(ajaxRoot, lifecycle, context);
restoredView.setRestored(true);
restoredView.resume();
restoredView.processUserEvent();
assertFalse("An unexpected event was signaled,", restoredView.eventSignaled());
assertFalse("An unexpected event was signaled,", restoredView.hasFlowEvent());
assertTrue("The lifecycle should have been invoked", ((NoEventLifecycle) lifecycle).executed);
}
@@ -210,10 +210,10 @@ public class JsfViewTests extends TestCase {
JsfView restoredView = new JsfView(existingRoot, lifecycle, context);
restoredView.setRestored(true);
restoredView.resume();
restoredView.processUserEvent();
assertTrue("No event was signaled,", restoredView.eventSignaled());
assertEquals("Event should be " + event, event, restoredView.getEvent().getId());
assertTrue("No event was signaled,", restoredView.hasFlowEvent());
assertEquals("Event should be " + event, event, restoredView.getFlowEvent().getId());
assertTrue("The lifecycle should have been invoked", ((EventSignalingLifecycle) lifecycle).executed);
}

View File

@@ -183,11 +183,11 @@ public class ViewState extends TransitionableState {
public void resume(RequestControlContext context) {
restoreVariables(context);
View view = viewFactory.getView(context);
view.resume();
if (view.eventSignaled()) {
Event event = view.getEvent();
view.processUserEvent();
if (view.hasFlowEvent()) {
Event event = view.getFlowEvent();
if (logger.isDebugEnabled()) {
logger.debug("Event '" + event.getId() + "' signaled on view " + view);
logger.debug("Event '" + event.getId() + "' returned from view " + view);
}
boolean stateExited = context.handleEvent(event);
if (!stateExited && context.getExternalContext().isResponseAllowed()) {

View File

@@ -66,15 +66,15 @@ public class ActionExecutingViewFactory implements ViewFactory {
}
}
public void resume() {
public void processUserEvent() {
}
public boolean eventSignaled() {
public boolean hasFlowEvent() {
return context.getExternalContext().getRequestParameterMap().contains("_eventId");
}
public Event getEvent() {
public Event getFlowEvent() {
return new Event(this, context.getExternalContext().getRequestParameterMap().get("_eventId"));
}

View File

@@ -40,19 +40,19 @@ public interface View {
/**
* Execute the view resume lifecycle. This typically results in a view model binding and validation.
*/
public void resume();
public void processUserEvent();
/**
* Returns true if an event occurred the flow system should handle.
* @return true if yes, false otherwise
*/
public boolean eventSignaled();
public boolean hasFlowEvent();
/**
* Get the user event the flow should handle. Returns an event object when {@link #eventSignaled()} returns true.
* Returns null otherwise
* Get the user event the flow should handle. Returns an event object when {@link #hasFlowEvent()} returns
* true. Returns null otherwise
* @return the event, or null if there is no event for the flow system to handle
*/
public Event getEvent();
public Event getFlowEvent();
}

View File

@@ -23,28 +23,36 @@ import javax.portlet.RenderResponse;
import org.springframework.context.ApplicationContext;
import org.springframework.web.portlet.DispatcherPortlet;
import org.springframework.web.servlet.View;
import org.springframework.web.servlet.ViewRendererServlet;
import org.springframework.webflow.context.ExternalContext;
import org.springframework.webflow.execution.RequestContext;
import org.springframework.webflow.mvc.view.MvcView;
/**
* Spring Web Portlet MVC view implementation.
* @author Keith Donald
* @author Scott Andrews
*/
public class PortletMvcView extends MvcView {
private ApplicationContext applicationContext;
/**
* Creates a new portlet view.
* @param view the view to render
* @param context the current flow request context
* @param applicationContext the application context
*/
public PortletMvcView(org.springframework.web.servlet.View view, RequestContext context,
ApplicationContext applicationContext) {
super(view, context);
this.applicationContext = applicationContext;
}
public void render(Map model, ExternalContext context) throws Exception {
public void doRender(org.springframework.web.servlet.View view, Map model, ExternalContext context) throws Exception {
PortletContext portletContext = (PortletContext) context.getNativeContext();
RenderRequest request = (RenderRequest) context.getNativeRequest();
RenderResponse response = (RenderResponse) context.getNativeResponse();
View view = getView();
// Set the content type on the response if needed and if possible.
// The Portlet spec requires the content type to be set on the RenderResponse;
// it's not sufficient to let the View set it on the ServletResponse.
@@ -55,14 +63,11 @@ public class PortletMvcView extends MvcView {
response.setContentType(contentType);
}
}
// Expose Portlet ApplicationContext to view objects.
request.setAttribute(ViewRendererServlet.WEB_APPLICATION_CONTEXT_ATTRIBUTE, applicationContext);
// These attributes are required by the ViewRendererServlet.
request.setAttribute(ViewRendererServlet.VIEW_ATTRIBUTE, view);
request.setAttribute(ViewRendererServlet.MODEL_ATTRIBUTE, model);
// Include the content of the view in the render response.
portletContext.getRequestDispatcher(DispatcherPortlet.DEFAULT_VIEW_RENDERER_URL).include(request, response);
}

View File

@@ -24,15 +24,24 @@ import org.springframework.webflow.context.ExternalContext;
import org.springframework.webflow.execution.RequestContext;
import org.springframework.webflow.mvc.view.MvcView;
/**
* Creates a new Spring Web Servlet MVC view.
* @author Keith Donald
*/
public class ServletMvcView extends MvcView {
/**
* Creates a new servlet view.
* @param view the view to render
* @param context the current flow request context.
*/
public ServletMvcView(org.springframework.web.servlet.View view, RequestContext context) {
super(view, context);
}
public void render(Map model, ExternalContext context) throws Exception {
getView().render(model, (HttpServletRequest) context.getNativeRequest(),
(HttpServletResponse) context.getNativeResponse());
public void doRender(org.springframework.web.servlet.View view, Map model, ExternalContext context) throws Exception {
view.render(model, (HttpServletRequest) context.getNativeRequest(), (HttpServletResponse) context
.getNativeResponse());
}
}

View File

@@ -55,6 +55,11 @@ import org.springframework.webflow.execution.RequestContext;
import org.springframework.webflow.execution.View;
import org.springframework.webflow.expression.DefaultExpressionParserFactory;
/**
* Base view implementation for the Spring Web MVC Servlet and Spring Web MVC Portlet frameworks.
*
* @author Keith Donald
*/
public abstract class MvcView implements View {
private static final MappingResultsCriteria PROPERTY_NOT_FOUND_ERROR = new PropertyNotFoundError();
@@ -75,15 +80,28 @@ public abstract class MvcView implements View {
private String eventId;
/**
* Creates a new MVC view.
* @param view the Spring MVC view to render
* @param context the current flow request context
*/
public MvcView(org.springframework.web.servlet.View view, RequestContext context) {
this.view = view;
this.context = context;
}
/**
* Sets the expression parser to use to parse model expressions.
* @param expressionParser the expression parser
*/
public void setExpressionParser(ExpressionParser expressionParser) {
this.expressionParser = expressionParser;
}
/**
* Sets the formatter registry to use to expose formatters for field values.
* @param formatterRegistry the formatter registry
*/
public void setFormatterRegistry(FormatterRegistry formatterRegistry) {
this.formatterRegistry = formatterRegistry;
}
@@ -98,20 +116,27 @@ public abstract class MvcView implements View {
model.put("currentUser", context.getExternalContext().getCurrentUser());
// TODO expose flow context to mvc view
try {
render(model, context.getExternalContext());
doRender(view, model, context.getExternalContext());
} catch (IOException e) {
throw e;
} catch (Exception e) {
throw new RuntimeException("Unexpected exception occurred rendering view " + view, e);
throw new IllegalStateException("Unexpected exception occurred rendering view " + view, e);
}
}
public abstract void render(Map model, ExternalContext context) throws Exception;
/**
* Template method subclasses should override to execute the view rendering logic.
* @param view the MVC view to render
* @param model the view model data
* @param context the flow external context, providing access to the request and response
* @throws Exception an exception occurred rendering the view
*/
protected abstract void doRender(org.springframework.web.servlet.View view, Map model, ExternalContext context)
throws Exception;
public void resume() {
public void processUserEvent() {
determineEventId(context);
if (eventId == null) {
// nothing to do
return;
}
Object model = getModelObject();
@@ -132,12 +157,12 @@ public abstract class MvcView implements View {
}
}
public boolean eventSignaled() {
public boolean hasFlowEvent() {
return eventId != null && !viewErrors;
}
public Event getEvent() {
if (!eventSignaled()) {
public Event getFlowEvent() {
if (!hasFlowEvent()) {
return null;
}
return new Event(this, eventId, context.getRequestParameters().asAttributeMap());
@@ -300,10 +325,6 @@ public abstract class MvcView implements View {
return null;
}
protected org.springframework.web.servlet.View getView() {
return view;
}
private static class PropertyNotFoundError implements MappingResultsCriteria {
public boolean test(MappingResult result) {
return result.getResult().isError() && "propertyNotFound".equals(result.getResult().getErrorCode());

View File

@@ -94,15 +94,15 @@ class MockViewFactoryCreator implements ViewFactoryCreator {
return viewId;
}
public void resume() {
public void processUserEvent() {
// TODO - implement me as appropriate for a test environment
}
public boolean eventSignaled() {
public boolean hasFlowEvent() {
return context.getRequestParameters().contains("_eventId");
}
public Event getEvent() {
public Event getFlowEvent() {
return new Event(this, context.getRequestParameters().get("_eventId"));
}

View File

@@ -37,15 +37,15 @@ public class StubViewFactory implements ViewFactory {
context.getFlowScope().put("renderCalled", Boolean.TRUE);
}
public void resume() {
public void processUserEvent() {
}
public boolean eventSignaled() {
public boolean hasFlowEvent() {
return context.getExternalContext().getRequestParameterMap().contains("_eventId");
}
public Event getEvent() {
public Event getFlowEvent() {
return new Event(this, context.getExternalContext().getRequestParameterMap().get("_eventId"));
}
}

View File

@@ -61,7 +61,7 @@ public class MvcViewFactoryTests extends TestCase {
context.setExternalContext(externalContext);
context.getMockFlowExecutionContext().setKey(new GeneratedFlowExecutionKey());
View view = viewFactory.getView(context);
assertEquals(false, view.eventSignaled());
assertEquals(false, view.hasFlowEvent());
view.render();
assertEquals("/parent/myview.jsp", response.getForwardedUrl());
}
@@ -81,7 +81,7 @@ public class MvcViewFactoryTests extends TestCase {
context.setExternalContext(externalContext);
context.getMockFlowExecutionContext().setKey(new GeneratedFlowExecutionKey());
View view = viewFactory.getView(context);
assertEquals(false, view.eventSignaled());
assertEquals(false, view.hasFlowEvent());
view.render();
assertEquals("myview", response.getForwardedUrl());
}
@@ -109,9 +109,9 @@ public class MvcViewFactoryTests extends TestCase {
context.setExternalContext(externalContext);
context.getMockFlowExecutionContext().setKey(new GeneratedFlowExecutionKey());
View view = viewFactory.getView(context);
view.resume();
assertEquals(true, view.eventSignaled());
Event e = view.getEvent();
view.processUserEvent();
assertEquals(true, view.hasFlowEvent());
Event e = view.getFlowEvent();
assertEquals(view, e.getSource());
assertEquals("foo", e.getId());
view.render();
@@ -141,9 +141,9 @@ public class MvcViewFactoryTests extends TestCase {
context.setExternalContext(externalContext);
context.getMockFlowExecutionContext().setKey(new GeneratedFlowExecutionKey());
View view = viewFactory.getView(context);
view.resume();
assertEquals(true, view.eventSignaled());
Event e = view.getEvent();
view.processUserEvent();
assertEquals(true, view.hasFlowEvent());
Event e = view.getFlowEvent();
assertEquals(view, e.getSource());
assertEquals("foo", e.getId());
view.render();

View File

@@ -21,8 +21,6 @@ import org.springframework.validation.BindingResult;
import org.springframework.web.servlet.View;
import org.springframework.webflow.context.ExternalContext;
import org.springframework.webflow.execution.RequestContext;
import org.springframework.webflow.mvc.view.BindingModel;
import org.springframework.webflow.mvc.view.MvcView;
import org.springframework.webflow.test.MockFlowExecutionKey;
import org.springframework.webflow.test.MockRequestContext;
@@ -99,9 +97,9 @@ public class MvcViewTests extends TestCase {
context.getMockFlowExecutionContext().setKey(new MockFlowExecutionKey("c1v1"));
org.springframework.web.servlet.View mvcView = new MockView();
MvcView view = new MockMvcView(mvcView, context);
view.resume();
assertFalse(view.eventSignaled());
assertNull(view.getEvent());
view.processUserEvent();
assertFalse(view.hasFlowEvent());
assertNull(view.getFlowEvent());
}
public void testResumeEventNoModelBinding() throws Exception {
@@ -114,9 +112,9 @@ public class MvcViewTests extends TestCase {
org.springframework.web.servlet.View mvcView = new MockView();
MvcView view = new MockMvcView(mvcView, context);
view.setFormatterRegistry(formatterRegistry);
view.resume();
assertTrue(view.eventSignaled());
assertEquals("submit", view.getEvent().getId());
view.processUserEvent();
assertTrue(view.hasFlowEvent());
assertEquals("submit", view.getFlowEvent().getId());
}
public void testResumeEventModelBinding() throws Exception {
@@ -137,9 +135,9 @@ public class MvcViewTests extends TestCase {
org.springframework.web.servlet.View mvcView = new MockView();
MvcView view = new MockMvcView(mvcView, context);
view.setFormatterRegistry(formatterRegistry);
view.resume();
assertTrue(view.eventSignaled());
assertEquals("submit", view.getEvent().getId());
view.processUserEvent();
assertTrue(view.hasFlowEvent());
assertEquals("submit", view.getFlowEvent().getId());
assertEquals("foo", bindBean.getStringProperty());
assertEquals(new Integer(5), bindBean.getIntegerProperty());
Calendar cal = Calendar.getInstance();
@@ -154,9 +152,10 @@ public class MvcViewTests extends TestCase {
super(view, context);
}
public void render(Map model, ExternalContext context) throws Exception {
getView().render(model, (HttpServletRequest) context.getNativeRequest(),
(HttpServletResponse) context.getNativeResponse());
protected void doRender(org.springframework.web.servlet.View view, Map model, ExternalContext context)
throws Exception {
view.render(model, (HttpServletRequest) context.getNativeRequest(), (HttpServletResponse) context
.getNativeResponse());
}
}