2.0.4 improvements: development mode, flow model parent registry fix, flow handler mapping, improved sample
This commit is contained in:
@@ -15,9 +15,6 @@
|
||||
*/
|
||||
package org.springframework.binding.mapping.results;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
|
||||
import org.springframework.binding.expression.EvaluationException;
|
||||
import org.springframework.binding.expression.PropertyNotFoundException;
|
||||
import org.springframework.binding.mapping.Result;
|
||||
@@ -68,11 +65,7 @@ public class SourceAccessError extends Result {
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
ToStringCreator creator = new ToStringCreator(this).append("errorCode", getErrorCode());
|
||||
StringWriter stringWriter = new StringWriter();
|
||||
PrintWriter writer = new PrintWriter(stringWriter);
|
||||
error.printStackTrace(writer);
|
||||
creator.append("exceptionStackTrace", stringWriter.toString());
|
||||
return creator.toString();
|
||||
return new ToStringCreator(this).append("errorCode", getErrorCode()).append("message", error.getMessage())
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,9 +15,6 @@
|
||||
*/
|
||||
package org.springframework.binding.mapping.results;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
|
||||
import org.springframework.binding.expression.EvaluationException;
|
||||
import org.springframework.binding.expression.PropertyNotFoundException;
|
||||
import org.springframework.binding.mapping.Result;
|
||||
@@ -72,11 +69,7 @@ public class TargetAccessError extends Result {
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
ToStringCreator creator = new ToStringCreator(this).append("errorCode", getErrorCode());
|
||||
StringWriter stringWriter = new StringWriter();
|
||||
PrintWriter writer = new PrintWriter(stringWriter);
|
||||
error.printStackTrace(writer);
|
||||
creator.append("stackTrace", stringWriter.toString());
|
||||
return creator.toString();
|
||||
return new ToStringCreator(this).append("errorCode", getErrorCode()).append("message", error.getMessage())
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,9 +15,6 @@
|
||||
*/
|
||||
package org.springframework.binding.mapping.results;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
|
||||
import org.springframework.binding.convert.ConversionExecutionException;
|
||||
import org.springframework.binding.mapping.Result;
|
||||
import org.springframework.core.style.ToStringCreator;
|
||||
@@ -76,12 +73,7 @@ public class TypeConversionError extends Result {
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
ToStringCreator creator = new ToStringCreator(this).append("originalValue", originalValue).append("targetType",
|
||||
targetType);
|
||||
StringWriter stringWriter = new StringWriter();
|
||||
PrintWriter writer = new PrintWriter(stringWriter);
|
||||
exception.printStackTrace(writer);
|
||||
creator.append("exceptionStackTrace", stringWriter.toString());
|
||||
return creator.toString();
|
||||
return new ToStringCreator(this).append("originalValue", originalValue).append("targetType", targetType)
|
||||
.append("message", exception.getMessage()).toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,15 +45,7 @@ public class FacesFlowBuilderServicesBeanDefinitionParser extends AbstractSingle
|
||||
parseConversionService(element, definitionBuilder);
|
||||
parseExpressionParser(element, definitionBuilder, parseEnableManagedBeans(element, definitionBuilder));
|
||||
parseViewFactoryCreator(element, definitionBuilder);
|
||||
}
|
||||
|
||||
private boolean parseEnableManagedBeans(Element element, BeanDefinitionBuilder definitionBuilder) {
|
||||
String enableManagedBeans = element.getAttribute("enable-managed-beans");
|
||||
if (StringUtils.hasText(enableManagedBeans)) {
|
||||
return Boolean.valueOf(enableManagedBeans).booleanValue();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
parseDevelopment(element, definitionBuilder);
|
||||
}
|
||||
|
||||
private void parseConversionService(Element element, BeanDefinitionBuilder definitionBuilder) {
|
||||
@@ -65,15 +57,6 @@ public class FacesFlowBuilderServicesBeanDefinitionParser extends AbstractSingle
|
||||
}
|
||||
}
|
||||
|
||||
private void parseViewFactoryCreator(Element element, BeanDefinitionBuilder definitionBuilder) {
|
||||
String viewFactoryCreator = element.getAttribute("view-factory-creator");
|
||||
if (StringUtils.hasText(viewFactoryCreator)) {
|
||||
definitionBuilder.addPropertyReference("viewFactoryCreator", viewFactoryCreator);
|
||||
} else {
|
||||
definitionBuilder.addPropertyValue("viewFactoryCreator", new JsfViewFactoryCreator());
|
||||
}
|
||||
}
|
||||
|
||||
private void parseExpressionParser(Element element, BeanDefinitionBuilder definitionBuilder,
|
||||
boolean enableManagedBeans) {
|
||||
if (enableManagedBeans) {
|
||||
@@ -122,4 +105,29 @@ public class FacesFlowBuilderServicesBeanDefinitionParser extends AbstractSingle
|
||||
return definitionBuilder.getBeanDefinition().getPropertyValues().getPropertyValue("conversionService")
|
||||
.getValue();
|
||||
}
|
||||
|
||||
private boolean parseEnableManagedBeans(Element element, BeanDefinitionBuilder definitionBuilder) {
|
||||
String enableManagedBeans = element.getAttribute("enable-managed-beans");
|
||||
if (StringUtils.hasText(enableManagedBeans)) {
|
||||
return Boolean.valueOf(enableManagedBeans).booleanValue();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void parseViewFactoryCreator(Element element, BeanDefinitionBuilder definitionBuilder) {
|
||||
String viewFactoryCreator = element.getAttribute("view-factory-creator");
|
||||
if (StringUtils.hasText(viewFactoryCreator)) {
|
||||
definitionBuilder.addPropertyReference("viewFactoryCreator", viewFactoryCreator);
|
||||
} else {
|
||||
definitionBuilder.addPropertyValue("viewFactoryCreator", new JsfViewFactoryCreator());
|
||||
}
|
||||
}
|
||||
|
||||
private void parseDevelopment(Element element, BeanDefinitionBuilder definitionBuilder) {
|
||||
String development = element.getAttribute("development");
|
||||
if (StringUtils.hasText(development)) {
|
||||
definitionBuilder.addPropertyValue("development", development);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -55,6 +55,16 @@ The custom ViewFactoryCreator implementation to use produce ViewFactories capabl
|
||||
<![CDATA[
|
||||
When this attribute is set to true, a special EL expression parser will be enabled that allows access to JSF-managed beans
|
||||
from EL expressions in flow definitions.
|
||||
]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="development" type="xsd:boolean">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
<![CDATA[
|
||||
Puts all flows in development mode.
|
||||
When set to true, changes to a flow definition will be auto-detected and will result in a flow refresh.
|
||||
]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
|
||||
@@ -43,6 +43,7 @@ public class FacesFlowBuilderServicesBeanDefinitionParserTests extends TestCase
|
||||
assertTrue(builderServices.getExpressionParser() instanceof WebFlowELExpressionParser);
|
||||
assertTrue(builderServices.getViewFactoryCreator() instanceof JsfViewFactoryCreator);
|
||||
assertTrue(builderServices.getConversionService() instanceof FacesConversionService);
|
||||
assertFalse(builderServices.getDevelopment());
|
||||
}
|
||||
|
||||
public void testEnableManagedBeans() {
|
||||
@@ -51,6 +52,7 @@ public class FacesFlowBuilderServicesBeanDefinitionParserTests extends TestCase
|
||||
assertTrue(builderServices.getExpressionParser() instanceof JsfManagedBeanAwareELExpressionParser);
|
||||
assertTrue(builderServices.getViewFactoryCreator() instanceof JsfViewFactoryCreator);
|
||||
assertTrue(builderServices.getConversionService() instanceof FacesConversionService);
|
||||
assertFalse(builderServices.getDevelopment());
|
||||
}
|
||||
|
||||
public void testFlowBuilderServicesAllCustomized() {
|
||||
@@ -59,6 +61,7 @@ public class FacesFlowBuilderServicesBeanDefinitionParserTests extends TestCase
|
||||
assertTrue(builderServices.getExpressionParser() instanceof WebFlowELExpressionParser);
|
||||
assertTrue(builderServices.getViewFactoryCreator() instanceof TestViewFactoryCreator);
|
||||
assertTrue(builderServices.getConversionService() instanceof TestConversionService);
|
||||
assertTrue(builderServices.getDevelopment());
|
||||
}
|
||||
|
||||
public void testFlowBuilderServicesConversionServiceCustomized() {
|
||||
@@ -68,6 +71,7 @@ public class FacesFlowBuilderServicesBeanDefinitionParserTests extends TestCase
|
||||
assertTrue(builderServices.getExpressionParser() instanceof WebFlowELExpressionParser);
|
||||
assertTrue(((WebFlowELExpressionParser) builderServices.getExpressionParser()).getConversionService() instanceof TestConversionService);
|
||||
assertTrue(builderServices.getViewFactoryCreator() instanceof JsfViewFactoryCreator);
|
||||
assertFalse(builderServices.getDevelopment());
|
||||
}
|
||||
|
||||
public static class TestViewFactoryCreator implements ViewFactoryCreator {
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
<faces:flow-builder-services id="flowBuilderServicesAllCustom"
|
||||
expression-parser="customExpressionParser"
|
||||
view-factory-creator="customViewFactoryCreator"
|
||||
conversion-service="customConversionService"/>
|
||||
conversion-service="customConversionService" development="true" />
|
||||
|
||||
<faces:flow-builder-services id="flowBuilderServicesConversionServiceCustom"
|
||||
conversion-service="customConversionService"/>
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
</webflow:flow-registry>
|
||||
|
||||
<!-- Configures the Spring Web Flow JSF integration -->
|
||||
<faces:flow-builder-services id="facesFlowBuilderServices" />
|
||||
<faces:flow-builder-services id="facesFlowBuilderServices" development="true" />
|
||||
|
||||
<!-- Installs a listener that manages JPA persistence contexts for flows that require them -->
|
||||
<bean id="jpaFlowExecutionListener" class="org.springframework.webflow.persistence.JpaFlowExecutionListener">
|
||||
|
||||
@@ -5,7 +5,7 @@ import java.util.List;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
@@ -21,29 +21,27 @@ public class HotelsController {
|
||||
}
|
||||
|
||||
@RequestMapping(method = RequestMethod.GET)
|
||||
public List<Booking> index(SearchCriteria searchCriteria, Principal currentUser) {
|
||||
public void index(SearchCriteria searchCriteria, Principal currentUser, Model model) {
|
||||
if (currentUser != null) {
|
||||
return bookingService.findBookings(currentUser.getName());
|
||||
} else {
|
||||
return null;
|
||||
List<Booking> booking = bookingService.findBookings(currentUser.getName());
|
||||
model.addAttribute(booking);
|
||||
}
|
||||
}
|
||||
|
||||
@RequestMapping(method = RequestMethod.GET)
|
||||
public @ModelAttribute("hotels")
|
||||
List<Hotel> search(SearchCriteria criteria) {
|
||||
return bookingService.findHotels(criteria);
|
||||
public String search(SearchCriteria criteria, Model model) {
|
||||
List<Hotel> hotels = bookingService.findHotels(criteria);
|
||||
model.addAttribute(hotels);
|
||||
return "hotels/search";
|
||||
}
|
||||
|
||||
@RequestMapping(method = RequestMethod.GET)
|
||||
public Hotel show(@RequestParam("id")
|
||||
Long id) {
|
||||
public Hotel show(@RequestParam("id") Long id) {
|
||||
return bookingService.findHotelById(id);
|
||||
}
|
||||
|
||||
@RequestMapping(method = RequestMethod.GET)
|
||||
public String deleteBooking(@RequestParam("id")
|
||||
Long id) {
|
||||
public String deleteBooking(@RequestParam("id") Long id) {
|
||||
bookingService.cancelBooking(id);
|
||||
return "redirect:index";
|
||||
}
|
||||
|
||||
@@ -18,11 +18,11 @@
|
||||
|
||||
<!-- The registry of executable flow definitions -->
|
||||
<webflow:flow-registry id="flowRegistry" flow-builder-services="flowBuilderServices">
|
||||
<webflow:flow-location path="/WEB-INF/hotels/booking/booking.xml" />
|
||||
<webflow:flow-location id="hotels/booking" path="/WEB-INF/hotels/booking/booking.xml" />
|
||||
</webflow:flow-registry>
|
||||
|
||||
|
||||
<!-- Plugs in a custom creator for Web Flow views -->
|
||||
<webflow:flow-builder-services id="flowBuilderServices" view-factory-creator="mvcViewFactoryCreator" conversion-service="conversionService"/>
|
||||
<webflow:flow-builder-services id="flowBuilderServices" view-factory-creator="mvcViewFactoryCreator" conversion-service="conversionService" development="true" />
|
||||
|
||||
<!-- Configures Web Flow to use Tiles to create views for rendering; Tiles allows for applying consistent layouts to your views -->
|
||||
<bean id="mvcViewFactoryCreator" class="org.springframework.webflow.mvc.builder.MvcViewFactoryCreator">
|
||||
|
||||
@@ -4,58 +4,45 @@
|
||||
xsi:schemaLocation="
|
||||
http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
|
||||
|
||||
<!-- URL to flow mapping rules -->
|
||||
<bean id="flowMappings" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
|
||||
<property name="mappings">
|
||||
<value>
|
||||
/hotels/booking=bookingFlowHandler
|
||||
</value>
|
||||
</property>
|
||||
<property name="order" value="0"/>
|
||||
|
||||
<!-- Maps request paths to flows in the flowRegistry; e.g. a path of /hotels/booking looks for a flow with id "hotels/booking" -->
|
||||
<bean class="org.springframework.webflow.mvc.servlet.FlowHandlerMapping">
|
||||
<property name="order" value="0" />
|
||||
</bean>
|
||||
|
||||
<!-- Maps request paths to @Controller classes; e.g. a path of /hotels looks for a controller named HotelsController -->
|
||||
<bean class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping">
|
||||
<property name="order" value="1" />
|
||||
<property name="defaultHandler">
|
||||
<!-- If no @Controller match, map path to a view to render; e.g. the "/intro" path would map to the view named "intro" -->
|
||||
<bean class="org.springframework.web.servlet.mvc.UrlFilenameViewController" />
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<!-- Controls access to the hotel booking flow -->
|
||||
<bean id="bookingFlowHandler" class="org.springframework.webflow.samples.booking.BookingFlowHandler" />
|
||||
|
||||
<!-- Enables convention-based request URL mapping to @Controllers e.g. /hotels/* maps to HotelsController -->
|
||||
<bean class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping">
|
||||
<property name="order" value="1"/>
|
||||
</bean>
|
||||
|
||||
<!-- Maps all other request URLs to views -->
|
||||
<bean id="viewMappings" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
|
||||
<property name="defaultHandler">
|
||||
<!-- Selects view names to render based on the request URI: e.g. the "/intro" URL would map to the view named "intro" -->
|
||||
<bean class="org.springframework.web.servlet.mvc.UrlFilenameViewController" />
|
||||
</property>
|
||||
<property name="order" value="2"/>
|
||||
</bean>
|
||||
|
||||
<!-- Configures the Tiles layout system -->
|
||||
<bean id="tilesConfigurer" class="org.springframework.web.servlet.view.tiles2.TilesConfigurer">
|
||||
<property name="definitions">
|
||||
<list>
|
||||
<value>/WEB-INF/layouts/layouts.xml</value>
|
||||
<value>/WEB-INF/views.xml</value>
|
||||
<value>/WEB-INF/hotels/views.xml</value>
|
||||
<value>/WEB-INF/hotels/booking/views.xml</value>
|
||||
</list>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<!-- Resolves views by delegating to the Tiles layout system; a view name to resolve is treated as the name of a tiles definition -->
|
||||
|
||||
<!-- Resolves logical view names returned by Controllers to Tiles; a view name to resolve is treated as the name of a tiles definition -->
|
||||
<bean id="tilesViewResolver" class="org.springframework.js.ajax.AjaxUrlBasedViewResolver">
|
||||
<property name="viewClass" value="org.springframework.webflow.mvc.view.FlowAjaxTilesView"/>
|
||||
</bean>
|
||||
|
||||
<!-- Enables annotated POJO @Controllers -->
|
||||
|
||||
<!-- Configures the Tiles layout system -->
|
||||
<bean id="tilesConfigurer" class="org.springframework.web.servlet.view.tiles2.TilesConfigurer">
|
||||
<property name="definitions">
|
||||
<list>
|
||||
<value>/WEB-INF/layouts/layouts.xml</value>
|
||||
<value>/WEB-INF/views.xml</value>
|
||||
<value>/WEB-INF/hotels/views.xml</value>
|
||||
<value>/WEB-INF/hotels/booking/views.xml</value>
|
||||
</list>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<!-- Dispatches requests mapped to POJO @Controller implementations -->
|
||||
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" />
|
||||
|
||||
<!-- Enables plain Controllers -->
|
||||
<!-- Dispatches requests mapped to org.springframework.web.servlet.mvc.Controller implementations -->
|
||||
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter" />
|
||||
|
||||
<!-- Enables FlowHandlers -->
|
||||
<!-- Dispatches requests mapped to flows -->
|
||||
<bean class="org.springframework.webflow.mvc.servlet.FlowHandlerAdapter">
|
||||
<property name="flowExecutor" ref="flowExecutor"/>
|
||||
</bean>
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
<transition on="cancel" to="cancel" />
|
||||
</view-state>
|
||||
|
||||
<end-state id="bookingConfirmed" commit="true" />
|
||||
<end-state id="bookingConfirmed" commit="true" view="externalRedirect:servletRelative:/hotels/index"/>
|
||||
|
||||
<end-state id="cancel" />
|
||||
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
booking.checkinDate.typeMismatch=The Check In Date must be in the format dd/mm/yy
|
||||
booking.checkinDate.beforeToday=The Check In Date must be a future date
|
||||
booking.checkinDate.required=The check in date is required
|
||||
booking.checkinDate.typeMismatch=The check in date must be in the format dd/mm/yy
|
||||
booking.checkinDate.beforeToday=The check in date must be a future date
|
||||
|
||||
booking.checkoutDate.typeMismatch=The Check Out Date must be in the format dd/mm/yy
|
||||
booking.checkoutDate.beforeCheckinDate=The Check Out Date must be later than the Check In Date
|
||||
booking.checkoutDate.required=The check out date is required
|
||||
booking.checkoutDate.typeMismatch=The check out date must be in the format dd/mm/yy
|
||||
booking.checkoutDate.beforeCheckinDate=The check out date must be later than the check in date
|
||||
|
||||
booking.creditCard.required=The credit card must be a valid 16 digit number
|
||||
booking.creditCardName.required=The name on the credit card is required
|
||||
|
||||
required=The {0} field is required
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
</script>
|
||||
</p>
|
||||
<div id="hotelResults" class="section">
|
||||
<c:if test="${not empty hotels}">
|
||||
<c:if test="${not empty hotelList}">
|
||||
<table class="summary">
|
||||
<thead>
|
||||
<tr>
|
||||
@@ -29,7 +29,7 @@
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<c:forEach var="hotel" items="${hotels}">
|
||||
<c:forEach var="hotel" items="${hotelList}">
|
||||
<tr>
|
||||
<td>${hotel.name}</td>
|
||||
<td>${hotel.address}</td>
|
||||
@@ -38,7 +38,7 @@
|
||||
<td><a href="show?id=${hotel.id}">View Hotel</a></td>
|
||||
</tr>
|
||||
</c:forEach>
|
||||
<c:if test="${empty hotels}">
|
||||
<c:if test="${empty hotelList}">
|
||||
<tr>
|
||||
<td colspan="5">No hotels found</td>
|
||||
</tr>
|
||||
@@ -56,7 +56,7 @@
|
||||
}));
|
||||
</script>
|
||||
</c:if>
|
||||
<c:if test="${not empty hotels && fn:length(hotels) == searchCriteria.pageSize}">
|
||||
<c:if test="${not empty hotelList && fn:length(hotelList) == searchCriteria.pageSize}">
|
||||
<a id="moreResultsLink" href="search?searchString=${searchCriteria.searchString}&pageSize=${searchCriteria.pageSize}&page=${searchCriteria.page + 1}">More Results</a>
|
||||
<script type="text/javascript">
|
||||
Spring.addDecoration(new Spring.AjaxEventDecoration({
|
||||
|
||||
@@ -19,7 +19,6 @@ import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.binding.convert.ConversionService;
|
||||
import org.springframework.binding.convert.service.DefaultConversionService;
|
||||
import org.springframework.util.StringUtils;
|
||||
@@ -39,13 +38,14 @@ class FlowBuilderServicesBeanDefinitionParser extends AbstractSingleBeanDefiniti
|
||||
return FlowBuilderServices.class;
|
||||
}
|
||||
|
||||
protected void doParse(Element element, ParserContext context, BeanDefinitionBuilder builder) {
|
||||
parseConversionService(element, builder, context);
|
||||
parseExpressionParser(element, builder, context);
|
||||
parseViewFactoryCreator(element, builder, context);
|
||||
protected void doParse(Element element, BeanDefinitionBuilder builder) {
|
||||
parseConversionService(element, builder);
|
||||
parseExpressionParser(element, builder);
|
||||
parseViewFactoryCreator(element, builder);
|
||||
parseDevelopment(element, builder);
|
||||
}
|
||||
|
||||
private void parseConversionService(Element element, BeanDefinitionBuilder definitionBuilder, ParserContext context) {
|
||||
private void parseConversionService(Element element, BeanDefinitionBuilder definitionBuilder) {
|
||||
String conversionService = element.getAttribute("conversion-service");
|
||||
if (StringUtils.hasText(conversionService)) {
|
||||
definitionBuilder.addPropertyReference("conversionService", conversionService);
|
||||
@@ -54,7 +54,7 @@ class FlowBuilderServicesBeanDefinitionParser extends AbstractSingleBeanDefiniti
|
||||
}
|
||||
}
|
||||
|
||||
private void parseExpressionParser(Element element, BeanDefinitionBuilder definitionBuilder, ParserContext context) {
|
||||
private void parseExpressionParser(Element element, BeanDefinitionBuilder definitionBuilder) {
|
||||
String expressionParser = element.getAttribute("expression-parser");
|
||||
if (StringUtils.hasText(expressionParser)) {
|
||||
definitionBuilder.addPropertyReference("expressionParser", expressionParser);
|
||||
@@ -74,7 +74,12 @@ class FlowBuilderServicesBeanDefinitionParser extends AbstractSingleBeanDefiniti
|
||||
}
|
||||
}
|
||||
|
||||
private void parseViewFactoryCreator(Element element, BeanDefinitionBuilder definitionBuilder, ParserContext context) {
|
||||
private Object getConversionServiceValue(BeanDefinitionBuilder definitionBuilder) {
|
||||
return definitionBuilder.getBeanDefinition().getPropertyValues().getPropertyValue("conversionService")
|
||||
.getValue();
|
||||
}
|
||||
|
||||
private void parseViewFactoryCreator(Element element, BeanDefinitionBuilder definitionBuilder) {
|
||||
String viewFactoryCreator = element.getAttribute("view-factory-creator");
|
||||
if (StringUtils.hasText(viewFactoryCreator)) {
|
||||
definitionBuilder.addPropertyReference("viewFactoryCreator", viewFactoryCreator);
|
||||
@@ -84,8 +89,10 @@ class FlowBuilderServicesBeanDefinitionParser extends AbstractSingleBeanDefiniti
|
||||
}
|
||||
}
|
||||
|
||||
private Object getConversionServiceValue(BeanDefinitionBuilder definitionBuilder) {
|
||||
return definitionBuilder.getBeanDefinition().getPropertyValues().getPropertyValue("conversionService")
|
||||
.getValue();
|
||||
private void parseDevelopment(Element element, BeanDefinitionBuilder definitionBuilder) {
|
||||
String development = element.getAttribute("development");
|
||||
if (StringUtils.hasText(development)) {
|
||||
definitionBuilder.addPropertyValue("development", development);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -44,6 +44,7 @@ import org.springframework.webflow.engine.model.builder.DefaultFlowModelHolder;
|
||||
import org.springframework.webflow.engine.model.builder.FlowModelBuilder;
|
||||
import org.springframework.webflow.engine.model.builder.xml.XmlFlowModelBuilder;
|
||||
import org.springframework.webflow.engine.model.registry.FlowModelHolder;
|
||||
import org.springframework.webflow.engine.model.registry.FlowModelRegistry;
|
||||
import org.springframework.webflow.engine.model.registry.FlowModelRegistryImpl;
|
||||
|
||||
/**
|
||||
@@ -71,12 +72,7 @@ class FlowRegistryFactoryBean implements FactoryBean, BeanClassLoaderAware, Init
|
||||
/**
|
||||
* The definition registry produced by this factory bean.
|
||||
*/
|
||||
private FlowDefinitionRegistryImpl flowRegistry;
|
||||
|
||||
/**
|
||||
* The model registry used to build flow models that can be assembled into registerable Flows.
|
||||
*/
|
||||
private FlowModelRegistryImpl flowModelRegistry;
|
||||
private DefaultFlowRegistry flowRegistry;
|
||||
|
||||
/**
|
||||
* A helper for creating abstract representation of externalized flow definition resources.
|
||||
@@ -128,9 +124,8 @@ class FlowRegistryFactoryBean implements FactoryBean, BeanClassLoaderAware, Init
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
flowResourceFactory = new FlowDefinitionResourceFactory(flowBuilderServices.getApplicationContext());
|
||||
flowRegistry = new FlowDefinitionRegistryImpl();
|
||||
flowRegistry = new DefaultFlowRegistry();
|
||||
flowRegistry.setParent(parent);
|
||||
flowModelRegistry = new FlowModelRegistryImpl();
|
||||
registerFlowLocations();
|
||||
registerFlowLocationPatterns();
|
||||
registerFlowBuilders();
|
||||
@@ -201,8 +196,14 @@ class FlowRegistryFactoryBean implements FactoryBean, BeanClassLoaderAware, Init
|
||||
|
||||
private AttributeMap getFlowAttributes(Set attributes) {
|
||||
MutableAttributeMap flowAttributes = null;
|
||||
if (flowBuilderServices.getDevelopment()) {
|
||||
flowAttributes = new LocalAttributeMap(1 + attributes.size(), 1);
|
||||
flowAttributes.put("development", Boolean.TRUE);
|
||||
}
|
||||
if (!attributes.isEmpty()) {
|
||||
flowAttributes = new LocalAttributeMap();
|
||||
if (flowAttributes == null) {
|
||||
flowAttributes = new LocalAttributeMap(attributes.size(), 1);
|
||||
}
|
||||
for (Iterator it = attributes.iterator(); it.hasNext();) {
|
||||
FlowElementAttribute attribute = (FlowElementAttribute) it.next();
|
||||
flowAttributes.put(attribute.getName(), getConvertedValue(attribute));
|
||||
@@ -217,13 +218,13 @@ class FlowRegistryFactoryBean implements FactoryBean, BeanClassLoaderAware, Init
|
||||
|
||||
private FlowModelHolder createFlowModelHolder(FlowDefinitionResource resource) {
|
||||
FlowModelHolder modelHolder = new DefaultFlowModelHolder(createFlowModelBuilder(resource));
|
||||
flowModelRegistry.registerFlowModel(resource.getId(), modelHolder);
|
||||
flowRegistry.getFlowModelRegistry().registerFlowModel(resource.getId(), modelHolder);
|
||||
return modelHolder;
|
||||
}
|
||||
|
||||
private FlowModelBuilder createFlowModelBuilder(FlowDefinitionResource resource) {
|
||||
if (isXml(resource.getPath())) {
|
||||
return new XmlFlowModelBuilder(resource.getPath(), flowModelRegistry);
|
||||
return new XmlFlowModelBuilder(resource.getPath(), flowRegistry.getFlowModelRegistry());
|
||||
} else {
|
||||
throw new IllegalArgumentException(resource
|
||||
+ " is not a supported resource type; supported types are [.xml]");
|
||||
@@ -280,4 +281,20 @@ class FlowRegistryFactoryBean implements FactoryBean, BeanClassLoaderAware, Init
|
||||
}
|
||||
}
|
||||
|
||||
public static class DefaultFlowRegistry extends FlowDefinitionRegistryImpl {
|
||||
private FlowModelRegistry flowModelRegistry = new FlowModelRegistryImpl();
|
||||
|
||||
public FlowModelRegistry getFlowModelRegistry() {
|
||||
return flowModelRegistry;
|
||||
}
|
||||
|
||||
public void setParent(FlowDefinitionRegistry parent) {
|
||||
super.setParent(parent);
|
||||
if (parent instanceof DefaultFlowRegistry) {
|
||||
DefaultFlowRegistry parentFlowRegistry = (DefaultFlowRegistry) parent;
|
||||
flowModelRegistry.setParent(parentFlowRegistry.getFlowModelRegistry());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -11,7 +11,7 @@
|
||||
<xsd:documentation>
|
||||
<![CDATA[
|
||||
Spring Web Flow Configuration Schema
|
||||
Authors: Keith Donald, Ben Hale, Jeremy Grelle
|
||||
Authors: Keith Donald, Jeremy Grelle
|
||||
<br>
|
||||
A XML-based DSL for configuring the Spring Web Flow 2.0 system.
|
||||
]]>
|
||||
@@ -206,6 +206,16 @@ The custom ExpressionParser implementation to use to compile expression strings
|
||||
<xsd:documentation>
|
||||
<![CDATA[
|
||||
The custom ViewFactoryCreator implementation to use produce ViewFactories capable of rendering Views.
|
||||
]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="development" type="xsd:boolean">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
<![CDATA[
|
||||
Puts all flows in development mode.
|
||||
When set to true, changes to a flow definition will be auto-detected and will result in a flow refresh.
|
||||
]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
|
||||
@@ -23,7 +23,6 @@ import java.util.Map;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.springframework.web.util.UrlPathHelper;
|
||||
import org.springframework.web.util.WebUtils;
|
||||
import org.springframework.webflow.core.collection.AttributeMap;
|
||||
|
||||
/**
|
||||
@@ -32,7 +31,7 @@ import org.springframework.webflow.core.collection.AttributeMap;
|
||||
* Expects URLs to launch flow to be of this pattern:
|
||||
*
|
||||
* <pre>
|
||||
* http://<host>/[app context path]/[app servlet path]/[namespace]/<flow id>
|
||||
* http://<host>/[app context path]/[app servlet path]/<flow id>
|
||||
* </pre>
|
||||
*
|
||||
* For example:
|
||||
@@ -44,7 +43,7 @@ import org.springframework.webflow.core.collection.AttributeMap;
|
||||
* Expects URLs to resume flows to be of this pattern:
|
||||
*
|
||||
* <pre>
|
||||
* http://<host>/[app context path]/[app servlet path]/[namespace]/<flow id>?execution=<flow execution key>
|
||||
* http://<host>/[app context path]/[app servlet path]/<flow id>?execution=<flow execution key>
|
||||
* </pre>
|
||||
*
|
||||
* For example:
|
||||
@@ -73,7 +72,7 @@ public class DefaultFlowUrlHandler implements FlowUrlHandler {
|
||||
}
|
||||
|
||||
public String getFlowId(HttpServletRequest request) {
|
||||
return WebUtils.extractFilenameFromUrlPath(urlPathHelper.getLookupPathForRequest(request));
|
||||
return request.getPathInfo().substring(0);
|
||||
}
|
||||
|
||||
public String createFlowExecutionUrl(String flowId, String flowExecutionKey, HttpServletRequest request) {
|
||||
@@ -86,9 +85,12 @@ public class DefaultFlowUrlHandler implements FlowUrlHandler {
|
||||
|
||||
public String createFlowDefinitionUrl(String flowId, AttributeMap input, HttpServletRequest request) {
|
||||
StringBuffer url = new StringBuffer();
|
||||
url.append(getFlowHandlerUri(request));
|
||||
url.append('/');
|
||||
url.append(encode(flowId));
|
||||
url.append(request.getContextPath());
|
||||
url.append(request.getServletPath());
|
||||
if (!flowId.startsWith("/")) {
|
||||
url.append('/');
|
||||
}
|
||||
url.append(flowId);
|
||||
if (input != null && !input.isEmpty()) {
|
||||
url.append('?');
|
||||
appendQueryParameters(url, input.asMap());
|
||||
@@ -125,10 +127,4 @@ public class DefaultFlowUrlHandler implements FlowUrlHandler {
|
||||
}
|
||||
}
|
||||
|
||||
private String getFlowHandlerUri(HttpServletRequest request) {
|
||||
String flowRequestUri = request.getRequestURI();
|
||||
int lastSlash = flowRequestUri.lastIndexOf('/');
|
||||
return flowRequestUri.substring(0, lastSlash);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -81,4 +81,10 @@ public interface FlowDefinition extends Annotated {
|
||||
*/
|
||||
public ApplicationContext getApplicationContext();
|
||||
|
||||
/**
|
||||
* Returns true if this flow definition is currently in development (running in development mode).
|
||||
* @return the development flag
|
||||
*/
|
||||
public boolean inDevelopment();
|
||||
|
||||
}
|
||||
@@ -67,4 +67,6 @@ public interface FlowDefinitionRegistry extends FlowDefinitionLocator {
|
||||
*/
|
||||
public void registerFlowDefinition(FlowDefinition definition);
|
||||
|
||||
public boolean containsFlowDefinition(String flowId);
|
||||
|
||||
}
|
||||
@@ -69,6 +69,10 @@ public class FlowDefinitionRegistryImpl implements FlowDefinitionRegistry {
|
||||
|
||||
// implementing FlowDefinitionRegistry
|
||||
|
||||
public boolean containsFlowDefinition(String flowId) {
|
||||
return flowDefinitions.containsKey(flowId);
|
||||
}
|
||||
|
||||
public int getFlowDefinitionCount() {
|
||||
return flowDefinitions.size();
|
||||
}
|
||||
|
||||
@@ -91,10 +91,10 @@ import org.springframework.webflow.execution.RequestContext;
|
||||
* {@link #start(RequestControlContext, MutableAttributeMap) start}, {@link #resume(RequestControlContext)},
|
||||
* {@link #handleEvent(RequestControlContext) on event},
|
||||
* {@link #end(RequestControlContext, String, MutableAttributeMap) end}, and
|
||||
* {@link #handleException(FlowExecutionException, RequestControlContext)}. Each method accepts a
|
||||
* {@link RequestContext request context} that allows for this flow to access execution state in a thread safe manner. A
|
||||
* flow execution is what models a running instance of this flow definition, somewhat analogous to a java object that is
|
||||
* an instance of a class.
|
||||
* {@link #handleException(FlowExecutionException, RequestControlContext)}. Each method accepts a {@link RequestContext
|
||||
* request context} that allows for this flow to access execution state in a thread safe manner. A flow execution is
|
||||
* what models a running instance of this flow definition, somewhat analogous to a java object that is an instance of a
|
||||
* class.
|
||||
*
|
||||
* @see org.springframework.webflow.engine.State
|
||||
* @see org.springframework.webflow.engine.ActionState
|
||||
@@ -239,6 +239,10 @@ public class Flow extends AnnotatedObject implements FlowDefinition {
|
||||
return applicationContext;
|
||||
}
|
||||
|
||||
public boolean inDevelopment() {
|
||||
return getAttributes().getBoolean("development", Boolean.FALSE).booleanValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add given state definition to this flow definition. Marked protected, as this method is to be called by the
|
||||
* (privileged) state definition classes themselves during state construction as part of a FlowBuilder invocation.
|
||||
@@ -288,8 +292,8 @@ public class Flow extends AnnotatedObject implements FlowDefinition {
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the start state for this flow to the state with the provided <code>stateId</code>; a state must exist by
|
||||
* the provided <code>stateId</code>.
|
||||
* Set the start state for this flow to the state with the provided <code>stateId</code>; a state must exist by the
|
||||
* provided <code>stateId</code>.
|
||||
* @param stateId the id of the new start state
|
||||
* @throws IllegalArgumentException when no state exists with the id you provided
|
||||
*/
|
||||
@@ -423,8 +427,8 @@ public class Flow extends AnnotatedObject implements FlowDefinition {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of actions executed by this flow when an execution of the flow <i>ends</i>. The returned list
|
||||
* is mutable.
|
||||
* Returns the list of actions executed by this flow when an execution of the flow <i>ends</i>. The returned list is
|
||||
* mutable.
|
||||
* @return the end action list
|
||||
*/
|
||||
public ActionList getEndActionList() {
|
||||
@@ -518,11 +522,10 @@ public class Flow extends AnnotatedObject implements FlowDefinition {
|
||||
/**
|
||||
* Start a new session for this flow in its start state. This boils down to the following:
|
||||
* <ol>
|
||||
* <li>Create (setup) all registered flow variables ({@link #addVariable(FlowVariable)}) in flow scope.</li>
|
||||
* <li>Map provided input data into the flow. Typically data will be mapped into flow scope using the registered
|
||||
* input mapper ({@link #setInputMapper(Mapper)}).</li>
|
||||
* <li>Execute all registered start actions ({@link #getStartActionList()}).</li>
|
||||
* <li>Enter the configured start state ({@link #setStartState(State)})</li>
|
||||
* <li>Create (setup) all registered flow variables ({@link #addVariable(FlowVariable)}) in flow scope.</li> <li>Map
|
||||
* provided input data into the flow. Typically data will be mapped into flow scope using the registered input
|
||||
* mapper ({@link #setInputMapper(Mapper)}).</li> <li>Execute all registered start actions (
|
||||
* {@link #getStartActionList()}).</li> <li>Enter the configured start state ({@link #setStartState(State)})</li>
|
||||
* </ol>
|
||||
* @param context the flow execution control context
|
||||
* @param input eligible input into the session
|
||||
@@ -576,9 +579,9 @@ public class Flow extends AnnotatedObject implements FlowDefinition {
|
||||
* Inform this flow definition that an execution session of itself has ended. As a result, the flow will do the
|
||||
* following:
|
||||
* <ol>
|
||||
* <li>Execute all registered end actions ({@link #getEndActionList()}).</li>
|
||||
* <li>Map data available in the flow execution control context into provided output map using a registered output
|
||||
* mapper ({@link #setOutputMapper(Mapper)}).</li>
|
||||
* <li>Execute all registered end actions ({@link #getEndActionList()}).</li> <li>Map data available in the flow
|
||||
* execution control context into provided output map using a registered output mapper (
|
||||
* {@link #setOutputMapper(Mapper)}).</li>
|
||||
* </ol>
|
||||
* @param context the flow execution control context
|
||||
* @param outcome the logical flow outcome that will be returned by the session, generally the id of the terminating
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
package org.springframework.webflow.engine.builder;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.core.style.ToStringCreator;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Contains the information needed to bind model to a view. This information consists of one or more
|
||||
* {@link Binding bindings} that connect properties of the model to UI elements of the view.
|
||||
* Contains the information needed to bind model to a view. This information consists of one or more {@link Binding
|
||||
* bindings} that connect properties of the model to UI elements of the view.
|
||||
*
|
||||
* @see ViewFactoryCreator
|
||||
*
|
||||
@@ -17,7 +17,7 @@ import org.springframework.util.Assert;
|
||||
*/
|
||||
public class BinderConfiguration {
|
||||
|
||||
private Set bindings = new HashSet();
|
||||
private Set bindings = new LinkedHashSet();
|
||||
|
||||
/**
|
||||
* Adds a new binding to this binding configuration.
|
||||
|
||||
@@ -76,8 +76,8 @@ public class DefaultFlowHolder implements FlowDefinitionHolder {
|
||||
logger.debug("Assembling the flow for the first time");
|
||||
assembleFlow();
|
||||
} else {
|
||||
if (getFlowBuilder().hasFlowChanged()) {
|
||||
logger.debug("The flow has changed; reassembling...");
|
||||
if (flowDefinition.inDevelopment() && getFlowBuilder().hasFlowChanged()) {
|
||||
logger.debug("The flow under development has changed; reassembling...");
|
||||
assembleFlow();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -142,13 +142,22 @@ public class FlowModelFlowBuilder extends AbstractFlowBuilder {
|
||||
protected void doInit() throws FlowBuilderException {
|
||||
try {
|
||||
flowModel = flowModelHolder.getFlowModel();
|
||||
initLocalFlowContext();
|
||||
} catch (FlowModelBuilderException e) {
|
||||
throw new FlowBuilderException("Unable to get the model for this flow", e);
|
||||
}
|
||||
if ("true".equals(flowModel.getAbstract())) {
|
||||
throw new FlowBuilderException("Abstract flow models cannot be instantiated.");
|
||||
}
|
||||
initLocalFlowContext();
|
||||
}
|
||||
|
||||
protected Flow createFlow() {
|
||||
String flowId = getContext().getFlowId();
|
||||
AttributeMap flowAttributes = parseFlowMetaAttributes(flowModel);
|
||||
flowAttributes = getContext().getFlowAttributes().union(flowAttributes);
|
||||
Flow flow = getLocalContext().getFlowArtifactFactory().createFlow(flowId, flowAttributes);
|
||||
flow.setApplicationContext(getLocalContext().getApplicationContext());
|
||||
return flow;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -257,12 +266,6 @@ public class FlowModelFlowBuilder extends AbstractFlowBuilder {
|
||||
|
||||
// subclassing hooks
|
||||
|
||||
protected Flow createFlow() {
|
||||
Flow flow = parseFlow(flowModel);
|
||||
flow.setApplicationContext(getLocalContext().getApplicationContext());
|
||||
return flow;
|
||||
}
|
||||
|
||||
protected FlowModel getFlowModel() {
|
||||
return flowModel;
|
||||
}
|
||||
@@ -346,6 +349,10 @@ public class FlowModelFlowBuilder extends AbstractFlowBuilder {
|
||||
return flowContext;
|
||||
}
|
||||
|
||||
private boolean isFlowInDevelopment() {
|
||||
return getContext().getFlowAttributes().getBoolean("development", Boolean.FALSE).booleanValue();
|
||||
}
|
||||
|
||||
private void registerMessageSource(GenericApplicationContext flowContext, Resource flowResource) {
|
||||
boolean localMessageSourcePresent = flowContext
|
||||
.containsLocalBean(AbstractApplicationContext.MESSAGE_SOURCE_BEAN_NAME);
|
||||
@@ -360,20 +367,20 @@ public class FlowModelFlowBuilder extends AbstractFlowBuilder {
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder
|
||||
.rootBeanDefinition(ReloadableResourceBundleMessageSource.class);
|
||||
builder.addPropertyValue("basename", "messages");
|
||||
if (isFlowInDevelopment()) {
|
||||
builder.addPropertyValue("cacheSeconds", "0");
|
||||
}
|
||||
flowContext.registerBeanDefinition(AbstractApplicationContext.MESSAGE_SOURCE_BEAN_NAME, builder
|
||||
.getBeanDefinition());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Flow parseFlow(FlowModel flow) {
|
||||
String flowId = getLocalContext().getFlowId();
|
||||
AttributeMap externallyAssignedAttributes = getLocalContext().getFlowAttributes();
|
||||
private AttributeMap parseFlowMetaAttributes(FlowModel flow) {
|
||||
MutableAttributeMap flowAttributes = parseMetaAttributes(flow.getAttributes());
|
||||
parseAndPutPersistenceContext(flow.getPersistenceContext(), flowAttributes);
|
||||
parseAndPutSecured(flow.getSecured(), flowAttributes);
|
||||
return this.getLocalContext().getFlowArtifactFactory().createFlow(flowId,
|
||||
flowAttributes.union(externallyAssignedAttributes));
|
||||
return flowAttributes;
|
||||
}
|
||||
|
||||
private FlowVariable parseFlowVariable(VarModel var) {
|
||||
|
||||
@@ -41,18 +41,10 @@ public abstract class AbstractFlowBuilder implements FlowBuilder {
|
||||
*/
|
||||
private FlowBuilderContext context;
|
||||
|
||||
/**
|
||||
* Returns this flow builder's context.
|
||||
* @return the flow builder context
|
||||
*/
|
||||
protected FlowBuilderContext getContext() {
|
||||
return context;
|
||||
}
|
||||
|
||||
public void init(FlowBuilderContext context) throws FlowBuilderException {
|
||||
this.context = context;
|
||||
doInit();
|
||||
this.flow = createFlow();
|
||||
flow = createFlow();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -73,6 +65,14 @@ public abstract class AbstractFlowBuilder implements FlowBuilder {
|
||||
return getContext().getFlowArtifactFactory().createFlow(id, attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns this flow builder's context.
|
||||
* @return the flow builder context
|
||||
*/
|
||||
protected FlowBuilderContext getContext() {
|
||||
return context;
|
||||
}
|
||||
|
||||
public void buildVariables() throws FlowBuilderException {
|
||||
}
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ import org.springframework.binding.expression.ExpressionParser;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.webflow.core.collection.AttributeMap;
|
||||
import org.springframework.webflow.core.collection.CollectionUtils;
|
||||
import org.springframework.webflow.definition.registry.FlowDefinitionLocator;
|
||||
import org.springframework.webflow.engine.builder.FlowArtifactFactory;
|
||||
import org.springframework.webflow.engine.builder.FlowBuilderContext;
|
||||
@@ -61,7 +62,7 @@ public class FlowBuilderContextImpl implements FlowBuilderContext {
|
||||
Assert.notNull(flowDefinitionLocator, "The flow definition locator is required");
|
||||
Assert.notNull(flowBuilderServices, "The flow builder services holder is required");
|
||||
this.flowId = flowId;
|
||||
this.flowAttributes = flowAttributes;
|
||||
initFlowAttributes(flowAttributes);
|
||||
this.flowDefinitionLocator = flowDefinitionLocator;
|
||||
this.flowBuilderServices = flowBuilderServices;
|
||||
this.conversionService = createConversionService();
|
||||
@@ -119,6 +120,14 @@ public class FlowBuilderContextImpl implements FlowBuilderContext {
|
||||
return service;
|
||||
}
|
||||
|
||||
private void initFlowAttributes(AttributeMap flowAttributes) {
|
||||
if (flowAttributes != null) {
|
||||
this.flowAttributes = flowAttributes;
|
||||
} else {
|
||||
this.flowAttributes = CollectionUtils.EMPTY_ATTRIBUTE_MAP;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A little proxy that refreshes the externally configured conversion service reference on each invocation.
|
||||
*/
|
||||
|
||||
@@ -43,14 +43,14 @@ import org.springframework.webflow.engine.builder.ViewFactoryCreator;
|
||||
public class FlowBuilderServices implements ApplicationContextAware, InitializingBean {
|
||||
|
||||
/**
|
||||
* The factory encapsulating the creation of central Flow artifacts such as {@link Flow flows} and
|
||||
* {@link State states}.
|
||||
* The factory encapsulating the creation of central Flow artifacts such as {@link Flow flows} and {@link State
|
||||
* states}.
|
||||
*/
|
||||
private FlowArtifactFactory flowArtifactFactory = new FlowArtifactFactory();
|
||||
|
||||
/**
|
||||
* The view factory creator for creating views to render during flow execution. The default is <code>null</code>
|
||||
* and this service must be configured externally.
|
||||
* The view factory creator for creating views to render during flow execution. The default is <code>null</code> and
|
||||
* this service must be configured externally.
|
||||
*/
|
||||
private ViewFactoryCreator viewFactoryCreator;
|
||||
|
||||
@@ -70,6 +70,11 @@ public class FlowBuilderServices implements ApplicationContextAware, Initializin
|
||||
*/
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
/**
|
||||
* Whether or not the flow system is in development mode. In development mode, flows auto-refresh on change.
|
||||
*/
|
||||
private boolean development;
|
||||
|
||||
public FlowArtifactFactory getFlowArtifactFactory() {
|
||||
return flowArtifactFactory;
|
||||
}
|
||||
@@ -102,6 +107,14 @@ public class FlowBuilderServices implements ApplicationContextAware, Initializin
|
||||
this.expressionParser = expressionParser;
|
||||
}
|
||||
|
||||
public boolean getDevelopment() {
|
||||
return development;
|
||||
}
|
||||
|
||||
public void setDevelopment(boolean development) {
|
||||
this.development = development;
|
||||
}
|
||||
|
||||
public ApplicationContext getApplicationContext() {
|
||||
return applicationContext;
|
||||
}
|
||||
|
||||
@@ -190,8 +190,7 @@ public class FlowHandlerAdapter extends PortletContentGenerator implements Handl
|
||||
RenderResponse response) {
|
||||
if (e instanceof NoSuchFlowExecutionException) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Restarting a new execution of previously expired/ended flow '" + flowHandler.getFlowId()
|
||||
+ "'");
|
||||
logger.debug("Restarting a new execution of previously ended flow '" + flowHandler.getFlowId() + "'");
|
||||
}
|
||||
// by default, attempt to restart the flow
|
||||
startFlow(flowHandler, null, request, response);
|
||||
|
||||
@@ -137,8 +137,8 @@ public class FlowHandlerAdapter extends WebContentGenerator implements HandlerAd
|
||||
* Set whether redirects sent by this handler adapter should be compatible with HTTP 1.0 clients.
|
||||
* <p>
|
||||
* By default, this will enforce a redirect HTTP status code of 302 by delegating to
|
||||
* <code>HttpServletResponse.sendRedirect</code>. Setting this to false will send HTTP status code 303, which is
|
||||
* the correct code for HTTP 1.1 clients, but not understood by HTTP 1.0 clients.
|
||||
* <code>HttpServletResponse.sendRedirect</code>. Setting this to false will send HTTP status code 303, which is the
|
||||
* correct code for HTTP 1.1 clients, but not understood by HTTP 1.0 clients.
|
||||
* <p>
|
||||
* Many HTTP 1.1 clients treat 302 just like 303, not making any difference. However, some clients depend on 303
|
||||
* when redirecting after a POST request; turn this flag off in such a scenario.
|
||||
@@ -278,7 +278,7 @@ public class FlowHandlerAdapter extends WebContentGenerator implements HandlerAd
|
||||
if (e instanceof NoSuchFlowExecutionException && flowId != null) {
|
||||
if (!response.isCommitted()) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Restarting a new execution of previously expired/ended flow '" + flowId + "'");
|
||||
logger.debug("Restarting a new execution of previously ended flow '" + flowId + "'");
|
||||
}
|
||||
// by default, attempt to restart the flow
|
||||
response.sendRedirect(flowUrlHandler.createFlowDefinitionUrl(flowId, null, request));
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
package org.springframework.webflow.mvc.servlet;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.springframework.web.servlet.handler.AbstractHandlerMapping;
|
||||
import org.springframework.webflow.definition.registry.FlowDefinitionRegistry;
|
||||
|
||||
public class FlowHandlerMapping extends AbstractHandlerMapping {
|
||||
|
||||
private FlowDefinitionRegistry flowRegistry;
|
||||
|
||||
protected void initServletContext(ServletContext servletContext) {
|
||||
if (flowRegistry == null) {
|
||||
flowRegistry = (FlowDefinitionRegistry) getApplicationContext().getBean("flowRegistry",
|
||||
FlowDefinitionRegistry.class);
|
||||
}
|
||||
}
|
||||
|
||||
protected Object getHandlerInternal(HttpServletRequest request) throws Exception {
|
||||
String flowId = request.getPathInfo().substring(1);
|
||||
if (getApplicationContext().containsBean(flowId)) {
|
||||
Object handler = getApplicationContext().getBean(flowId);
|
||||
if (handler instanceof FlowHandler) {
|
||||
return handler;
|
||||
}
|
||||
}
|
||||
if (flowRegistry.containsFlowDefinition(flowId)) {
|
||||
return new DefaultFlowHandler(flowId);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static class DefaultFlowHandler extends AbstractFlowHandler {
|
||||
private String flowId;
|
||||
|
||||
public DefaultFlowHandler(String flowId) {
|
||||
this.flowId = flowId;
|
||||
}
|
||||
|
||||
public String getFlowId() {
|
||||
return flowId;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -35,6 +35,7 @@ public class FlowBuilderServicesBeanDefinitionParserTests extends TestCase {
|
||||
assertTrue(builderServices.getExpressionParser() instanceof WebFlowELExpressionParser);
|
||||
assertTrue(builderServices.getViewFactoryCreator() instanceof MvcViewFactoryCreator);
|
||||
assertTrue(builderServices.getConversionService() instanceof DefaultConversionService);
|
||||
assertFalse(builderServices.getDevelopment());
|
||||
}
|
||||
|
||||
public void testFlowBuilderServicesAllCustomized() {
|
||||
@@ -43,6 +44,7 @@ public class FlowBuilderServicesBeanDefinitionParserTests extends TestCase {
|
||||
assertTrue(builderServices.getExpressionParser() instanceof WebFlowELExpressionParser);
|
||||
assertTrue(builderServices.getViewFactoryCreator() instanceof TestViewFactoryCreator);
|
||||
assertTrue(builderServices.getConversionService() instanceof TestConversionService);
|
||||
assertTrue(builderServices.getDevelopment());
|
||||
}
|
||||
|
||||
public void testFlowBuilderServicesConversionServiceCustomized() {
|
||||
@@ -52,6 +54,7 @@ public class FlowBuilderServicesBeanDefinitionParserTests extends TestCase {
|
||||
assertTrue(builderServices.getExpressionParser() instanceof WebFlowELExpressionParser);
|
||||
assertTrue(((WebFlowELExpressionParser) builderServices.getExpressionParser()).getConversionService() instanceof TestConversionService);
|
||||
assertTrue(builderServices.getViewFactoryCreator() instanceof MvcViewFactoryCreator);
|
||||
assertFalse(builderServices.getDevelopment());
|
||||
}
|
||||
|
||||
public static class TestViewFactoryCreator implements ViewFactoryCreator {
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
<webflow:flow-builder-services id="flowBuilderServicesAllCustom"
|
||||
expression-parser="customExpressionParser"
|
||||
view-factory-creator="customViewFactoryCreator"
|
||||
conversion-service="customConversionService" />
|
||||
conversion-service="customConversionService" development="true" />
|
||||
|
||||
<webflow:flow-builder-services id="flowBuilderServicesConversionServiceCustom"
|
||||
conversion-service="customConversionService" />
|
||||
|
||||
@@ -140,6 +140,9 @@ public class FlowDefinitionRegistryImplTests extends TestCase {
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean inDevelopment() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static class BarFlow implements FlowDefinition {
|
||||
@@ -180,5 +183,10 @@ public class FlowDefinitionRegistryImplTests extends TestCase {
|
||||
public ApplicationContext getApplicationContext() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean inDevelopment() {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user