From 89242f19fc87b4c491fbbbf9805ef71adbfb20bb Mon Sep 17 00:00:00 2001 From: Keith Donald Date: Wed, 23 Apr 2008 22:58:04 +0000 Subject: [PATCH] portlet refinements --- .../mvc/portlet/AbstractFlowHandler.java | 16 +-- .../webflow/mvc/portlet/FlowHandler.java | 20 +-- .../mvc/portlet/FlowHandlerAdapter.java | 117 +++++++++--------- .../mvc/portlet/FlowHandlerAdapterTests.java | 48 +++---- 4 files changed, 103 insertions(+), 98 deletions(-) diff --git a/spring-webflow/src/main/java/org/springframework/webflow/mvc/portlet/AbstractFlowHandler.java b/spring-webflow/src/main/java/org/springframework/webflow/mvc/portlet/AbstractFlowHandler.java index 036500fc..ef285000 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/mvc/portlet/AbstractFlowHandler.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/mvc/portlet/AbstractFlowHandler.java @@ -15,11 +15,11 @@ */ package org.springframework.webflow.mvc.portlet; -import javax.portlet.PortletRequest; +import javax.portlet.ActionRequest; +import javax.portlet.ActionResponse; import javax.portlet.RenderRequest; import javax.portlet.RenderResponse; -import org.springframework.web.portlet.ModelAndView; import org.springframework.webflow.core.FlowException; import org.springframework.webflow.core.collection.MutableAttributeMap; import org.springframework.webflow.execution.FlowExecutionOutcome; @@ -32,19 +32,19 @@ import org.springframework.webflow.execution.FlowExecutionOutcome; */ public class AbstractFlowHandler implements FlowHandler { - public MutableAttributeMap createExecutionInputMap(PortletRequest request) { - return null; - } - public String getFlowId() { return null; } - public ModelAndView handleException(FlowException e, RenderRequest request, RenderResponse response) { + public MutableAttributeMap createExecutionInputMap(RenderRequest request) { return null; } - public String handleFlowOutcome(FlowExecutionOutcome outcome, RenderRequest request, RenderResponse response) { + public boolean handleExecutionOutcome(FlowExecutionOutcome outcome, ActionRequest request, ActionResponse response) { + return false; + } + + public String handleException(FlowException e, RenderRequest request, RenderResponse response) { return null; } diff --git a/spring-webflow/src/main/java/org/springframework/webflow/mvc/portlet/FlowHandler.java b/spring-webflow/src/main/java/org/springframework/webflow/mvc/portlet/FlowHandler.java index 894cea50..81f67e28 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/mvc/portlet/FlowHandler.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/mvc/portlet/FlowHandler.java @@ -15,11 +15,12 @@ */ package org.springframework.webflow.mvc.portlet; -import javax.portlet.PortletRequest; +import javax.portlet.ActionRequest; +import javax.portlet.ActionResponse; +import javax.portlet.PortletModeException; import javax.portlet.RenderRequest; import javax.portlet.RenderResponse; -import org.springframework.web.portlet.ModelAndView; import org.springframework.webflow.core.FlowException; import org.springframework.webflow.core.collection.MutableAttributeMap; import org.springframework.webflow.execution.FlowExecutionOutcome; @@ -50,17 +51,18 @@ public interface FlowHandler { * @param request the current request * @return the input map */ - public MutableAttributeMap createExecutionInputMap(PortletRequest request); + public MutableAttributeMap createExecutionInputMap(RenderRequest request); /** - * Handles a specific flow execution outcome. Used to select a new view to render after the flow ends. + * Handles a specific flow execution outcome. Used to change portlet modes after the flow ends. * @param outcome the outcome that was reached * @param request the current render request * @param response the current render response - * @return the id of the flow to start after handling the outcome, or null if the outcome should be handled by the - * caller + * @return whether this outcome was handled, or whether the caller should handle it + * @throws PortletModeException if this handler tries to change the portlet mode to something invalid */ - public String handleFlowOutcome(FlowExecutionOutcome outcome, RenderRequest request, RenderResponse response); + public boolean handleExecutionOutcome(FlowExecutionOutcome outcome, ActionRequest request, ActionResponse response) + throws PortletModeException; /** * Handles a flow exception that was not handled by the Web Flow system. Used by a Controller to handle a specific @@ -69,8 +71,8 @@ public interface FlowHandler { * the flow executor system if no execution could be restored. * @param request the current request * @param response the current response - * @return the model and view to render on the occurrence of this exception, or null if the exception is not handled + * @return the name of a specific error view to render, or null if the exception should be handled by the caller */ - public ModelAndView handleException(FlowException e, RenderRequest request, RenderResponse response); + public String handleException(FlowException e, RenderRequest request, RenderResponse response); } diff --git a/spring-webflow/src/main/java/org/springframework/webflow/mvc/portlet/FlowHandlerAdapter.java b/spring-webflow/src/main/java/org/springframework/webflow/mvc/portlet/FlowHandlerAdapter.java index 82712bd5..c15415f9 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/mvc/portlet/FlowHandlerAdapter.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/mvc/portlet/FlowHandlerAdapter.java @@ -21,6 +21,7 @@ import java.util.Map; import javax.portlet.ActionRequest; import javax.portlet.ActionResponse; +import javax.portlet.PortletModeException; import javax.portlet.PortletRequest; import javax.portlet.PortletResponse; import javax.portlet.PortletSession; @@ -43,9 +44,7 @@ import org.springframework.webflow.executor.FlowExecutor; public class FlowHandlerAdapter extends PortletApplicationObjectSupport implements HandlerAdapter { - private static final String ACTION_FLOW_EXCEPTION_ATTRIBUTE = "actionFlowException"; - - private static final String FLOW_EXECUTION_RESULT_ATTRIBUTE = "flowExecutionResult"; + private static final String ACTION_REQUEST_FLOW_EXCEPTION_ATTRIBUTE = "actionRequestFlowException"; private FlowExecutor flowExecutor; @@ -65,41 +64,22 @@ public class FlowHandlerAdapter extends PortletApplicationObjectSupport implemen populateConveniencePortletProperties(request); PortletSession session = request.getPortletSession(false); if (session != null) { - FlowException e = (FlowException) session.getAttribute(ACTION_FLOW_EXCEPTION_ATTRIBUTE); + FlowException e = (FlowException) session.getAttribute(ACTION_REQUEST_FLOW_EXCEPTION_ATTRIBUTE); if (e != null) { - session.removeAttribute(ACTION_FLOW_EXCEPTION_ATTRIBUTE); - ModelAndView mv = flowHandler.handleException(e, request, response); - return mv != null ? mv : defaultHandleResumeFlowException(flowHandler, e, request, response); + session.removeAttribute(ACTION_REQUEST_FLOW_EXCEPTION_ATTRIBUTE); + return handleException(e, flowHandler, request, response); } } String flowExecutionKey = urlHandler.getFlowExecutionKey(request); if (flowExecutionKey != null) { - PortletExternalContext context = createPortletExternalContext(request, response); - try { - flowExecutor.resumeExecution(flowExecutionKey, context); - return null; - } catch (FlowException e) { - ModelAndView mv = flowHandler.handleException(e, request, response); - return mv != null ? mv : defaultHandleResumeFlowException(flowHandler, e, request, response); - } + return resumeFlow(flowExecutionKey, flowHandler, request, response); } else { - if (session != null) { - FlowExecutionResult result = (FlowExecutionResult) session - .getAttribute(FLOW_EXECUTION_RESULT_ATTRIBUTE); - if (result != null) { - session.removeAttribute(FLOW_EXECUTION_RESULT_ATTRIBUTE); - String flowId = flowHandler.handleFlowOutcome(result.getOutcome(), request, response); - return defaultHandleFlowOutcome(flowHandler, result.getOutcome(), flowId, request, response); - } else { - return startFlow(request, response, flowHandler); - } - } else { - return startFlow(request, response, flowHandler); - } + return startFlow(flowHandler, request, response); } } public void handleAction(ActionRequest request, ActionResponse response, Object handler) throws Exception { + FlowHandler flowHandler = (FlowHandler) handler; populateConveniencePortletProperties(request); String flowExecutionKey = urlHandler.getFlowExecutionKey(request); PortletExternalContext context = createPortletExternalContext(request, response); @@ -107,11 +87,13 @@ public class FlowHandlerAdapter extends PortletApplicationObjectSupport implemen FlowExecutionResult result = flowExecutor.resumeExecution(flowExecutionKey, context); if (result.isPaused()) { urlHandler.setFlowExecutionRenderParameter(result.getPausedKey(), response); + } else if (result.isEnded()) { + handleFlowExecutionOutcome(result.getOutcome(), flowHandler, request, response); } else { - request.getPortletSession().setAttribute(FLOW_EXECUTION_RESULT_ATTRIBUTE, result); + throw new IllegalStateException("Execution result should have been one of [paused] or [ended]"); } } catch (FlowException e) { - request.getPortletSession().setAttribute(ACTION_FLOW_EXCEPTION_ATTRIBUTE, e); + request.getPortletSession().setAttribute(ACTION_REQUEST_FLOW_EXCEPTION_ATTRIBUTE, e); } } @@ -126,7 +108,7 @@ public class FlowHandlerAdapter extends PortletApplicationObjectSupport implemen return new PortletExternalContext(getPortletContext(), request, response); } - protected MutableAttributeMap defaultFlowExecutionInputMap(PortletRequest request) { + protected MutableAttributeMap defaultCreateFlowExecutionInputMap(PortletRequest request) { LocalAttributeMap inputMap = new LocalAttributeMap(); Map parameterMap = request.getParameterMap(); Iterator it = parameterMap.entrySet().iterator(); @@ -143,29 +125,19 @@ public class FlowHandlerAdapter extends PortletApplicationObjectSupport implemen return inputMap; } - protected ModelAndView defaultHandleFlowOutcome(FlowHandler flowHandler, FlowExecutionOutcome outcome, - String nextFlowId, RenderRequest request, RenderResponse response) throws IOException { - if (nextFlowId == null) { - nextFlowId = flowHandler.getFlowId(); - } - if (logger.isDebugEnabled()) { - logger.debug("Starting a new execution of flow '" + nextFlowId + "'"); - } - PortletExternalContext context = createPortletExternalContext(request, response); - flowExecutor.launchExecution(nextFlowId, new LocalAttributeMap(outcome.getOutput().asMap()), context); - return null; + protected void defaultHandleExecutionOutcome(FlowExecutionOutcome outcome, FlowHandler flowHandler, + ActionRequest request, ActionResponse response) throws PortletModeException { } - protected ModelAndView defaultHandleResumeFlowException(FlowHandler flowHandler, FlowException e, - RenderRequest request, RenderResponse response) throws IOException { + protected ModelAndView defaultHandleException(FlowHandler flowHandler, FlowException e, RenderRequest request, + RenderResponse response) { if (e instanceof NoSuchFlowExecutionException) { - String flowId = flowHandler.getFlowId(); if (logger.isDebugEnabled()) { - logger.debug("Restarting a new execution of previously expired/ended flow '" + flowId + "'"); + logger.debug("Restarting a new execution of previously expired/ended flow '" + flowHandler.getFlowId() + + "'"); } // by default, attempt to restart the flow - PortletExternalContext context = createPortletExternalContext(request, response); - flowExecutor.launchExecution(flowId, null, context); + startFlow(flowHandler, null, request, response); return null; } else { throw e; @@ -174,12 +146,34 @@ public class FlowHandlerAdapter extends PortletApplicationObjectSupport implemen // helpers - private ModelAndView startFlow(RenderRequest request, RenderResponse response, FlowHandler flowHandler) - throws Exception { + private ModelAndView handleException(FlowException e, FlowHandler flowHandler, RenderRequest request, + RenderResponse response) { + String viewName = flowHandler.handleException(e, request, response); + if (viewName != null) { + return new ModelAndView(viewName); + } else { + return defaultHandleException(flowHandler, e, request, response); + } + } + + private void handleFlowExecutionOutcome(FlowExecutionOutcome outcome, FlowHandler flowHandler, + ActionRequest request, ActionResponse response) throws PortletModeException { + boolean handled = flowHandler.handleExecutionOutcome(outcome, request, response); + if (!handled) { + defaultHandleExecutionOutcome(outcome, flowHandler, request, response); + } + } + + private ModelAndView startFlow(FlowHandler flowHandler, RenderRequest request, RenderResponse response) { MutableAttributeMap input = flowHandler.createExecutionInputMap(request); if (input == null) { - input = defaultFlowExecutionInputMap(request); + input = defaultCreateFlowExecutionInputMap(request); } + return startFlow(flowHandler, input, request, response); + } + + private ModelAndView startFlow(FlowHandler flowHandler, MutableAttributeMap input, RenderRequest request, + RenderResponse response) { PortletExternalContext context = createPortletExternalContext(request, response); try { FlowExecutionResult result = flowExecutor.launchExecution(flowHandler.getFlowId(), input, context); @@ -188,12 +182,19 @@ public class FlowHandlerAdapter extends PortletApplicationObjectSupport implemen } return null; } catch (FlowException e) { - ModelAndView mv = flowHandler.handleException(e, request, response); - if (mv != null) { - return mv; - } else { - throw e; - } + return handleException(e, flowHandler, request, response); } } -} + + private ModelAndView resumeFlow(String flowExecutionKey, FlowHandler flowHandler, RenderRequest request, + RenderResponse response) throws IOException { + PortletExternalContext context = createPortletExternalContext(request, response); + try { + flowExecutor.resumeExecution(flowExecutionKey, context); + return null; + } catch (FlowException e) { + return handleException(e, flowHandler, request, response); + } + } + +} \ No newline at end of file diff --git a/spring-webflow/src/test/java/org/springframework/webflow/mvc/portlet/FlowHandlerAdapterTests.java b/spring-webflow/src/test/java/org/springframework/webflow/mvc/portlet/FlowHandlerAdapterTests.java index 29b166f2..7b007eb5 100644 --- a/spring-webflow/src/test/java/org/springframework/webflow/mvc/portlet/FlowHandlerAdapterTests.java +++ b/spring-webflow/src/test/java/org/springframework/webflow/mvc/portlet/FlowHandlerAdapterTests.java @@ -1,6 +1,7 @@ package org.springframework.webflow.mvc.portlet; import javax.portlet.ActionRequest; +import javax.portlet.ActionResponse; import javax.portlet.PortletRequest; import javax.portlet.PortletResponse; import javax.portlet.PortletSession; @@ -43,6 +44,7 @@ public class FlowHandlerAdapterTests extends TestCase { private LocalAttributeMap flowInput = new LocalAttributeMap(); private boolean handleException; private boolean handleExecutionOutcome; + private boolean handleExecutionOutcomeCalled; protected void setUp() { executor = (FlowExecutor) EasyMock.createMock(FlowExecutor.class); @@ -68,25 +70,27 @@ public class FlowHandlerAdapterTests extends TestCase { controller.setApplicationContext(new StaticWebApplicationContext()); controller.setPortletContext(portletContext); flowHandler = new FlowHandler() { - public MutableAttributeMap createExecutionInputMap(PortletRequest request) { - return null; - } - public String getFlowId() { return "foo"; } - public ModelAndView handleException(FlowException e, RenderRequest request, RenderResponse response) { - if (handleException) { - return new ModelAndView("error"); + public MutableAttributeMap createExecutionInputMap(RenderRequest request) { + return null; + } + + public boolean handleExecutionOutcome(FlowExecutionOutcome outcome, ActionRequest request, + ActionResponse response) { + handleExecutionOutcomeCalled = true; + if (handleExecutionOutcome) { + return true; } else { - return null; + return false; } } - public String handleFlowOutcome(FlowExecutionOutcome outcome, RenderRequest request, RenderResponse response) { - if (handleExecutionOutcome) { - return "home"; + public String handleException(FlowException e, RenderRequest request, RenderResponse response) { + if (handleException) { + return "error"; } else { return null; } @@ -144,7 +148,7 @@ public class FlowHandlerAdapterTests extends TestCase { PortletSession session = renderRequest.getPortletSession(); final FlowException flowException = new FlowException("Error") { }; - session.setAttribute("actionFlowException", flowException); + session.setAttribute("actionRequestFlowException", flowException); try { controller.handleRender(renderRequest, renderResponse, flowHandler); fail("Should have thrown exception"); @@ -161,28 +165,25 @@ public class FlowHandlerAdapterTests extends TestCase { EasyMock.expectLastCall().andThrow(flowException); EasyMock.replay(new Object[] { executor }); controller.handleAction(actionRequest, actionResponse, flowHandler); - assertNotNull(actionRequest.getPortletSession().getAttribute("actionFlowException")); + assertNotNull(actionRequest.getPortletSession().getAttribute("actionRequestFlowException")); EasyMock.verify(new Object[] { executor }); - Exception e = (Exception) actionRequest.getPortletSession().getAttribute("actionFlowException"); + Exception e = (Exception) actionRequest.getPortletSession().getAttribute("actionRequestFlowException"); assertTrue(e instanceof NoSuchFlowExecutionException); } public void testHandleFlowOutcomeCustomFlowHandler() throws Exception { handleExecutionOutcome = true; - renderRequest.setContextPath("/springtravel"); + actionRequest.setContextPath("/springtravel"); + actionRequest.addParameter("execution", "12345"); LocalAttributeMap output = new LocalAttributeMap(); output.put("bar", "baz"); FlowExecutionOutcome outcome = new FlowExecutionOutcome("finish", output); - FlowExecutionResult result = FlowExecutionResult.createEndedResult("foo", outcome); - PortletSession session = renderRequest.getPortletSession(); - session.setAttribute("flowExecutionResult", result); - executor.launchExecution("home", output, renderContext); + executor.resumeExecution("12345", actionContext); EasyMock.expectLastCall().andReturn(FlowExecutionResult.createEndedResult("bar", outcome)); EasyMock.replay(new Object[] { executor }); - ModelAndView mv = controller.handleRender(renderRequest, renderResponse, flowHandler); - assertNull(mv); + controller.handleAction(actionRequest, actionResponse, flowHandler); + assertTrue(handleExecutionOutcomeCalled); EasyMock.verify(new Object[] { executor }); - } public void testHandleFlowExceptionCustomFlowHandler() throws Exception { @@ -195,6 +196,7 @@ public class FlowHandlerAdapterTests extends TestCase { EasyMock.replay(new Object[] { executor }); ModelAndView mv = controller.handleRender(renderRequest, renderResponse, flowHandler); assertNotNull(mv); + assertEquals("error", mv.getViewName()); EasyMock.verify(new Object[] { executor }); } @@ -203,7 +205,7 @@ public class FlowHandlerAdapterTests extends TestCase { PortletSession session = renderRequest.getPortletSession(); final FlowException flowException = new FlowException("Error") { }; - session.setAttribute("actionFlowException", flowException); + session.setAttribute("actionRequestFlowException", flowException); ModelAndView mv = controller.handleRender(renderRequest, renderResponse, flowHandler); assertEquals("error", mv.getViewName()); }