diff --git a/spring-webflow/changelog.txt b/spring-webflow/changelog.txt index 569ae8e5..e68ffe3f 100644 --- a/spring-webflow/changelog.txt +++ b/spring-webflow/changelog.txt @@ -56,6 +56,8 @@ Package org.springframework.webflow.executor * Added support for configuring a in a JSF environment, greatly simplifying JSF SWF configuration and making it consistent with Spring MVC and Struts. This also means its much easier to benefit from defaults such as a continuation-based flow execution repository and 'alwaysRedirectOnPause'. +* Introduced ResponseInstructionHandler convenience class and refactored FlowController, PortletFlowController, + FlowAction and FlowPhaseListener to use it. Package org.springframework.webflow.test * Added constructor taking test name argument to AbstractFlowExecutionTests, AbstractExternalizedFlowExecutionTests diff --git a/spring-webflow/src/main/java/org/springframework/webflow/executor/jsf/FlowPhaseListener.java b/spring-webflow/src/main/java/org/springframework/webflow/executor/jsf/FlowPhaseListener.java index f20cfc0e..b1bcb43f 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/executor/jsf/FlowPhaseListener.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/executor/jsf/FlowPhaseListener.java @@ -42,8 +42,10 @@ import org.springframework.webflow.execution.support.ApplicationView; import org.springframework.webflow.execution.support.ExternalRedirect; import org.springframework.webflow.execution.support.FlowDefinitionRedirect; import org.springframework.webflow.execution.support.FlowExecutionRedirect; +import org.springframework.webflow.executor.ResponseInstruction; import org.springframework.webflow.executor.support.FlowExecutorArgumentHandler; import org.springframework.webflow.executor.support.RequestParameterFlowExecutorArgumentHandler; +import org.springframework.webflow.executor.support.ResponseInstructionHandler; /** * JSF phase listener that is responsible for managing a {@link FlowExecution} @@ -196,7 +198,7 @@ public class FlowPhaseListener implements PhaseListener { return null; } - protected void prepareResponse(JsfExternalContext context, FlowExecutionHolder holder) { + protected void prepareResponse(final JsfExternalContext context, final FlowExecutionHolder holder) { if (holder.needsSave()) { generateKey(context, holder); } @@ -205,26 +207,38 @@ public class FlowPhaseListener implements PhaseListener { selectedView = holder.getFlowExecution().refresh(context); holder.setViewSelection(selectedView); } - if (selectedView instanceof ApplicationView) { - prepareApplicationView(context.getFacesContext(), holder); - } - else if (selectedView instanceof FlowExecutionRedirect) { - String url = argumentHandler.createFlowExecutionUrl(holder.getFlowExecutionKey().toString(), holder - .getFlowExecution(), context); - sendRedirect(url, context); - } - else if (selectedView instanceof ExternalRedirect) { - String flowExecutionKey = holder.getFlowExecution().isActive() ? holder.getFlowExecutionKey().toString() - : null; - String url = argumentHandler.createExternalUrl((ExternalRedirect) holder.getViewSelection(), - flowExecutionKey, context); - sendRedirect(url, context); - } - else if (selectedView instanceof FlowDefinitionRedirect) { - String url = argumentHandler.createFlowDefinitionUrl((FlowDefinitionRedirect) holder.getViewSelection(), - context); - sendRedirect(url, context); - } + + new ResponseInstructionHandler() { + + protected void handleApplicationView(ApplicationView view) throws Exception { + prepareApplicationView(context.getFacesContext(), holder); + } + + protected void handleFlowDefinitionRedirect(FlowDefinitionRedirect redirect) throws Exception { + String url = argumentHandler.createFlowDefinitionUrl((FlowDefinitionRedirect) holder.getViewSelection(), + context); + sendRedirect(url, context); + } + + protected void handleFlowExecutionRedirect(FlowExecutionRedirect redirect) throws Exception { + String url = argumentHandler.createFlowExecutionUrl(holder.getFlowExecutionKey().toString(), holder + .getFlowExecution(), context); + sendRedirect(url, context); + } + + protected void handleExternalRedirect(ExternalRedirect redirect) throws Exception { + String flowExecutionKey = holder.getFlowExecution().isActive() ? holder.getFlowExecutionKey().toString() + : null; + String url = argumentHandler.createExternalUrl((ExternalRedirect) holder.getViewSelection(), + flowExecutionKey, context); + sendRedirect(url, context); + } + + protected void handleNull() throws Exception { + // nothing to do + } + + }.handleQuietly(new ResponseInstruction(holder.getFlowExecution(), selectedView)); } protected void prepareApplicationView(FacesContext facesContext, FlowExecutionHolder holder) { diff --git a/spring-webflow/src/main/java/org/springframework/webflow/executor/mvc/FlowController.java b/spring-webflow/src/main/java/org/springframework/webflow/executor/mvc/FlowController.java index 93f8ddf6..147b0353 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/executor/mvc/FlowController.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/executor/mvc/FlowController.java @@ -32,12 +32,14 @@ import org.springframework.webflow.context.servlet.ServletExternalContext; import org.springframework.webflow.execution.support.ApplicationView; import org.springframework.webflow.execution.support.ExternalRedirect; import org.springframework.webflow.execution.support.FlowDefinitionRedirect; +import org.springframework.webflow.execution.support.FlowExecutionRedirect; import org.springframework.webflow.executor.FlowExecutor; import org.springframework.webflow.executor.ResponseInstruction; import org.springframework.webflow.executor.support.FlowExecutorArgumentHandler; import org.springframework.webflow.executor.support.FlowRequestHandler; import org.springframework.webflow.executor.support.RequestParameterFlowExecutorArgumentHandler; import org.springframework.webflow.executor.support.RequestPathFlowExecutorArgumentHandler; +import org.springframework.webflow.executor.support.ResponseInstructionHandler; /** * Point of integration between Spring Web MVC and Spring Web Flow: a @@ -186,41 +188,45 @@ public class FlowController extends AbstractController implements InitializingBe * Create a ModelAndView object based on the information in the selected * response instruction. Subclasses can override this to return a * specialized ModelAndView or to do custom processing on it. - * @param response instruction the response instruction to convert + * @param responseInstruction the response instruction to convert * @return a new ModelAndView object */ - protected ModelAndView toModelAndView(ResponseInstruction response, ExternalContext context) { - if (response.isApplicationView()) { - // forward to a view as part of an active conversation - ApplicationView view = (ApplicationView)response.getViewSelection(); - Map model = new HashMap(view.getModel()); - argumentHandler.exposeFlowExecutionContext( - response.getFlowExecutionKey(), response.getFlowExecutionContext(), model); - return new ModelAndView(view.getViewName(), model); - } - else if (response.isFlowDefinitionRedirect()) { - // restart the flow by redirecting to flow launch URL - String flowUrl = argumentHandler.createFlowDefinitionUrl((FlowDefinitionRedirect)response.getViewSelection(), context); - return new ModelAndView(new RedirectView(flowUrl)); - } - else if (response.isFlowExecutionRedirect()) { - // redirect to active flow execution URL - String flowExecutionUrl = argumentHandler.createFlowExecutionUrl( - response.getFlowExecutionKey(), response.getFlowExecutionContext(), context); - return new ModelAndView(new RedirectView(flowExecutionUrl)); - } - else if (response.isExternalRedirect()) { - // redirect to external URL - ExternalRedirect redirect = (ExternalRedirect)response.getViewSelection(); - String externalUrl = argumentHandler.createExternalUrl(redirect, response.getFlowExecutionKey(), context); - return new ModelAndView(new RedirectView(externalUrl)); - } - else if (response.isNull()) { - // no response to issue - return null; - } - else { - throw new IllegalArgumentException("Don't know how to handle response instruction " + response); - } + protected ModelAndView toModelAndView( + final ResponseInstruction responseInstruction, final ExternalContext context) { + return (ModelAndView)new ResponseInstructionHandler() { + protected void handleApplicationView(ApplicationView view) throws Exception { + // forward to a view as part of an active conversation + Map model = new HashMap(view.getModel()); + argumentHandler.exposeFlowExecutionContext(responseInstruction.getFlowExecutionKey(), + responseInstruction.getFlowExecutionContext(), model); + setResult(new ModelAndView(view.getViewName(), model)); + } + + protected void handleFlowDefinitionRedirect(FlowDefinitionRedirect redirect) throws Exception { + // restart the flow by redirecting to flow launch URL + String flowUrl = argumentHandler.createFlowDefinitionUrl(redirect, context); + setResult(new ModelAndView(new RedirectView(flowUrl))); + } + + protected void handleFlowExecutionRedirect(FlowExecutionRedirect redirect) throws Exception { + // redirect to active flow execution URL + String flowExecutionUrl = argumentHandler.createFlowExecutionUrl( + responseInstruction.getFlowExecutionKey(), + responseInstruction.getFlowExecutionContext(), context); + setResult(new ModelAndView(new RedirectView(flowExecutionUrl))); + } + + protected void handleExternalRedirect(ExternalRedirect redirect) throws Exception { + // redirect to external URL + String externalUrl = argumentHandler.createExternalUrl(redirect, + responseInstruction.getFlowExecutionKey(), context); + setResult(new ModelAndView(new RedirectView(externalUrl))); + } + + protected void handleNull() throws Exception { + // no response to issue + setResult(null); + } + }.handleQuietly(responseInstruction).getResult(); } } \ No newline at end of file diff --git a/spring-webflow/src/main/java/org/springframework/webflow/executor/mvc/PortletFlowController.java b/spring-webflow/src/main/java/org/springframework/webflow/executor/mvc/PortletFlowController.java index 72d09ca5..72d8454a 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/executor/mvc/PortletFlowController.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/executor/mvc/PortletFlowController.java @@ -34,10 +34,12 @@ import org.springframework.webflow.context.portlet.PortletExternalContext; import org.springframework.webflow.execution.support.ApplicationView; import org.springframework.webflow.execution.support.ExternalRedirect; import org.springframework.webflow.execution.support.FlowDefinitionRedirect; +import org.springframework.webflow.execution.support.FlowExecutionRedirect; import org.springframework.webflow.executor.FlowExecutor; import org.springframework.webflow.executor.ResponseInstruction; import org.springframework.webflow.executor.support.FlowExecutorArgumentHandler; import org.springframework.webflow.executor.support.RequestParameterFlowExecutorArgumentHandler; +import org.springframework.webflow.executor.support.ResponseInstructionHandler; /** * Point of integration between Spring Portlet MVC and Spring Web Flow: a @@ -186,50 +188,59 @@ public class PortletFlowController extends AbstractController implements Initial } } - protected void handleActionRequestInternal(ActionRequest request, ActionResponse response) throws Exception { - PortletExternalContext context = new PortletExternalContext(getPortletContext(), request, response); - String flowExecutionKey = argumentHandler.extractFlowExecutionKey(context); - String eventId = argumentHandler.extractEventId(context); + protected void handleActionRequestInternal(final ActionRequest request, final ActionResponse response) + throws Exception { + final PortletExternalContext context = new PortletExternalContext(getPortletContext(), request, response); + final String flowExecutionKey = argumentHandler.extractFlowExecutionKey(context); + final String eventId = argumentHandler.extractEventId(context); + // signal the event against the flow execution, returning the next // response instruction - ResponseInstruction responseInstruction = flowExecutor.resume(flowExecutionKey, eventId, context); - if (responseInstruction.isApplicationView()) { - // response instruction is a forward to an "application view" - if (responseInstruction.isActiveView()) { - // is an "active" forward from a view-state (not end-state) -- - // set the flow execution key render parameter to support - // browser refresh + final ResponseInstruction responseInstruction = flowExecutor.resume(flowExecutionKey, eventId, context); + + new ResponseInstructionHandler() { + + protected void handleApplicationView(ApplicationView view) throws Exception { + // response instruction is a forward to an "application view" + if (responseInstruction.isActiveView()) { + // is an "active" forward from a view-state (not end-state) -- + // set the flow execution key render parameter to support + // browser refresh + response.setRenderParameter( + argumentHandler.getFlowExecutionKeyArgumentName(), + responseInstruction.getFlowExecutionKey()); + } + // cache response instruction for access during render phase of this + // portlet + exposeToRenderPhase(responseInstruction, request); + } + + protected void handleFlowDefinitionRedirect(FlowDefinitionRedirect redirect) throws Exception { + // set flow id render parameter to request that a new flow be + // launched within this portlet + response.setRenderParameters(redirect.getExecutionInput()); + response.setRenderParameter(argumentHandler.getFlowIdArgumentName(), redirect.getFlowDefinitionId()); + } + + protected void handleFlowExecutionRedirect(FlowExecutionRedirect redirect) throws Exception { + // is a flow execution redirect: simply expose key parameter to + // support refresh during render phase response.setRenderParameter( argumentHandler.getFlowExecutionKeyArgumentName(), responseInstruction.getFlowExecutionKey()); } - // cache response instruction for access during render phase of this - // portlet - exposeToRenderPhase(responseInstruction, request); - } - else if (responseInstruction.isFlowExecutionRedirect()) { - // is a flow execution redirect: simply expose key parameter to - // support refresh during render phase - response.setRenderParameter( - argumentHandler.getFlowExecutionKeyArgumentName(), - responseInstruction.getFlowExecutionKey()); - } - else if (responseInstruction.isFlowDefinitionRedirect()) { - // set flow id render parameter to request that a new flow be - // launched within this portlet - FlowDefinitionRedirect redirect = (FlowDefinitionRedirect)responseInstruction.getViewSelection(); - response.setRenderParameters(redirect.getExecutionInput()); - response.setRenderParameter(argumentHandler.getFlowIdArgumentName(), redirect.getFlowDefinitionId()); - } - else if (responseInstruction.isExternalRedirect()) { - // issue the redirect to the external URL - ExternalRedirect redirect = (ExternalRedirect)responseInstruction.getViewSelection(); - String url = argumentHandler.createExternalUrl(redirect, flowExecutionKey, context); - response.sendRedirect(url); - } - else { - throw new IllegalArgumentException("Don't know how to handle response instruction " + responseInstruction); - } + + protected void handleExternalRedirect(ExternalRedirect redirect) throws Exception { + // issue the redirect to the external URL + String url = argumentHandler.createExternalUrl(redirect, flowExecutionKey, context); + response.sendRedirect(url); + } + + protected void handleNull() throws Exception { + // nothing to do + } + + }.handle(responseInstruction); } // helpers @@ -269,21 +280,22 @@ public class PortletFlowController extends AbstractController implements Initial * Convert given response instruction into a Spring Portlet MVC model and * view. */ - protected ModelAndView toModelAndView(ResponseInstruction response) { - if (response.isApplicationView()) { + protected ModelAndView toModelAndView(ResponseInstruction responseInstruction) { + if (responseInstruction.isApplicationView()) { // forward to a view as part of an active conversation - ApplicationView forward = (ApplicationView)response.getViewSelection(); + ApplicationView forward = (ApplicationView)responseInstruction.getViewSelection(); Map model = new HashMap(forward.getModel()); argumentHandler.exposeFlowExecutionContext( - response.getFlowExecutionKey(), response.getFlowExecutionContext(), model); + responseInstruction.getFlowExecutionKey(), responseInstruction.getFlowExecutionContext(), model); return new ModelAndView(forward.getViewName(), model); } - else if (response.isNull()) { + else if (responseInstruction.isNull()) { // no response to issue return null; } else { - throw new IllegalArgumentException("Don't know how to handle response instruction " + response); + throw new IllegalArgumentException( + "Don't know how to handle response instruction " + responseInstruction); } } } \ No newline at end of file diff --git a/spring-webflow/src/main/java/org/springframework/webflow/executor/struts/FlowAction.java b/spring-webflow/src/main/java/org/springframework/webflow/executor/struts/FlowAction.java index ebd63545..aec78173 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/executor/struts/FlowAction.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/executor/struts/FlowAction.java @@ -35,11 +35,13 @@ import org.springframework.webflow.context.ExternalContext; import org.springframework.webflow.execution.support.ApplicationView; import org.springframework.webflow.execution.support.ExternalRedirect; import org.springframework.webflow.execution.support.FlowDefinitionRedirect; +import org.springframework.webflow.execution.support.FlowExecutionRedirect; import org.springframework.webflow.executor.FlowExecutor; import org.springframework.webflow.executor.ResponseInstruction; import org.springframework.webflow.executor.support.FlowExecutorArgumentHandler; import org.springframework.webflow.executor.support.FlowRequestHandler; import org.springframework.webflow.executor.support.RequestParameterFlowExecutorArgumentHandler; +import org.springframework.webflow.executor.support.ResponseInstructionHandler; /** * Point of integration between Struts and Spring Web Flow: a Struts Action that @@ -232,50 +234,52 @@ public class FlowAction extends ActionSupport { * Return a Struts ActionForward given a ResponseInstruction. Adds all * attributes from the ResponseInstruction as request attributes. */ - protected ActionForward toActionForward(ResponseInstruction response, ActionMapping mapping, ActionForm form, - HttpServletRequest request, HttpServletResponse httpResponse, ExternalContext context) throws Exception { - if (response.isApplicationView()) { - // forward to a view as part of an active conversation - ApplicationView forward = (ApplicationView)response.getViewSelection(); - Map model = new HashMap(forward.getModel()); - argumentHandler.exposeFlowExecutionContext( - response.getFlowExecutionKey(), response.getFlowExecutionContext(), model); - WebUtils.exposeRequestAttributes(request, model); - if (form instanceof SpringBindingActionForm) { - SpringBindingActionForm bindingForm = (SpringBindingActionForm)form; - // expose the form object and associated errors as the - // "current form object" in the request - Errors currentErrors = (Errors)model.get(FormObjectAccessor.getCurrentFormErrorsName()); - bindingForm.expose(currentErrors, request); + protected ActionForward toActionForward(final ResponseInstruction responseInstruction, + final ActionMapping mapping, final ActionForm form, + final HttpServletRequest request, final HttpServletResponse response, + final ExternalContext context) throws Exception { + return (ActionForward)new ResponseInstructionHandler() { + protected void handleApplicationView(ApplicationView view) throws Exception { + // forward to a view as part of an active conversation + Map model = new HashMap(view.getModel()); + argumentHandler.exposeFlowExecutionContext( + responseInstruction.getFlowExecutionKey(), responseInstruction.getFlowExecutionContext(), model); + WebUtils.exposeRequestAttributes(request, model); + if (form instanceof SpringBindingActionForm) { + SpringBindingActionForm bindingForm = (SpringBindingActionForm)form; + // expose the form object and associated errors as the + // "current form object" in the request + Errors currentErrors = (Errors)model.get(FormObjectAccessor.getCurrentFormErrorsName()); + bindingForm.expose(currentErrors, request); + } + setResult(findForward(view, mapping)); } - return findForward(forward, mapping); - } - else if (response.isFlowExecutionRedirect()) { - // redirect to active flow execution URL - String flowExecutionUrl = argumentHandler.createFlowExecutionUrl( - response.getFlowExecutionKey(), response.getFlowExecutionContext(), context); - return createRedirectForward(flowExecutionUrl, httpResponse); - } - else if (response.isFlowDefinitionRedirect()) { - // restart the flow by redirecting to flow launch URL - String flowUrl = argumentHandler.createFlowDefinitionUrl( - (FlowDefinitionRedirect)response.getViewSelection(), context); - return createRedirectForward(flowUrl, httpResponse); - } - else if (response.isExternalRedirect()) { - // redirect to external URL - String externalUrl = argumentHandler.createExternalUrl( - (ExternalRedirect)response.getViewSelection(), response.getFlowExecutionKey(), context); - return createRedirectForward(externalUrl, httpResponse); - } - else if (response.isNull()) { - // no response to issue - return null; - } - else { - throw new IllegalArgumentException("Don't know how to handle response instruction " + response); - } + protected void handleFlowDefinitionRedirect(FlowDefinitionRedirect redirect) throws Exception { + // restart the flow by redirecting to flow launch URL + String flowUrl = argumentHandler.createFlowDefinitionUrl(redirect, context); + setResult(createRedirectForward(flowUrl, response)); + } + + protected void handleFlowExecutionRedirect(FlowExecutionRedirect redirect) throws Exception { + // redirect to active flow execution URL + String flowExecutionUrl = argumentHandler.createFlowExecutionUrl( + responseInstruction.getFlowExecutionKey(), responseInstruction.getFlowExecutionContext(), context); + setResult(createRedirectForward(flowExecutionUrl, response)); + } + + protected void handleExternalRedirect(ExternalRedirect redirect) throws Exception { + // redirect to external URL + String externalUrl = argumentHandler.createExternalUrl( + redirect, responseInstruction.getFlowExecutionKey(), context); + setResult(createRedirectForward(externalUrl, response)); + } + + protected void handleNull() throws Exception { + // no response to issue + setResult(null); + } + }.handle(responseInstruction).getResult(); } /** diff --git a/spring-webflow/src/main/java/org/springframework/webflow/executor/support/ResponseInstructionHandler.java b/spring-webflow/src/main/java/org/springframework/webflow/executor/support/ResponseInstructionHandler.java new file mode 100644 index 00000000..9c5e3881 --- /dev/null +++ b/spring-webflow/src/main/java/org/springframework/webflow/executor/support/ResponseInstructionHandler.java @@ -0,0 +1,152 @@ +/* + * Copyright 2004-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.webflow.executor.support; + +import org.springframework.webflow.execution.ViewSelection; +import org.springframework.webflow.execution.support.ApplicationView; +import org.springframework.webflow.execution.support.ExternalRedirect; +import org.springframework.webflow.execution.support.FlowDefinitionRedirect; +import org.springframework.webflow.execution.support.FlowExecutionRedirect; +import org.springframework.webflow.executor.ResponseInstruction; + +/** + * Abstract helper class that allows easy handling of all known view + * selection types. Users need to implement each of the hook methods + * dealing with a particular type of view selection, typically in an + * anonymous inner subclass of this class. + * + * @see ViewSelection + * + * @author Erwin Vervaet + */ +public abstract class ResponseInstructionHandler { + + private Object result; + + /** + * Set the object resulting from response handling. + * This is optional. + * @param result the result object + */ + public void setResult(Object result) { + this.result = result; + } + + /** + * Returns the object resulting from response handling. + * This is optional and will only be set if the subclass + * calls {@link #setResult(Object)} to set the result object. + * @return the result object, or null if none + */ + public Object getResult() { + return result; + } + + /** + * Issue a response for given response instruction. Will delegate to + * any of the available hook methods depending on the type of view selection + * contained in the response instruction. + * @param responseInstruction the response instruction to issue a response for + * @return this object, for call chaining + * @throws Exception when an error occured + */ + public final ResponseInstructionHandler handle(ResponseInstruction responseInstruction) throws Exception { + if (responseInstruction.isApplicationView()) { + handleApplicationView((ApplicationView)responseInstruction.getViewSelection()); + } + else if (responseInstruction.isFlowDefinitionRedirect()) { + handleFlowDefinitionRedirect((FlowDefinitionRedirect)responseInstruction.getViewSelection()); + } + else if (responseInstruction.isFlowExecutionRedirect()) { + handleFlowExecutionRedirect((FlowExecutionRedirect)responseInstruction.getViewSelection()); + } + else if (responseInstruction.isExternalRedirect()) { + handleExternalRedirect((ExternalRedirect)responseInstruction.getViewSelection()); + } + else if (responseInstruction.isNull()) { + handleNull(); + } + else { + throw new IllegalArgumentException( + "Don't know how to handle response instruction " + responseInstruction); + } + return this; + } + + /** + * Quietly issue a response for given response instruction, turning any Exception + * raised while handling the response instruction into a RuntimeException. + * Will delegate to any of the available hook methods depending on the type of view selection + * contained in the response instruction. + * @param responseInstruction the response instruction to issue a response for + * @return this object, for call chaining + */ + public final ResponseInstructionHandler handleQuietly(ResponseInstruction responseInstruction) { + try { + return handle(responseInstruction); + } + catch (Exception e) { + throw new RuntimeException( + "Unexpected exception handling response instruction " + responseInstruction, e); + } + } + + // template methods + + /** + * Issue a response for given application view. + * @param view the application view to issue a response for + * @throws Exception when an error occured + * @see ResponseInstruction#isActiveView() + * @see ApplicationView + */ + protected abstract void handleApplicationView(ApplicationView view) throws Exception; + + /** + * Issue a response for given flow definition redirect. + * @param redirect the flow definition redirect to issue a response for + * @throws Exception when an error occured + * @see ResponseInstruction#isFlowDefinitionRedirect() + * @see FlowDefinitionRedirect + */ + protected abstract void handleFlowDefinitionRedirect(FlowDefinitionRedirect redirect) throws Exception; + + /** + * Issue a response for given flow execution redirect. + * @param redirect the flow execution redirect to issue a response for + * @throws Exception when an error occured + * @see ResponseInstruction#isFlowExecutionRedirect() + * @see FlowExecutionRedirect + */ + protected abstract void handleFlowExecutionRedirect(FlowExecutionRedirect redirect) throws Exception; + + /** + * Issue a response for given external redirect. + * @param redirect the external redirect to issue a response for + * @throws Exception when an error occured + * @see ResponseInstruction#isExternalRedirect() + * @see ExternalRedirect + */ + protected abstract void handleExternalRedirect(ExternalRedirect redirect) throws Exception; + + /** + * Issue a respone for the null view selection. + * @throws Exception + * @see ResponseInstruction#isNull() + * @see ViewSelection#NULL_VIEW + */ + protected abstract void handleNull() throws Exception; +}