Fixed fallback to JSF navigation when inside a restored flow execution.

This commit is contained in:
Erwin Vervaet
2008-06-24 10:29:58 +00:00
parent 6f31fd413b
commit 5a1604b3c5
6 changed files with 44 additions and 6 deletions

View File

@@ -18,8 +18,9 @@ Package org.springframework.webflow.executor
* In a JSF 1.2 environment, SWF will now correctly maintain the "java.faces.ViewState" parameter accross flow
execution redirects (SWF-445).
* FlowPhaseListener now maintains FacesMessages accross a flow execution redirect by temporarily storing them in
flash scope (SWF-745).
the flow execution (SWF-745).
* FlowPhaseListener will now save the JSF component state before a flow execution redirect is issued (SWF-747).
* Fixed FlowPhaseListener to correctly deal with scenarios where we fallback to standard JSF navigation.
Changes in version 1.0.5 (03.10.2007)
-------------------------------------

View File

@@ -37,6 +37,10 @@ import org.springframework.webflow.executor.support.AutowiringSupport;
* require special autowiring behaviour, consider overriding the {@link #autowire(ScopeType, String, Object)} method.
* <p>
* This phase listener will use the root web application context as {@link AutowireCapableBeanFactory}.
* <p>
* Note about customization: since PhaseListeners managed directly by the JSF provider cannot benefit from dependency
* injection, See Spring's {@link org.springframework.web.jsf.DelegatingPhaseListenerMulticaster} when you need to
* customize an AutowiringPhaseListener instance.
*
* @see FlowPhaseListener
* @see WebApplicationContextUtils#getWebApplicationContext(ServletContext)

View File

@@ -54,10 +54,16 @@ public class FlowExecutionHolder implements Serializable {
private FlowExecutionLock flowExecutionLock;
/**
* The currently selected view selection for this request.
* The currently selected view for this request.
*/
private ViewSelection viewSelection;
/**
* Flag that indicates whether or not it was Web Flow that processed navigation, or if there was fallback to the
* standard JSF navigation handler. Defaults to false.
*/
private boolean navigationFallback = false;
/**
* Creates a new flow execution holder for a flow execution that has not yet been placed in a repository.
* @param flowExecution the flow execution to hold
@@ -130,6 +136,24 @@ public class FlowExecutionHolder implements Serializable {
this.viewSelection = viewSelection;
}
/**
* Set whether or not fallback happened to the standard JSF navigation handler. Defaults to false.
*
* @since 1.0.6
*/
public void setNavigationFallback(boolean b) {
this.navigationFallback = b;
}
/**
* Returns whether or not fallback happened to the standard JSF navigation handler.
*
* @since 1.0.6
*/
public boolean isNavigationFallback() {
return navigationFallback;
}
/**
* Replace the current flow execution with the one provided. This method will clear out all state associated with
* the original execution and unlock it if necessary.
@@ -138,6 +162,7 @@ public class FlowExecutionHolder implements Serializable {
public void replaceWith(FlowExecution flowExecution) {
this.flowExecutionKey = null;
this.viewSelection = null;
this.navigationFallback = false;
unlockFlowExecutionIfNecessary();
this.flowExecution = flowExecution;
}

View File

@@ -54,7 +54,7 @@ public class FlowExecutionKeyStateHolder extends UIComponentBase {
public static final String COMPONENT_ID = "FlowExecutionKeyStateHolder";
/**
* The key value
* The key value.
*/
private String flowExecutionKey;
@@ -65,7 +65,7 @@ public class FlowExecutionKeyStateHolder extends UIComponentBase {
}
public void setId(String id) {
// Do nothing so as to ensure the id never gets overwritten.
// do nothing so as to ensure the id never gets overwritten.
return;
}

View File

@@ -170,12 +170,13 @@ public class FlowNavigationHandler extends DecoratingNavigationHandler {
} else {
// not a launch request - see if this is a resume request to continue an existing execution
if (FlowExecutionHolderUtils.isFlowExecutionRestored(facesContext)) {
FlowExecutionHolder holder = FlowExecutionHolderUtils.getFlowExecutionHolder(facesContext);
// a flow execution has been restored - see if we need to signal an event against it
if (argumentExtractor.isEventIdPresent(context)) {
// signal the event against the current flow execution
String eventId = argumentExtractor.extractEventId(context);
try {
FlowExecutionHolder holder = FlowExecutionHolderUtils.getFlowExecutionHolder(facesContext);
ViewSelection selectedView = holder.getFlowExecution().signalEvent(eventId, context);
// set the next view to render
holder.setViewSelection(selectedView);
@@ -185,6 +186,7 @@ public class FlowNavigationHandler extends DecoratingNavigationHandler {
+ "'; falling back to standard navigation handler.");
}
// not a valid event in the current state: proceed with standard navigation
holder.setNavigationFallback(true);
originalNavigationHandler.handleNavigation(facesContext, fromAction, outcome);
}
}

View File

@@ -382,13 +382,19 @@ public class FlowPhaseListener implements PhaseListener {
* @param holder the holder
*/
protected void prepareResponse(final JsfExternalContext context, final FlowExecutionHolder holder) {
if (holder.isNavigationFallback()) {
// navigation was not processed by Web Flow, but by the standard JSF navigation handler
// just leave response rendering up to JSF
return;
}
ViewSelection selectedView = holder.getViewSelection();
if (selectedView == null) {
// no navigation event has been processed - simply refresh the execution with the same key
selectedView = holder.getFlowExecution().refresh(context);
holder.setViewSelection(selectedView);
} else {
// an navigation event has been processed - generate a new flow execution key if necessary
// a navigation event has been processed - generate a new flow execution key if necessary
generateKey(context, holder);
}
new ResponseInstructionHandler() {