automatic exposing of flow execution key in view root, so no need to post back manually now in jsf env
This commit is contained in:
@@ -165,7 +165,7 @@
|
||||
<sect2 id="executor-custom-repo">
|
||||
<title>A flow executor using a simple execution repository</title>
|
||||
<programlisting>
|
||||
<flow:executor id="flowExecutor" registry-ref="flowRegistry" repository-type="simple"/>
|
||||
<flow:executor id="flowExecutor" registry-ref="flowRegistry" repository-type="simple"/>
|
||||
</programlisting>
|
||||
<para>
|
||||
This executor is configured with a simple repository that manages
|
||||
@@ -175,7 +175,7 @@
|
||||
<sect2 id="executor-custom-repo2">
|
||||
<title>A flow executor using a client-side continuation-based execution repository</title>
|
||||
<programlisting>
|
||||
<flow:executor id="flowExecutor" registry-ref="flowRegistry" repository-type="client"/>
|
||||
<flow:executor id="flowExecutor" registry-ref="flowRegistry" repository-type="client"/>
|
||||
</programlisting>
|
||||
<para>
|
||||
This executor is configured with a continuation-based repository that serializes
|
||||
@@ -185,7 +185,7 @@
|
||||
<sect2 id="executor-custom-repo3">
|
||||
<title>A flow executor using a single key execution repository</title>
|
||||
<programlisting>
|
||||
<flow:executor id="flowExecutor" registry-ref="flowRegistry" repository-type="singleKey"/>
|
||||
<flow:executor id="flowExecutor" registry-ref="flowRegistry" repository-type="singleKey"/>>
|
||||
</programlisting>
|
||||
<para>
|
||||
This executor is configured with a simple repository that assigns a single
|
||||
@@ -193,6 +193,26 @@
|
||||
for the duration of the conversation.
|
||||
</para>
|
||||
</sect2>
|
||||
<sect2 id="executor-custom-repo4">
|
||||
<title>A flow executor setting custom conversation management attributes</title>
|
||||
<programlisting>
|
||||
<flow:executor id="flowExecutor" registry-ref="flowRegistry">
|
||||
<flow:repository type="continuation" max-conversations="5" max-continuations="30" conversation-manager-ref="conversationManager"/>
|
||||
</flow:executor>
|
||||
|
||||
<bean id="conversationManager" class="example.MyCustomConversationalStateManager"/>
|
||||
</programlisting>
|
||||
<para>
|
||||
This executor is configured with a continuation repository configured with custom settings for:
|
||||
<orderedlist>
|
||||
<listitem><para>The maximum number of active conversations per user session (5)</para></listitem>
|
||||
<listitem><para>The maximum number of restorable flow execution snapshots (continuations) per conversation (30)</para></listitem>
|
||||
<listitem><para>Where conversational state will be stored (via a custom conversationManager)</para></listitem>
|
||||
</orderedlist>
|
||||
The <literal>flow:repository</literal> child element is the more flexible form for configuring the flow execution repository.
|
||||
Use it or the convenient <literal>repository-type</literal> attribute, not both.
|
||||
</para>
|
||||
</sect2>
|
||||
<sect2 id="executor-excution-attributes">
|
||||
<title>A flow executor setting system execution attributes</title>
|
||||
<programlisting>
|
||||
@@ -227,7 +247,7 @@
|
||||
</flow-executor>
|
||||
|
||||
<!-- A FlowExecutionListener to observe the lifecycle of order-flow executions -->
|
||||
<bean id="listener" class="org.springframework.webflow.samples.sellitem.SellItemFlowExecutionListener"/>
|
||||
<bean id="listener" class="example.OrderFlowExecutionListener"/>
|
||||
</programlisting>
|
||||
<para>
|
||||
This executor is configured to apply the execution listener to the "order-flow".
|
||||
@@ -503,7 +523,8 @@
|
||||
<para>
|
||||
Spring Web Flow integrates with JSF. The JSF integration relies on custom implementations of
|
||||
core JSF artifacts such as navigation handler and phase listener to drive the
|
||||
execution of flows.
|
||||
execution of flows. In addition, it relies on custom Variable and Property Resolvers to
|
||||
access flow execution variables from JSF components.
|
||||
</para>
|
||||
<sect2 id="executor-jsf-simple">
|
||||
<title>A typical faces-config.xml file</title>
|
||||
@@ -513,18 +534,61 @@
|
||||
<navigation-handler>
|
||||
org.springframework.webflow.executor.jsf.FlowNavigationHandler
|
||||
</navigation-handler>
|
||||
<variable-resolver>
|
||||
org.springframework.webflow.executor.jsf.FlowExecutionVariableResolver
|
||||
</variable-resolver>
|
||||
<property-resolver>
|
||||
org.springframework.webflow.executor.jsf.FlowPropertyResolver
|
||||
org.springframework.webflow.executor.jsf.FlowExecutionPropertyResolver
|
||||
</property-resolver>
|
||||
</application>
|
||||
|
||||
<lifecycle>
|
||||
<phase-listener>org.springframework.webflow.executor.jsf.FlowPhaseListener</phase-listener>
|
||||
</lifecycle>
|
||||
</faces-config>
|
||||
</programlisting>
|
||||
</sect>
|
||||
<sect2 id="executor-jsf-launch-get">
|
||||
<title>Launching a flow execution - command link</title>
|
||||
<programlisting>
|
||||
<h:commandLink value="Go" action="flowId:myflow"/>
|
||||
</programlisting>
|
||||
</sect2>
|
||||
<sect2 id="executor-jsf-resume-form">
|
||||
<title>Resuming a flow execution - form bound to flow execution variables</title>
|
||||
<programlisting>
|
||||
<h:form id="form">
|
||||
...
|
||||
<h:inputText id="propertyName" value="#{flowExecution.flashScope.aFlashScopeAttribute}"/>
|
||||
<h:inputText id="propertyName" value="#{flowExecution.flowScope.aFlowScopeAttribute}"/>
|
||||
<h:inputText id="propertyName" value="#{flowExecution.conversationScope.aConversationScopeAttribute}"/>
|
||||
|
||||
<h:inputText id="propertyName" value="#{flowExecution.anAttributeToSearchForAcrossAllScopes}"/>
|
||||
...
|
||||
<input type="hidden" name="_flowExecutionKey" value="${flowExecutionKey}">
|
||||
<h:commandButton type="submit" value="Next" action="submit"/>
|
||||
</h:form>
|
||||
</programlisting>
|
||||
</sect2>
|
||||
<sect2 id="executor-jsf-simple">
|
||||
<title>A pre Spring Web Flow 1.0.2 faces-config.xml file</title>
|
||||
<para>
|
||||
Before Spring Web Flow 1.0.2 Spring Web Flow only supported resolving variables in flow scope
|
||||
(and not the other scopes such as flash and conversation shown above). This configuration is still supported
|
||||
for backwards compatibility reasons and follows:
|
||||
</para>
|
||||
<programlisting>
|
||||
<faces-config>
|
||||
<application>
|
||||
<navigation-handler>
|
||||
org.springframework.webflow.executor.jsf.FlowNavigationHandler
|
||||
</navigation-handler>
|
||||
<variable-resolver>
|
||||
org.springframework.webflow.executor.jsf.FlowVariableResolver
|
||||
</variable-resolver>
|
||||
<variable-resolver>
|
||||
org.springframework.web.jsf.DelegatingVariableResolver
|
||||
</variable-resolver>
|
||||
<variable-resolver>
|
||||
org.springframework.web.jsf.WebApplicationContextVariableResolver
|
||||
</variable-resolver>
|
||||
<property-resolver>
|
||||
org.springframework.webflow.executor.jsf.FlowPropertyResolver
|
||||
</property-resolver>
|
||||
</application>
|
||||
|
||||
<lifecycle>
|
||||
@@ -533,18 +597,12 @@
|
||||
</faces-config>
|
||||
</programlisting>
|
||||
</sect2>
|
||||
<sect2 id="executor-jsf-launch-get">
|
||||
<title>Launching a flow execution - command link</title>
|
||||
<programlisting>
|
||||
<h:commandLink value="Go" action="flowId:myflow"/>
|
||||
</programlisting>
|
||||
</sect2>
|
||||
<sect2 id="executor-jsf-resume-form">
|
||||
<title>Resuming a flow execution - form</title>
|
||||
<title>Resuming a flow execution - pre 1.0.2 form bound to flow scope variables</title>
|
||||
<programlisting>
|
||||
<h:form id="form">
|
||||
...
|
||||
<h:inputText id="propertyName" value="#{flowScope.managedBeanName.propertyName}"/>
|
||||
<h:inputText id="propertyName" value="#{flowScope.aFlowScopeAttribute}"/>
|
||||
...
|
||||
<input type="hidden" name="_flowExecutionKey" value="${flowExecutionKey}">
|
||||
<h:commandButton type="submit" value="Next" action="submit"/>
|
||||
|
||||
@@ -52,23 +52,21 @@ import org.springframework.webflow.executor.support.RequestParameterFlowExecutor
|
||||
import org.springframework.webflow.executor.support.ResponseInstructionHandler;
|
||||
|
||||
/**
|
||||
* JSF phase listener that is responsible for managing a {@link FlowExecution}
|
||||
* object representing an active user conversation so that other JSF artifacts
|
||||
* that execute in different phases of the JSF lifecycle may have access to it.
|
||||
* <p> This phase listener implements the following algorithm: <ul> <li>On
|
||||
* BEFORE_RESTORE_VIEW, restore the {@link FlowExecution} the user is
|
||||
* participating in if a call to
|
||||
* {@link FlowExecutorArgumentHandler#extractFlowExecutionKey(ExternalContext)}
|
||||
* returns a submitted flow execution identifier. Place the restored flow
|
||||
* execution in a holder that other JSF artifacts such as VariableResolvers,
|
||||
* PropertyResolvers, and NavigationHandlers may access during the request
|
||||
* lifecycle. <li>On BEFORE_RENDER_RESPONSE, if a flow execution was restored
|
||||
* in the RESTORE_VIEW phase generate a new key for identifying the updated
|
||||
* execution within a the selected {@link FlowExecutionRepository}. Expose
|
||||
* managed flow execution attributes to the views before rendering. <li>On
|
||||
* AFTER_RENDER_RESPONSE, if a flow execution was restored in the RESTORE_VIEW
|
||||
* phase <em>save</em> the updated execution to the repository using the new
|
||||
* key generated in the BEFORE_RENDER_RESPONSE phase. </ul>
|
||||
* JSF phase listener that is responsible for managing a {@link FlowExecution} object representing an active user
|
||||
* conversation so that other JSF artifacts that execute in different phases of the JSF lifecycle may have access to it.
|
||||
* <p>
|
||||
* This phase listener implements the following algorithm:
|
||||
* <ul>
|
||||
* <li>On BEFORE_RESTORE_VIEW, restore the {@link FlowExecution} the user is participating in if a call to
|
||||
* {@link FlowExecutorArgumentHandler#extractFlowExecutionKey(ExternalContext)} returns a submitted flow execution
|
||||
* identifier. Place the restored flow execution in a holder that other JSF artifacts such as VariableResolvers,
|
||||
* PropertyResolvers, and NavigationHandlers may access during the request lifecycle.
|
||||
* <li>On BEFORE_RENDER_RESPONSE, if a flow execution was restored in the RESTORE_VIEW phase generate a new key for
|
||||
* identifying the updated execution within a the selected {@link FlowExecutionRepository}. Expose managed flow
|
||||
* execution attributes to the views before rendering.
|
||||
* <li>On AFTER_RENDER_RESPONSE, if a flow execution was restored in the RESTORE_VIEW phase <em>save</em> the updated
|
||||
* execution to the repository using the new key generated in the BEFORE_RENDER_RESPONSE phase.
|
||||
* </ul>
|
||||
*
|
||||
* @author Colin Sampaleanu
|
||||
* @author Keith Donald
|
||||
@@ -79,27 +77,24 @@ public class FlowPhaseListener implements PhaseListener {
|
||||
* Logger, usable by subclasses.
|
||||
*/
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
|
||||
/**
|
||||
* A helper for handling arguments needed by this phase listener to resume and launch flow executions.
|
||||
*/
|
||||
private FlowExecutorArgumentHandler argumentHandler = new RequestParameterFlowExecutorArgumentHandler();
|
||||
|
||||
/**
|
||||
* The service responsible for mapping attributes of an
|
||||
* {@link ExternalContext} to a new {@link FlowExecution} during the
|
||||
* {@link #launch(String, ExternalContext) launch flow} operation.
|
||||
* The service responsible for mapping attributes of an {@link ExternalContext} to a new {@link FlowExecution}
|
||||
* during the {@link #launch(String, ExternalContext) launch flow} operation.
|
||||
* <p>
|
||||
* This allows developers to control what attributes are made available in
|
||||
* the <code>inputMap</code> to new top-level flow executions. The
|
||||
* starting execution may then choose to map that available input into its
|
||||
* own local scope.
|
||||
* This allows developers to control what attributes are made available in the <code>inputMap</code> to new
|
||||
* top-level flow executions. The starting execution may then choose to map that available input into its own local
|
||||
* scope.
|
||||
* <p>
|
||||
* The default implementation simply exposes all request parameters as flow
|
||||
* execution input attributes. May be null.
|
||||
* The default implementation simply exposes all request parameters as flow execution input attributes. May be null.
|
||||
*/
|
||||
private AttributeMapper inputMapper = new RequestParameterInputMapper();
|
||||
|
||||
|
||||
/**
|
||||
* Resolves selected Web Flow view names to JSF view ids.
|
||||
*/
|
||||
@@ -127,17 +122,16 @@ public class FlowPhaseListener implements PhaseListener {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the service responsible for mapping attributes of an
|
||||
* {@link ExternalContext} to a new {@link FlowExecution} during a launch flow operation.
|
||||
* Sets the service responsible for mapping attributes of an {@link ExternalContext} to a new {@link FlowExecution}
|
||||
* during a launch flow operation.
|
||||
* <p>
|
||||
* The default implementation simply exposes all request parameters as flow
|
||||
* execution input attributes. May be null.
|
||||
* The default implementation simply exposes all request parameters as flow execution input attributes. May be null.
|
||||
* @see RequestParameterInputMapper
|
||||
*/
|
||||
public void setInputMapper(AttributeMapper inputMapper) {
|
||||
this.inputMapper = inputMapper;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the JSF view id resolver used by this phase listener.
|
||||
*/
|
||||
@@ -157,11 +151,7 @@ public class FlowPhaseListener implements PhaseListener {
|
||||
}
|
||||
|
||||
public void beforePhase(PhaseEvent event) {
|
||||
if (event.getPhaseId() == PhaseId.RESTORE_VIEW) {
|
||||
ExternalContextHolder.setExternalContext(new JsfExternalContext(event.getFacesContext()));
|
||||
restoreFlowExecution(event.getFacesContext());
|
||||
}
|
||||
else if (event.getPhaseId() == PhaseId.RENDER_RESPONSE) {
|
||||
if (event.getPhaseId() == PhaseId.RENDER_RESPONSE) {
|
||||
if (FlowExecutionHolderUtils.isFlowExecutionRestored(event.getFacesContext())) {
|
||||
prepareResponse(getCurrentContext(), FlowExecutionHolderUtils.getFlowExecutionHolder(event
|
||||
.getFacesContext()));
|
||||
@@ -170,7 +160,10 @@ public class FlowPhaseListener implements PhaseListener {
|
||||
}
|
||||
|
||||
public void afterPhase(PhaseEvent event) {
|
||||
if (event.getPhaseId() == PhaseId.RENDER_RESPONSE) {
|
||||
if (event.getPhaseId() == PhaseId.RESTORE_VIEW) {
|
||||
ExternalContextHolder.setExternalContext(new JsfExternalContext(event.getFacesContext()));
|
||||
restoreFlowExecution(event.getFacesContext());
|
||||
} else if (event.getPhaseId() == PhaseId.RENDER_RESPONSE) {
|
||||
try {
|
||||
if (FlowExecutionHolderUtils.isFlowExecutionRestored(event.getFacesContext())) {
|
||||
FlowExecutionHolder holder = FlowExecutionHolderUtils.getFlowExecutionHolder(event
|
||||
@@ -191,20 +184,25 @@ public class FlowPhaseListener implements PhaseListener {
|
||||
}
|
||||
}
|
||||
|
||||
private JsfExternalContext getCurrentContext() {
|
||||
return (JsfExternalContext) ExternalContextHolder.getExternalContext();
|
||||
}
|
||||
|
||||
protected void restoreFlowExecution(FacesContext facesContext) {
|
||||
JsfExternalContext context = new JsfExternalContext(facesContext);
|
||||
if (argumentHandler.isFlowExecutionKeyPresent(context)) {
|
||||
if (argumentHandler.isFlowExecutionKeyPresent(context) || isFlowExecutionKeyInViewRoot(facesContext)) {
|
||||
// restore flow execution from repository so it will be
|
||||
// available to variable/property resolvers and the flow
|
||||
// navigation handler (this could happen as part of a submission or
|
||||
// flow execution redirect)
|
||||
FlowExecutionRepository repository = getRepository(context);
|
||||
FlowExecutionKey flowExecutionKey = repository.parseFlowExecutionKey(argumentHandler
|
||||
.extractFlowExecutionKey(context));
|
||||
FlowExecutionKey flowExecutionKey;
|
||||
if (argumentHandler.isFlowExecutionKeyPresent(context)) {
|
||||
// extract it in the "traditional way" (request parameter in url by default)
|
||||
flowExecutionKey = repository.parseFlowExecutionKey(argumentHandler.extractFlowExecutionKey(context));
|
||||
}
|
||||
else {
|
||||
// restore the key from an attribute in the root of the component tree
|
||||
flowExecutionKey = repository.parseFlowExecutionKey((String)facesContext.getViewRoot().getAttributes().get("_flowExecutionKey"));
|
||||
// remove it (it should always be placed back before response rendering)
|
||||
facesContext.getViewRoot().getAttributes().remove("_flowExecutionKey");
|
||||
}
|
||||
FlowExecutionLock lock = repository.getLock(flowExecutionKey);
|
||||
lock.lock();
|
||||
FlowExecution flowExecution = repository.getFlowExecution(flowExecutionKey);
|
||||
@@ -231,9 +229,8 @@ public class FlowPhaseListener implements PhaseListener {
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory method that creates the input attribute map for a newly created
|
||||
* {@link FlowExecution}. This implementation uses the registered input mapper,
|
||||
* if any.
|
||||
* Factory method that creates the input attribute map for a newly created {@link FlowExecution}. This
|
||||
* implementation uses the registered input mapper, if any.
|
||||
* @param context the external context
|
||||
* @return the input map, or null if no input
|
||||
*/
|
||||
@@ -295,9 +292,74 @@ public class FlowPhaseListener implements PhaseListener {
|
||||
}
|
||||
Map requestMap = facesContext.getExternalContext().getRequestMap();
|
||||
String flowExecutionKey = holder.getFlowExecution().isActive() ? holder.getFlowExecutionKey().toString() : null;
|
||||
if (flowExecutionKey != null) {
|
||||
// expose to view root for preservation in the component tree
|
||||
if (viewRootAttributeMapPresent(facesContext)) {
|
||||
facesContext.getViewRoot().getAttributes().put("_flowExecutionKey", flowExecutionKey);
|
||||
}
|
||||
}
|
||||
argumentHandler.exposeFlowExecutionContext(flowExecutionKey, holder.getFlowExecution(), requestMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the current flow execution in the repository.
|
||||
* @param context the external context
|
||||
* @param holder the current flow execution holder
|
||||
*/
|
||||
protected void saveFlowExecution(JsfExternalContext context, FlowExecutionHolder holder) {
|
||||
FlowExecution flowExecution = holder.getFlowExecution();
|
||||
FlowExecutionRepository repository = getRepository(context);
|
||||
if (flowExecution.isActive()) {
|
||||
// save the flow execution out to the repository
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Saving continuation to repository with key " + holder.getFlowExecutionKey());
|
||||
}
|
||||
repository.putFlowExecution(holder.getFlowExecutionKey(), flowExecution);
|
||||
}
|
||||
else {
|
||||
if (holder.getFlowExecutionKey() != null) {
|
||||
// remove the flow execution from the repository
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Removing execution in repository with key '" + holder.getFlowExecutionKey() + "'");
|
||||
}
|
||||
repository.removeFlowExecution(holder.getFlowExecutionKey());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// private helpers
|
||||
|
||||
private JsfExternalContext getCurrentContext() {
|
||||
return (JsfExternalContext) ExternalContextHolder.getExternalContext();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the root of the component tree contains the flow execution key attribute, used
|
||||
* to restore the flow execution on subsequent reqests.
|
||||
* @param facesContext the key
|
||||
* @return true if yes, false otherwise
|
||||
*/
|
||||
private boolean isFlowExecutionKeyInViewRoot(FacesContext facesContext) {
|
||||
if (viewRootAttributeMapPresent(facesContext)) {
|
||||
return facesContext.getViewRoot().getAttributes().containsKey("_flowExecutionKey");
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple little helper that returns true if the view root attribute map is non-null.
|
||||
* @param facesContext the faces context
|
||||
* @return true if so, false otherwise
|
||||
*/
|
||||
private boolean viewRootAttributeMapPresent(FacesContext facesContext) {
|
||||
if (facesContext.getViewRoot() != null && facesContext.getViewRoot().getAttributes() != null) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void updateViewRoot(FacesContext facesContext, String viewId) {
|
||||
UIViewRoot viewRoot = facesContext.getViewRoot();
|
||||
if (viewRoot == null || hasViewChanged(viewRoot, viewId)) {
|
||||
@@ -332,31 +394,9 @@ public class FlowPhaseListener implements PhaseListener {
|
||||
}
|
||||
}
|
||||
|
||||
protected void saveFlowExecution(JsfExternalContext context, FlowExecutionHolder holder) {
|
||||
FlowExecution flowExecution = holder.getFlowExecution();
|
||||
FlowExecutionRepository repository = getRepository(context);
|
||||
if (flowExecution.isActive()) {
|
||||
// save the flow execution out to the repository
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Saving continuation to repository with key " + holder.getFlowExecutionKey());
|
||||
}
|
||||
repository.putFlowExecution(holder.getFlowExecutionKey(), flowExecution);
|
||||
}
|
||||
else {
|
||||
if (holder.getFlowExecutionKey() != null) {
|
||||
// remove the flow execution from the repository
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Removing execution in repository with key '" + holder.getFlowExecutionKey() + "'");
|
||||
}
|
||||
repository.removeFlowExecution(holder.getFlowExecutionKey());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility method needed needed only because we can not rely on JSF
|
||||
* RequestMap supporting Map's putAll method. Tries putAll, falls back to
|
||||
* individual adds
|
||||
* Utility method needed needed only because we can not rely on JSF RequestMap supporting Map's putAll method. Tries
|
||||
* putAll, falls back to individual adds
|
||||
* @param targetMap the target map to add the model data to
|
||||
* @param map the model data to add to the target map
|
||||
*/
|
||||
@@ -387,8 +427,7 @@ public class FlowPhaseListener implements PhaseListener {
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard default view id resolver which uses the web flow view name as
|
||||
* the jsf view id
|
||||
* Standard default view id resolver which uses the web flow view name as the jsf view id
|
||||
*/
|
||||
public static class DefaultViewIdMapper implements ViewIdMapper {
|
||||
public String mapViewId(String viewName) {
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package org.springframework.webflow.executor.support;
|
||||
|
||||
import org.springframework.core.NestedRuntimeException;
|
||||
import org.springframework.webflow.execution.ViewSelection;
|
||||
import org.springframework.webflow.execution.support.ApplicationView;
|
||||
import org.springframework.webflow.execution.support.ExternalRedirect;
|
||||
@@ -99,8 +100,8 @@ public abstract class ResponseInstructionHandler {
|
||||
return handle(responseInstruction);
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new RuntimeException(
|
||||
"Unexpected exception handling response instruction " + responseInstruction + ": " + e);
|
||||
throw new RuntimeResponseHandlingException(
|
||||
"Unexpected exception handling response instruction " + responseInstruction + "", e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -149,4 +150,14 @@ public abstract class ResponseInstructionHandler {
|
||||
* @see ViewSelection#NULL_VIEW
|
||||
*/
|
||||
protected abstract void handleNull() throws Exception;
|
||||
}
|
||||
|
||||
/**
|
||||
* Thrown during handleQuietly.
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public static class RuntimeResponseHandlingException extends NestedRuntimeException {
|
||||
public RuntimeResponseHandlingException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user