diff --git a/spring-webflow/src/main/java/org/springframework/webflow/context/portlet/DefaultFlowUrlHandler.java b/spring-webflow/src/main/java/org/springframework/webflow/context/portlet/DefaultFlowUrlHandler.java index da4b4678..946293ba 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/context/portlet/DefaultFlowUrlHandler.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/context/portlet/DefaultFlowUrlHandler.java @@ -17,11 +17,14 @@ package org.springframework.webflow.context.portlet; import javax.portlet.ActionRequest; import javax.portlet.ActionResponse; +import javax.portlet.MimeResponse; import javax.portlet.PortletRequest; import javax.portlet.PortletSession; import javax.portlet.PortletURL; import javax.portlet.RenderRequest; import javax.portlet.RenderResponse; +import javax.portlet.ResourceRequest; +import javax.portlet.ResourceResponse; /** * Default flow URL handler for SWF 2. @@ -50,13 +53,31 @@ public class DefaultFlowUrlHandler implements FlowUrlHandler { } public void setFlowExecutionInSession(String flowExecutionKey, RenderRequest request) { - PortletSession session = request.getPortletSession(); - session.setAttribute(EXECUTION_ATTRIBUTE, flowExecutionKey); + setSessionAttribute(EXECUTION_ATTRIBUTE, flowExecutionKey, request); + } + + public void setFlowExecutionInSession(String flowExecutionKey, ResourceRequest request) { + setSessionAttribute(EXECUTION_ATTRIBUTE, flowExecutionKey, request); } public String createFlowExecutionUrl(String flowId, String flowExecutionKey, RenderResponse response) { + return createFlowExecutionActionUrl(flowExecutionKey, response); + } + + public String createFlowExecutionUrl(String flowId, String flowExecutionKey, ResourceResponse response) { + // Create Action URL by default + return createFlowExecutionActionUrl(flowExecutionKey, response); + } + + private void setSessionAttribute(String name, String value, PortletRequest request) { + PortletSession session = request.getPortletSession(); + session.setAttribute(name, value); + } + + private String createFlowExecutionActionUrl(String flowExecutionKey, MimeResponse response) { PortletURL url = response.createActionURL(); url.setParameter(EXECUTION_ATTRIBUTE, flowExecutionKey); return url.toString(); } + } diff --git a/spring-webflow/src/main/java/org/springframework/webflow/context/portlet/FlowUrlHandler.java b/spring-webflow/src/main/java/org/springframework/webflow/context/portlet/FlowUrlHandler.java index 1ce831ec..6534a08d 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/context/portlet/FlowUrlHandler.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/context/portlet/FlowUrlHandler.java @@ -19,6 +19,8 @@ import javax.portlet.ActionResponse; import javax.portlet.PortletRequest; import javax.portlet.RenderRequest; import javax.portlet.RenderResponse; +import javax.portlet.ResourceRequest; +import javax.portlet.ResourceResponse; /** * A interface for parsing and generating flow URLs. Encapsulates a specific flow URL format. @@ -43,20 +45,37 @@ public interface FlowUrlHandler { public void setFlowExecutionRenderParameter(String flowExecutionKey, ActionResponse response); /** - * Set the flow execution key into the portlet session. This should only be used when the portlet is started before - * any action requests are made + * Set the flow execution key into the portlet session. This should only be used in a render request when the + * portlet is started before any action requests are made * @param flowExecutionKey the key - * @param request the render request + * @param request the request */ public void setFlowExecutionInSession(String flowExecutionKey, RenderRequest request); /** - * Creates a flow execution URL suitable for use as an action URL. + * Set the flow execution key into the portlet session. This should only be used in a resource request when the + * portlet is started before any action requests are made + * @param flowExecutionKey the key + * @param request the request + */ + public void setFlowExecutionInSession(String flowExecutionKey, ResourceRequest request); + + /** + * Creates a flow execution URL during a render phase suitable to invoke Web Flow in a portlet environment * @param flowId the flow id * @param flowExecutionKey the flow execution key - * @param response the render response + * @param response the response * @return the execution url */ public String createFlowExecutionUrl(String flowId, String flowExecutionKey, RenderResponse response); + /** + * Creates a flow execution URL during a resource phase suitable to invoke Web Flow in a portlet environment + * @param flowId the flow id + * @param flowExecutionKey the flow execution key + * @param response the response + * @return the execution url + */ + public String createFlowExecutionUrl(String flowId, String flowExecutionKey, ResourceResponse response); + } diff --git a/spring-webflow/src/main/java/org/springframework/webflow/context/portlet/PortletExternalContext.java b/spring-webflow/src/main/java/org/springframework/webflow/context/portlet/PortletExternalContext.java index 6f7e7dd5..0cc58af2 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/context/portlet/PortletExternalContext.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/context/portlet/PortletExternalContext.java @@ -22,11 +22,14 @@ import java.util.Locale; import javax.portlet.ActionRequest; import javax.portlet.ActionResponse; +import javax.portlet.MimeResponse; import javax.portlet.PortletContext; import javax.portlet.PortletRequest; import javax.portlet.PortletResponse; import javax.portlet.RenderRequest; import javax.portlet.RenderResponse; +import javax.portlet.ResourceRequest; +import javax.portlet.ResourceResponse; import org.springframework.webflow.context.ExternalContext; import org.springframework.webflow.core.collection.LocalAttributeMap; @@ -50,6 +53,8 @@ public class PortletExternalContext implements ExternalContext { protected static final short RENDER_PHASE = 2; + protected static final short RESOURCE_PHASE = 3; + /** * The context. */ @@ -66,7 +71,7 @@ public class PortletExternalContext implements ExternalContext { private PortletResponse response; /** - * The portlet request phase: render or action + * The portlet request phase: render, action, resource */ private short requestPhase; @@ -202,17 +207,20 @@ public class PortletExternalContext implements ExternalContext { } public String getFlowExecutionUrl(String flowId, String flowExecutionKey) { - if (!isRenderPhase()) { + if (isRenderPhase()) { + return flowUrlHandler.createFlowExecutionUrl(flowId, flowExecutionKey, (RenderResponse) response); + } else if (isResourcePhase()) { + return flowUrlHandler.createFlowExecutionUrl(flowId, flowExecutionKey, (ResourceResponse) response); + } else { throw new IllegalStateException( - "A flow execution action URL can only be obtained in a RenderRequest using a RenderResponse"); + "A flow execution action URL can only be obtained in a RenderRequest or a ResourceRequest"); } - return flowUrlHandler.createFlowExecutionUrl(flowId, flowExecutionKey, (RenderResponse) response); } public Writer getResponseWriter() throws IllegalStateException { assertResponseAllowed(); try { - return ((RenderResponse) response).getWriter(); + return ((MimeResponse) response).getWriter(); } catch (IOException e) { IllegalStateException ise = new IllegalStateException("Unable to access the response Writer"); ise.initCause(e); @@ -221,7 +229,7 @@ public class PortletExternalContext implements ExternalContext { } public boolean isResponseAllowed() { - return isRenderPhase() && !responseComplete; + return (isRenderPhase() || isResourcePhase()) && !responseComplete; } public boolean isResponseComplete() { @@ -331,6 +339,13 @@ public class PortletExternalContext implements ExternalContext { return requestPhase == RENDER_PHASE; } + /** + * Returns true if the current request phase is the resource phase + */ + public boolean isResourcePhase() { + return requestPhase == RESOURCE_PHASE; + } + // private helpers private void init(PortletContext context, PortletRequest request, PortletResponse response, @@ -347,15 +362,17 @@ public class PortletExternalContext implements ExternalContext { requestPhase = ACTION_PHASE; } else if (request instanceof RenderRequest && response instanceof RenderResponse) { requestPhase = RENDER_PHASE; + } else if (request instanceof ResourceRequest && response instanceof ResourceResponse) { + requestPhase = RESOURCE_PHASE; } else { - throw new IllegalArgumentException("Unknown portlet phase, expected: action or render"); + throw new IllegalArgumentException("Unknown portlet phase, expected: action, render, or resource"); } } private void assertResponseAllowed() throws IllegalStateException { - if (!isRenderPhase()) { + if (!isRenderPhase() && !isResourcePhase()) { throw new IllegalStateException( - "A response is not allowed because the current PortletRequest is not a RenderRequest"); + "A response is not allowed because the current PortletRequest is neither a RenderRequest nor a ResourceRequest"); } if (responseComplete) { throw new IllegalStateException( 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 ef285000..7d833b02 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 @@ -17,8 +17,11 @@ package org.springframework.webflow.mvc.portlet; import javax.portlet.ActionRequest; import javax.portlet.ActionResponse; +import javax.portlet.PortletRequest; import javax.portlet.RenderRequest; import javax.portlet.RenderResponse; +import javax.portlet.ResourceRequest; +import javax.portlet.ResourceResponse; import org.springframework.webflow.core.FlowException; import org.springframework.webflow.core.collection.MutableAttributeMap; @@ -29,6 +32,7 @@ import org.springframework.webflow.execution.FlowExecutionOutcome; * which operations they need. * * @author Keith Donald + * @author Rossen Stoyanchev */ public class AbstractFlowHandler implements FlowHandler { @@ -40,12 +44,24 @@ public class AbstractFlowHandler implements FlowHandler { return null; } + public MutableAttributeMap createResourceExecutionInputMap(ResourceRequest request) { + return null; + } + public boolean handleExecutionOutcome(FlowExecutionOutcome outcome, ActionRequest request, ActionResponse response) { return false; } + public String handleException(FlowException e, PortletRequest request, RenderResponse response) { + return null; + } + public String handleException(FlowException e, RenderRequest request, RenderResponse response) { return null; } + public String handleResourceException(FlowException e, ResourceRequest request, ResourceResponse 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 bf413b48..44b8d677 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 @@ -20,6 +20,8 @@ import javax.portlet.ActionResponse; import javax.portlet.PortletModeException; import javax.portlet.RenderRequest; import javax.portlet.RenderResponse; +import javax.portlet.ResourceRequest; +import javax.portlet.ResourceResponse; import org.springframework.webflow.core.FlowException; import org.springframework.webflow.core.collection.MutableAttributeMap; @@ -37,6 +39,7 @@ import org.springframework.webflow.execution.FlowExecutionOutcome; * flow id to launch, how to provision its input, how to process its outcomes, and how to handle uncaught exceptions. * * @author Keith Donald + * @author Rossen Stoyanchev */ public interface FlowHandler { @@ -47,13 +50,21 @@ public interface FlowHandler { public String getFlowId(); /** - * Creates the flow execution input map to pass to a new instance of the flow being started. Used by a Controller to - * launch the flow execution with the correct input. + * Creates the flow execution input map to pass to a new instance of the flow being started in a render request. + * Used by a Controller to launch the flow execution with the correct input. * @param request the current request * @return the input map */ public MutableAttributeMap createExecutionInputMap(RenderRequest request); + /** + * Creates the flow execution input map to pass to a new instance of the flow being started in a resource request. + * Used by a Controller to launch the flow execution with the correct input. + * @param request the current request + * @return the input map + */ + public MutableAttributeMap createResourceExecutionInputMap(ResourceRequest request); + /** * Handles a specific flow execution outcome. Used to change portlet modes after the flow ends. * @param outcome the outcome that was reached @@ -66,8 +77,8 @@ public interface FlowHandler { throws PortletModeException; /** - * Handles a flow exception that was not handled by the Web Flow system. Used by a Controller to handle a specific - * type of exception dealing with this flow in a custom manner. + * Handles a flow exception that was not handled by the Web Flow system in render request. Used by a Controller to + * handle a specific type of exception dealing with this flow in a custom manner. * @param e the unhandled exception originating from Spring Web Flow. May be thrown by the flow execution itself or * the flow executor system if no execution could be restored. * @param request the current request @@ -77,4 +88,16 @@ public interface FlowHandler { */ public String handleException(FlowException e, RenderRequest request, RenderResponse response); + /** + * Handles a flow exception that was not handled by the Web Flow system in a resource request. Used by a Controller + * to handle a specific type of exception dealing with this flow in a custom manner. + * @param e the unhandled exception originating from Spring Web Flow. May be thrown by the flow execution itself or + * the flow executor system if no execution could be restored. + * @param request the current request + * @param response the current response + * @return the name of a specific error view to render, or null if the exception should be handled by + * the caller + */ + public String handleResourceException(FlowException e, ResourceRequest request, ResourceResponse 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 e6d58e7d..95d93835 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 @@ -15,7 +15,6 @@ */ package org.springframework.webflow.mvc.portlet; -import java.io.IOException; import java.util.Iterator; import java.util.Map; @@ -25,7 +24,6 @@ import javax.portlet.EventRequest; import javax.portlet.EventResponse; import javax.portlet.PortletModeException; import javax.portlet.PortletRequest; -import javax.portlet.PortletRequestDispatcher; import javax.portlet.PortletResponse; import javax.portlet.PortletSession; import javax.portlet.RenderRequest; @@ -56,6 +54,7 @@ import org.springframework.webflow.executor.FlowExecutor; * * @author Keith Donald * @author Scott Andrews + * @author Rossen Stoyanchev */ public class FlowHandlerAdapter extends PortletContentGenerator implements HandlerAdapter, InitializingBean { @@ -121,19 +120,36 @@ public class FlowHandlerAdapter extends PortletContentGenerator implements Handl FlowHandler flowHandler = (FlowHandler) handler; checkAndPrepare(request, response); populateConveniencePortletProperties(request); - PortletSession session = request.getPortletSession(false); - if (session != null) { - FlowException e = (FlowException) session.getAttribute(ACTION_REQUEST_FLOW_EXCEPTION_ATTRIBUTE); - if (e != null) { - session.removeAttribute(ACTION_REQUEST_FLOW_EXCEPTION_ATTRIBUTE); - return handleException(e, flowHandler, request, response); - } + FlowException e = clearActionRequestFlowException(request, response, flowHandler); + if (e != null) { + return handleException(e, flowHandler, request, response); } String flowExecutionKey = flowUrlHandler.getFlowExecutionKey(request); if (flowExecutionKey != null) { - return resumeFlow(flowExecutionKey, flowHandler, request, response); + return resumeFlowRender(request, response, flowHandler, flowExecutionKey); } else { - return startFlow(flowHandler, request, response); + MutableAttributeMap input = flowHandler.createExecutionInputMap(request); + if (input == null) { + input = defaultCreateFlowExecutionInputMap(request); + } + return startFlowRender(flowHandler, input, request, response); + } + } + + public ModelAndView handleResource(ResourceRequest request, ResourceResponse response, Object handler) + throws Exception { + FlowHandler flowHandler = (FlowHandler) handler; + checkAndPrepare(request, response); + populateConveniencePortletProperties(request); + String flowExecutionKey = flowUrlHandler.getFlowExecutionKey(request); + if (flowExecutionKey != null) { + return resumeFlowResource(request, response, flowHandler, flowExecutionKey); + } else { + MutableAttributeMap input = flowHandler.createResourceExecutionInputMap(request); + if (input == null) { + input = defaultCreateFlowExecutionInputMap(request); + } + return startFlowResource(flowHandler, request, response); } } @@ -161,18 +177,6 @@ public class FlowHandlerAdapter extends PortletContentGenerator implements Handl response.setRenderParameters(request); } - public ModelAndView handleResource(ResourceRequest request, ResourceResponse response, Object handler) - throws Exception { - // equivalent to Portlet 2.0 GenericPortlet - if (request.getResourceID() != null) { - PortletRequestDispatcher rd = this.getPortletContext().getRequestDispatcher(request.getResourceID()); - if (rd != null) { - rd.forward(request, response); - } - } - return null; - } - // subclassing hooks protected void populateConveniencePortletProperties(PortletRequest request) { @@ -212,11 +216,28 @@ public class FlowHandlerAdapter extends PortletContentGenerator implements Handl RenderResponse response) { if (e instanceof NoSuchFlowExecutionException) { if (logger.isDebugEnabled()) { - logger.debug("Restarting a new execution of previously ended flow '" + flowHandler.getFlowId() + "'"); + logger.debug("Starting a new execution of previously ended flow '" + flowHandler.getFlowId() + "'"); } // by default, attempt to restart the flow - startFlow(flowHandler, null, request, response); - return null; + try { + startFlowRender(flowHandler, null, request, response); + return null; + } catch (FlowException flowException) { + return handleException(flowException, flowHandler, request, response); + } + } else { + throw e; + } + } + + protected ModelAndView defaultHandleResourceException(FlowHandler flowHandler, FlowException e, + ResourceRequest request, ResourceResponse response) { + if (e instanceof NoSuchFlowExecutionException) { + if (logger.isDebugEnabled()) { + logger.debug("Starting a new execution of previously ended flow '" + flowHandler.getFlowId() + "'"); + } + // by default, attempt to restart the flow + return startFlowResource(flowHandler, request, response); } else { throw e; } @@ -226,14 +247,24 @@ public class FlowHandlerAdapter extends PortletContentGenerator implements Handl 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); + String view = flowHandler.handleException(e, request, response); + if (view != null) { + return new ModelAndView(view); } else { return defaultHandleException(flowHandler, e, request, response); } } + private ModelAndView handleResourceException(FlowException e, FlowHandler flowHandler, ResourceRequest request, + ResourceResponse response) { + String view = flowHandler.handleResourceException(e, request, response); + if (view != null) { + return new ModelAndView(view); + } else { + return defaultHandleResourceException(flowHandler, e, request, response); + } + } + private void handleFlowExecutionOutcome(FlowExecutionOutcome outcome, FlowHandler flowHandler, ActionRequest request, ActionResponse response) throws PortletModeException { boolean handled = flowHandler.handleExecutionOutcome(outcome, request, response); @@ -242,15 +273,7 @@ public class FlowHandlerAdapter extends PortletContentGenerator implements Handl } } - private ModelAndView startFlow(FlowHandler flowHandler, RenderRequest request, RenderResponse response) { - MutableAttributeMap input = flowHandler.createExecutionInputMap(request); - if (input == null) { - input = defaultCreateFlowExecutionInputMap(request); - } - return startFlow(flowHandler, input, request, response); - } - - private ModelAndView startFlow(FlowHandler flowHandler, MutableAttributeMap input, RenderRequest request, + private ModelAndView startFlowRender(FlowHandler flowHandler, MutableAttributeMap input, RenderRequest request, RenderResponse response) { PortletExternalContext context = createPortletExternalContext(request, response); try { @@ -259,13 +282,26 @@ public class FlowHandlerAdapter extends PortletContentGenerator implements Handl flowUrlHandler.setFlowExecutionInSession(result.getPausedKey(), request); } return null; - } catch (FlowException e) { - return handleException(e, flowHandler, request, response); + } catch (FlowException flowEx) { + return handleException(flowEx, flowHandler, request, response); } } - private ModelAndView resumeFlow(String flowExecutionKey, FlowHandler flowHandler, RenderRequest request, - RenderResponse response) throws IOException { + private ModelAndView startFlowResource(FlowHandler flowHandler, ResourceRequest request, ResourceResponse response) { + PortletExternalContext context = createPortletExternalContext(request, response); + try { + FlowExecutionResult result = flowExecutor.launchExecution(flowHandler.getFlowId(), null, context); + if (result.isPaused()) { + flowUrlHandler.setFlowExecutionInSession(result.getPausedKey(), request); + } + return null; + } catch (FlowException flowEx) { + return handleResourceException(flowEx, flowHandler, request, response); + } + } + + private ModelAndView resumeFlowRender(RenderRequest request, RenderResponse response, FlowHandler flowHandler, + String flowExecutionKey) { PortletExternalContext context = createPortletExternalContext(request, response); try { flowExecutor.resumeExecution(flowExecutionKey, context); @@ -275,4 +311,28 @@ public class FlowHandlerAdapter extends PortletContentGenerator implements Handl } } + private ModelAndView resumeFlowResource(ResourceRequest request, ResourceResponse response, + FlowHandler flowHandler, String flowExecutionKey) { + PortletExternalContext context = createPortletExternalContext(request, response); + try { + flowExecutor.resumeExecution(flowExecutionKey, context); + return null; + } catch (FlowException e) { + return handleResourceException(e, flowHandler, request, response); + } + } + + private FlowException clearActionRequestFlowException(RenderRequest request, RenderResponse response, + FlowHandler flowHandler) { + PortletSession session = request.getPortletSession(false); + if (session != null) { + FlowException e = (FlowException) session.getAttribute(ACTION_REQUEST_FLOW_EXCEPTION_ATTRIBUTE); + if (e != null) { + session.removeAttribute(ACTION_REQUEST_FLOW_EXCEPTION_ATTRIBUTE); + return e; + } + } + return null; + } + } \ No newline at end of file diff --git a/spring-webflow/src/main/java/org/springframework/webflow/mvc/portlet/PortletMvcView.java b/spring-webflow/src/main/java/org/springframework/webflow/mvc/portlet/PortletMvcView.java index c8dcfa6c..1b8486de 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/mvc/portlet/PortletMvcView.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/mvc/portlet/PortletMvcView.java @@ -17,9 +17,9 @@ package org.springframework.webflow.mvc.portlet; import java.util.Map; +import javax.portlet.MimeResponse; import javax.portlet.PortletContext; -import javax.portlet.RenderRequest; -import javax.portlet.RenderResponse; +import javax.portlet.PortletRequest; import org.springframework.web.portlet.DispatcherPortlet; import org.springframework.web.servlet.View; @@ -50,8 +50,8 @@ public class PortletMvcView extends AbstractMvcView { ExternalContext externalContext = context.getExternalContext(); View view = getView(); PortletContext portletContext = (PortletContext) externalContext.getNativeContext(); - RenderRequest request = (RenderRequest) externalContext.getNativeRequest(); - RenderResponse response = (RenderResponse) externalContext.getNativeResponse(); + PortletRequest request = (PortletRequest) externalContext.getNativeRequest(); + MimeResponse response = (MimeResponse) externalContext.getNativeResponse(); if (response.getContentType() == null) { // No Portlet content type specified yet -> use the view-determined type. // (The Portlet spec requires the content type to be set on the RenderResponse) 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 75ffba51..a33cf7ef 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 @@ -7,6 +7,8 @@ import javax.portlet.PortletResponse; import javax.portlet.PortletSession; import javax.portlet.RenderRequest; import javax.portlet.RenderResponse; +import javax.portlet.ResourceRequest; +import javax.portlet.ResourceResponse; import junit.framework.TestCase; @@ -67,10 +69,10 @@ public class FlowHandlerAdapterTests extends TestCase { actionResponse = new MockActionResponse(); renderRequest = new MockRenderRequest(); renderResponse = new MockRenderResponse(); - actionContext = new PortletExternalContext(portletContext, actionRequest, actionResponse, controller - .getFlowUrlHandler()); - renderContext = new PortletExternalContext(portletContext, renderRequest, renderResponse, controller - .getFlowUrlHandler()); + actionContext = new PortletExternalContext(portletContext, actionRequest, actionResponse, + controller.getFlowUrlHandler()); + renderContext = new PortletExternalContext(portletContext, renderRequest, renderResponse, + controller.getFlowUrlHandler()); flowHandler = new FlowHandler() { public String getFlowId() { @@ -81,6 +83,10 @@ public class FlowHandlerAdapterTests extends TestCase { return null; } + public MutableAttributeMap createResourceExecutionInputMap(ResourceRequest request) { + return null; + } + public boolean handleExecutionOutcome(FlowExecutionOutcome outcome, ActionRequest request, ActionResponse response) { handleExecutionOutcomeCalled = true; @@ -99,6 +105,14 @@ public class FlowHandlerAdapterTests extends TestCase { } } + public String handleResourceException(FlowException e, ResourceRequest request, ResourceResponse response) { + if (handleException) { + return "error"; + } else { + return null; + } + } + }; }