delegating flow resolver
This commit is contained in:
@@ -1,33 +1,22 @@
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<!DOCTYPE faces-config PUBLIC
|
||||
"-//Sun Microsystems, Inc.//DTD JavaServer Faces Config 1.0//EN"
|
||||
"http://java.sun.com/dtd/web-facesconfig_1_0.dtd">
|
||||
|
||||
<faces-config>
|
||||
<application>
|
||||
<!-- Navigation handler proxy for a Spring-managed bean that is the Web Flow Navigation Handler -->
|
||||
<navigation-handler>
|
||||
org.springframework.web.jsf.DelegatingNavigationHandlerProxy
|
||||
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>
|
||||
<variable-resolver>
|
||||
org.springframework.webflow.executor.jsf.FlowVariableResolver
|
||||
</variable-resolver>
|
||||
<variable-resolver>
|
||||
org.springframework.web.jsf.DelegatingVariableResolver
|
||||
</variable-resolver>
|
||||
<!-- Extended "webApplicationContext" resolver -->
|
||||
<variable-resolver>
|
||||
org.springframework.web.jsf.WebApplicationContextVariableResolver
|
||||
</variable-resolver>
|
||||
</application>
|
||||
|
||||
<lifecycle>
|
||||
<!-- Multi-caster that broadcasts phase events to all PhaseListeners managed by Spring -->
|
||||
<phase-listener>org.springframework.web.jsf.DelegatingPhaseListenerMulticaster</phase-listener>
|
||||
</lifecycle>
|
||||
|
||||
<lifecycle>
|
||||
<phase-listener>org.springframework.webflow.executor.jsf.FlowPhaseListener</phase-listener>
|
||||
</lifecycle>
|
||||
</faces-config>
|
||||
@@ -3,7 +3,9 @@
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/webflow
|
||||
http://www.springframework.org/schema/webflow/spring-webflow-1.0.xsd">
|
||||
|
||||
|
||||
<var name="sale" class="org.springframework.webflow.samples.sellitem.Sale"/>
|
||||
|
||||
<start-state idref="enterPriceAndItemCount" />
|
||||
|
||||
<view-state id="enterPriceAndItemCount" view="/priceAndItemCountForm.jsp">
|
||||
|
||||
@@ -16,25 +16,4 @@
|
||||
<flow:location path="/WEB-INF/flows/sellitem-flow.xml" />
|
||||
</flow:registry>
|
||||
|
||||
<!-- A "Sale" managed bean created by JSF for each 'sellitem' flow execution -->
|
||||
<bean name="sale" class="org.springframework.webflow.samples.sellitem.Sale" scope="prototype" />
|
||||
|
||||
<!--
|
||||
Spring configured flow navigation handler delegate, allowing for custom configuration
|
||||
using standard dependency injection techniques.
|
||||
|
||||
Note: this definition is optional; you may choose to simply specify your FlowNavigationHandler
|
||||
in your faces-config.xml if its defaults meet your needs.
|
||||
-->
|
||||
<bean id="jsfNavigationHandler" class="org.springframework.webflow.executor.jsf.FlowNavigationHandler" />
|
||||
|
||||
<!--
|
||||
Spring configured flow phase listener delegate, allowing for custom configuration using
|
||||
standard dependency injection techniques.
|
||||
|
||||
Note: this definition is optional; you may choose to simply specify your FlowPhaseListener
|
||||
in your faces-config.xml if its defaults meet your needs.
|
||||
-->
|
||||
<bean id="flowPhaseListener" class="org.springframework.webflow.executor.jsf.FlowPhaseListener" />
|
||||
|
||||
</beans>
|
||||
@@ -21,17 +21,17 @@
|
||||
<h2>Select category</h2>
|
||||
<table>
|
||||
<tr class="readOnly">
|
||||
<td>Price:</td><td><h:outputText value="#{flowScope.sale.price}"/></td>
|
||||
<td>Price:</td><td><h:outputText value="#{sale.price} "/></td>
|
||||
</tr>
|
||||
<tr class="readOnly">
|
||||
<td>Item count:</td><td><h:outputText value="#{flowScope.sale.itemCount}"/></td>
|
||||
<td>Item count:</td><td><h:outputText value="#{sale.itemCount}"/></td>
|
||||
</tr>
|
||||
|
||||
<h:form id="categoryForm">
|
||||
<tr>
|
||||
<td>Category:</td>
|
||||
<td>
|
||||
<h:selectOneMenu value="#{flowScope.sale.category}">
|
||||
<h:selectOneMenu value="#{sale.category}">
|
||||
<f:selectItem itemLabel="None (0.02 discount rate)" itemValue=""/>
|
||||
<f:selectItem itemLabel="Cat. A (0.1 discount rate when more than 100 items)" itemValue="A"/>
|
||||
<f:selectItem itemLabel="Cat. B (0.2 discount rate when more than 200 items)" itemValue="B"/>
|
||||
@@ -41,12 +41,11 @@
|
||||
<tr>
|
||||
<td>Is shipping required?:</td>
|
||||
<td>
|
||||
<h:selectBooleanCheckbox value="#{flowScope.sale.shipping}"/>
|
||||
<h:selectBooleanCheckbox value="#{sale.shipping}"/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2" class="buttonBar">
|
||||
<input type="hidden" name="_flowExecutionKey" value="${flowExecutionKey}"/>
|
||||
<h:commandButton type="submit" value="Next" action="submit" immediate="false" />
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
<f:view>
|
||||
<div id="content">
|
||||
<div id="insert"><img src="images/webflow-logo.jpg" /></div>
|
||||
|
||||
<h2>Enter price and item count</h2>
|
||||
<hr>
|
||||
<table>
|
||||
@@ -26,7 +25,7 @@
|
||||
<tr>
|
||||
<td>Price:</td>
|
||||
<td>
|
||||
<h:inputText id="price" value="#{flowScope.sale.price}" required="true">
|
||||
<h:inputText id="price" value="#{sale.price}" required="true">
|
||||
<f:validateDoubleRange minimum="0.01"/>
|
||||
</h:inputText>
|
||||
</td>
|
||||
@@ -37,7 +36,7 @@
|
||||
<tr>
|
||||
<td>Item count:</td>
|
||||
<td>
|
||||
<h:inputText id="itemCount" value="#{flowScope.sale.itemCount}" required="true">
|
||||
<h:inputText id="itemCount" value="#{sale.itemCount}" required="true">
|
||||
<f:validateLongRange minimum="1"/>
|
||||
</h:inputText>
|
||||
</td>
|
||||
@@ -47,7 +46,6 @@
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2" class="buttonBar">
|
||||
<input type="hidden" name="_flowExecutionKey" value="${flowExecutionKey}"/>
|
||||
<h:commandButton type="submit" value="Next" action="submit" immediate="false" />
|
||||
</td>
|
||||
<td></td>
|
||||
|
||||
@@ -22,22 +22,22 @@
|
||||
<hr>
|
||||
<table>
|
||||
<tr class="readOnly">
|
||||
<td>Price:</td><td><h:outputText value="#{flowScope.sale.price}"/></td>
|
||||
<td>Price:</td><td><h:outputText value="#{sale.price}"/></td>
|
||||
</tr>
|
||||
<tr class="readOnly">
|
||||
<td>Item count:</td><td><h:outputText value="#{flowScope.sale.itemCount}"/></td>
|
||||
<td>Item count:</td><td><h:outputText value="#{sale.itemCount}"/></td>
|
||||
</tr>
|
||||
<tr class="readOnly">
|
||||
<td>Category:</td><td><h:outputText value="#{flowScope.sale.category}"/></td>
|
||||
<td>Category:</td><td><h:outputText value="#{sale.category}"/></td>
|
||||
<tr class="readOnly">
|
||||
<td>Shipping:</td><td><h:outputText value="#{flowScope.sale.shipping}"/></td>
|
||||
<td>Shipping:</td><td><h:outputText value="#{sale.shipping}"/></td>
|
||||
</tr>
|
||||
|
||||
<h:form id="shippingForm">
|
||||
<tr>
|
||||
<td>Shipping type:</td>
|
||||
<td>
|
||||
<h:selectOneMenu value="#{flowScope.sale.shippingType}">
|
||||
<h:selectOneMenu value="#{sale.shippingType}">
|
||||
<f:selectItem itemLabel="Standard (10 extra cost)" itemValue="S"/>
|
||||
<f:selectItem itemLabel="Express (20 extra cost)" itemValue="E"/>
|
||||
</h:selectOneMenu>
|
||||
@@ -45,7 +45,6 @@
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2" class="buttonBar">
|
||||
<input type="hidden" name="_flowExecutionKey" value="${flowExecutionKey}"/>
|
||||
<h:commandButton type="submit" value="Next" action="submit" immediate="false" />
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* 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.jsf;
|
||||
|
||||
import javax.faces.context.FacesContext;
|
||||
import javax.faces.el.EvaluationException;
|
||||
import javax.faces.el.VariableResolver;
|
||||
|
||||
import org.springframework.webflow.execution.FlowExecution;
|
||||
|
||||
/**
|
||||
* Custom variable resolver that searches the current flow execution for variables to resolve.
|
||||
* The search algorithm looks in flash scope first, then flow scope, then conversation scope.
|
||||
* If no variable is found, this resolver delegates to the next resolver in the chain.
|
||||
*
|
||||
* Suitable for use along side other variable resolvers to support EL binding expressions like
|
||||
* {#bean.property} where "bean" could be a property in any supported scope.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public class DelegatingFlowVariableResolver extends VariableResolver {
|
||||
|
||||
/**
|
||||
* The standard variable resolver to delegate to if this one doesn't apply.
|
||||
*/
|
||||
private VariableResolver resolverDelegate;
|
||||
|
||||
/**
|
||||
* Create a new FlowExecutionVariableResolver, using the given original VariableResolver.
|
||||
* <p>
|
||||
* A JSF implementation will automatically pass its original resolver into the constructor of a configured resolver,
|
||||
* provided that there is a corresponding constructor argument.
|
||||
*
|
||||
* @param resolverDelegate the original VariableResolver
|
||||
*/
|
||||
public DelegatingFlowVariableResolver(VariableResolver resolverDelegate) {
|
||||
this.resolverDelegate = resolverDelegate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the original VariableResolver that this resolver delegates to.
|
||||
*/
|
||||
protected final VariableResolver getResolverDelegate() {
|
||||
return resolverDelegate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check flash/flow/conversation scope. If the variable is not found, delegate to next variable resolver in the
|
||||
* chain.
|
||||
*/
|
||||
public Object resolveVariable(FacesContext context, String name) throws EvaluationException {
|
||||
FlowExecution execution = FlowExecutionHolderUtils.getRequiredCurrentFlowExecution(context);
|
||||
// try flash/flow/conversation
|
||||
if (execution.getActiveSession().getFlashMap().contains(name)) {
|
||||
return execution.getActiveSession().getFlashMap().get(name);
|
||||
}
|
||||
else if (execution.getActiveSession().getScope().contains(name)) {
|
||||
return execution.getActiveSession().getScope().get(name);
|
||||
}
|
||||
else if (execution.getConversationScope().contains(name)) {
|
||||
return execution.getConversationScope().get(name);
|
||||
}
|
||||
else {
|
||||
// neither found a value, delegate to next resolver in the chain
|
||||
return resolverDelegate.resolveVariable(context, name);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,13 +17,15 @@ package org.springframework.webflow.executor.jsf;
|
||||
|
||||
import javax.faces.context.ExternalContext;
|
||||
import javax.faces.context.FacesContext;
|
||||
import javax.faces.el.EvaluationException;
|
||||
|
||||
import org.springframework.webflow.execution.FlowExecution;
|
||||
|
||||
/**
|
||||
* A static utility class for accessing the current flow execution holder.
|
||||
* <p>
|
||||
* By default, the current flow execution holder is stored associated with the
|
||||
* current thread in the {@link FacesContext}'s
|
||||
* {@link ExternalContext#getRequestMap()}.
|
||||
* By default, the current flow execution holder is stored associated with the current thread in the
|
||||
* {@link FacesContext}'s {@link ExternalContext#getRequestMap()}.
|
||||
*
|
||||
* @author Keith Donald
|
||||
* @author Craig McClanahan
|
||||
@@ -36,7 +38,24 @@ public class FlowExecutionHolderUtils {
|
||||
* @return the flow execution holder, or <code>null</code> if none set.
|
||||
*/
|
||||
public static FlowExecutionHolder getFlowExecutionHolder(FacesContext context) {
|
||||
return (FlowExecutionHolder)context.getExternalContext().getRequestMap().get(getFlowExecutionHolderKey());
|
||||
return (FlowExecutionHolder) context.getExternalContext().getRequestMap().get(getFlowExecutionHolderKey());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current flow execution holder for the given faces context.
|
||||
* @param context faces context
|
||||
* @return the flow execution holder or <code>null</code> if none set
|
||||
* @throws EvaluationException if no flow execution was bound
|
||||
*/
|
||||
public static FlowExecution getRequiredCurrentFlowExecution(FacesContext context) throws EvaluationException {
|
||||
FlowExecutionHolder holder = getFlowExecutionHolder(context);
|
||||
if (holder != null) {
|
||||
return holder.getFlowExecution();
|
||||
}
|
||||
else {
|
||||
throw new EvaluationException(
|
||||
"FlowExecution is not bound to current thread context - has the flow ended or expired?");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -48,11 +67,17 @@ public class FlowExecutionHolderUtils {
|
||||
context.getExternalContext().getRequestMap().put(getFlowExecutionHolderKey(), holder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the flow execution has been restored in the current thread.
|
||||
* @param context the faces context
|
||||
* @return true if restored, false otherwise
|
||||
*/
|
||||
public static boolean isFlowExecutionRestored(FacesContext context) {
|
||||
return getFlowExecutionHolder(context) != null;
|
||||
}
|
||||
|
||||
private static String getFlowExecutionHolderKey() {
|
||||
return FlowExecutionHolder.class.getName();
|
||||
}
|
||||
|
||||
public static boolean isFlowExecutionRestored(FacesContext context) {
|
||||
return getFlowExecutionHolder(context) != null;
|
||||
}
|
||||
}
|
||||
@@ -72,12 +72,7 @@ public class FlowExecutionVariableResolver extends VariableResolver {
|
||||
return resolverDelegate.resolveVariable(context, name);
|
||||
}
|
||||
else {
|
||||
FlowExecutionHolder holder = FlowExecutionHolderUtils.getFlowExecutionHolder(context);
|
||||
if (holder == null)
|
||||
throw new EvaluationException("'" + FLOW_EXECUTION_VARIABLE_NAME
|
||||
+ "' variable prefix specified but a FlowExecution is not bound to current thread context: "
|
||||
+ "has the flow ended or expired?");
|
||||
return holder.getFlowExecution();
|
||||
return FlowExecutionHolderUtils.getRequiredCurrentFlowExecution(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -68,11 +68,7 @@ public class FlowVariableResolver extends VariableResolver {
|
||||
return resolverDelegate.resolveVariable(context, name);
|
||||
}
|
||||
else {
|
||||
FlowExecutionHolder holder = FlowExecutionHolderUtils.getFlowExecutionHolder(context);
|
||||
if (holder == null)
|
||||
throw new EvaluationException(
|
||||
"'flowScope' variable prefix specified but a FlowExecution is not bound to current thread context - has the flow ended or expired?");
|
||||
return holder.getFlowExecution();
|
||||
return FlowExecutionHolderUtils.getRequiredCurrentFlowExecution(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user