TOC PREV NEXT INDEX

Spring Web Flow Integration


The Spring Framework is a full-stack Java/JEE application framework focusing on increased development productivity while improving application testability and quality. For more information on Spring Framework, see http://www.springframework.org.

Getting Started

The easiest way to produce a working ICEfaces/Spring Web Flow application is to check out the demonstration application available from http://anonsvn.icefaces.org/repo/projects/swf-booking-icefaces/trunk/swf-booking-icefaces. The build process is explained in the readme.txt included with the project. This application is based on the original Spring Booking demonstration application, and consists of a simple Web Flow example coupled with ICEfaces components. Using the build mechanism in place from the Spring examples allows Ivy to resolve any JAR dependencies.

Configuring Spring Applications to Work with ICEfaces

Generally speaking, Spring Web Flow applications are about managing state change and managing navigation through the web application. ICEfaces can certainly work in this environment, but ICEfaces brings Ajax technology to web applications simply, without exposure to verbose JavaScript. Using partial submits, you can increase the functionality of a given page and expose more business logic without the need for the same amount of cumbersome full-page navigation states in the application. Any single page can now be enhanced with features, such as autocomplete, with values fetched from the Server, or server-based business rules for calculating intermediate costs.

The good news is that requests to the server made by ICEfaces components don't change or affect the state of the current Web Flow State as long as the interaction doesn't return a navigation result that is the same as the result defined for the Spring Web Flow. This means that you can add a component to the page and go about increasing functionality without worrying about inadvertently changing the application's behavior.

Primarily, the changes to a Spring application to work with ICEfaces consist of:

Changes to webflow-config.xml

There are some concepts necessary for correctly configuring the always-redirect-on-pause configuration parameter. The Spring resource is an excellent starting point: http://www.ervacon.com/products/swf/tips/tip4.html

There are certain applications that can benefit from ICEFaces AJAX navigation. In this type of configuration, interaction is done via POST requests, but the response contains the updates to the page. If navigation occurs, then the new page contents are fully rendered in the response and redirects are not necessary. We don't recommend this type of interaction for applications where duplicate POSTing of details is an issue but it does have applications.

The downside to setting the always-redirect-on-pause setting to false in ICEFaces is that without redirects, the Flow execution key isn't inserted into the URL in the nav bar. This means that reloading the page will restart the Flow.

The default for Spring Web Flow is to consider always-redirect-on-pause=true. Add the following always-redirect-on-pause attribute to webflow-config.xml for ICEFaces POST->Response behavior:


 
<!-- Executes flows: the central entry point into the Spring Web Flow system--> 
<webflow:flow-executor id="flowExecutor"> 
 
  <webflow:flow-execution-attributes> 
 
    <webflow:always-redirect-on-pause value="false" /> 
 
  </webflow:flow-execution-attributes> 
 
  <webflow:flow-execution-listeners> 
 
	<webflow:listener  ref="jpaFlowExecutionListener" /> 
 
	<webflow:listener ref="securityFlowExecutionListener" /> 
 
  </webflow:flow-execution-listeners>
 

 
Changes to web.xml

The following is the web.xml file from the downloadable example application:

<?xml version="1.0" encoding="ISO-8859-1"?>
 
<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
 
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 
	xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee 
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
 
	version="2.4">
 

 
	<!-- The master configuration file for this Spring web application -->
 

 
	<context-param>
 
		<param-name>contextConfigLocation</param-name>
 
		<param-value>
 
			/WEB-INF/config/web-application-config.xml
 
		</param-value>
 
	</context-param>
 

 
	
 
	<!-- Use JSF view templates saved as *.xhtml, for use with Facelets -->
 
	<context-param>
 
		<param-name>javax.faces.DEFAULT_SUFFIX</param-name>
 
		<param-value>.xhtml</param-value>
 
	</context-param>
 
	
 
	<!-- Enables special Facelets debug output during development -->
 
  	<context-param>
 
        <param-name>facelets.DEVELOPMENT</param-name>
 
   		<param-value>true</param-value>
 
  	</context-param>
 
  	
 
  	<!-- Causes Facelets to refresh templates during development -->
 
  	<context-param>
 
  		<param-name>facelets.REFRESH_PERIOD</param-name>
 
  		<param-value>1</param-value>
 
  	</context-param>
 
	
 
	<!-- Enables Spring Security -->
 
	 <filter>
 
        <filter-name>springSecurityFilterChain</filter-name>
 
        <filter-class>
 
               org.springframework.web.filter.DelegatingFilterProxy
 
        </filter-class>
 
    </filter>
 

 
    <filter-mapping>
 
      <filter-name>springSecurityFilterChain</filter-name>
 
      <url-pattern>/*</url-pattern>
 
    </filter-mapping>
 

 
	<!-- Loads the Spring web application context -->
 
	<listener>
 
		<listener-class>
 
            org.springframework.web.context.ContextLoaderListener
 
    </listener-class>
 
	</listener>
 
  	
 
  	<!-- Serves static resource content from .jar files such as spring-faces.jar -->
 
	<servlet>
 
		<servlet-name>Resources Servlet</servlet-name>
 
		<servlet-class>org.springframework.js.resource.ResourceServlet</servlet-class>
 
		<load-on-startup>0</load-on-startup>
 
	</servlet>
 
		
 
    <servlet>
 
        <servlet-name>SpringWebFlowInstantiationServlet</servlet-name>
 
        <servlet-class>
 
            com.icesoft.faces.webapp.http.servlet.SpringWebFlowInstantiationServlet
 
        </servlet-class>
 
                <init-param>
 
                        <param-name>contextConfigLocation</param-name>
 
                        <param-value>
 
                             /WEB-INF/config/web-application-config.xml
 
                        </param-value>
 
                </init-param>
 
        <load-on-startup> 1 </load-on-startup>
 
    </servlet>
 
    
 
	<!-- Map all /resources requests to the Resource Servlet for handling -->
 
	<servlet-mapping>
 
		<servlet-name>Resources Servlet</servlet-name>
 
		<url-pattern>/resources/*</url-pattern>
 
	</servlet-mapping>
 
	
 
	<!-- The front controller of this Spring Web application, responsible 
 
       for handling all application requests -->
 
	<servlet>
 
		<servlet-name>Spring MVC Dispatcher Servlet</servlet-name>
 
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
 
		<init-param>
 
			<param-name>contextConfigLocation</param-name>
 
			<param-value></param-value>
 
		</init-param>
 
		<load-on-startup>2</load-on-startup>
 
	</servlet>
 
		
 
	<!-- Map all /spring requests to the Dispatcher Servlet for handling -->
 
	<servlet-mapping>
 
		<servlet-name>Spring MVC Dispatcher Servlet</servlet-name>
 
		<url-pattern>/pages/*</url-pattern>
 
	</servlet-mapping>
 

 
	<!-- Just here so the JSF implementation can initialize, 
 
       *not* used at runtime -->
 
	<servlet>
 
		<servlet-name>Faces Servlet</servlet-name>
 
		<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
 
		<load-on-startup>1</load-on-startup>
 
	</servlet>
 
	
 
	<!-- Just here so the JSF implementation can initialize -->
 
	<servlet-mapping>
 
		<servlet-name>Faces Servlet</servlet-name>
 
		<url-pattern>*.faces</url-pattern>
 
	</servlet-mapping>
 
	
 
	<welcome-file-list>
 
		<welcome-file>index.html</welcome-file>
 
	</welcome-file-list>
 

 
<!--  Icesoft specific config --> 
 
<!-- Specifies to the ICEfaces framework whether to support multiple views of a
 
     single application from the same browser.  When running in a Portlet
 
     environment, this parameter must be set to true. -->
 
    <context-param>
 
        <param-name>com.icesoft.faces.concurrentDOMViews</param-name>
 
        <param-value>true</param-value>
 
    </context-param>
 

 
	<context-param>
 
		<param-name>javax.faces.STATE_SAVING_METHOD</param-name>
 
		<param-value>server</param-value>
 
	</context-param>
 

 
    <context-param>
 
        <param-name>com.icesoft.faces.synchronousUpdate</param-name>
 
        <param-value>false</param-value>
 
    </context-param>
 

 
    <context-param>
 
        <param-name>com.sun.faces.validateXml</param-name>
 
        <param-value>true</param-value>
 
    </context-param>
 

 
    <context-param>
 
        <param-name>com.prime.facestrace.DISABLE_TRACE</param-name>
 
        <param-value>true</param-value>
 
    </context-param>
 

 
    <context-param>
 
        <param-name>com.icesoft.faces.standardRequestScope</param-name>
 
        <param-value>true</param-value>
 
    </context-param>
 

 
    <context-param>
 
        <param-name>com.icesoft.faces.uploadDirectory</param-name>
 
        <param-value>upload</param-value>
 
    </context-param>
 

 
<listener>
 
        <listener-class>
 
             com.icesoft.faces.util.event.servlet.ContextEventRepeater
 
        </listener-class>
 
    </listener>
 
	<listener>
 
		<listener-class>
 
			com.sun.faces.application.WebappLifecycleListener
 
		</listener-class>
 
	</listener>
 

 
    <!-- file upload Servlet -->
 
    <servlet>
 
         <servlet-name>uploadServlet</servlet-name>
 
         <servlet-class>
 
             com.icesoft.faces.component.inputfile.FileUploadServlet
 
         </servlet-class>
 
         <load-on-startup> 1 </load-on-startup>
 
    </servlet>
 

 

 
    <servlet>
 
        <servlet-name>Persistent Faces Servlet</servlet-name>
 
        <servlet-class>
 
            com.icesoft.faces.webapp.xmlhttp.PersistentFacesServlet
 
        </servlet-class>
 
        <load-on-startup> 1 </load-on-startup>
 
    </servlet>
 

 
    <servlet>
 
        <servlet-name>Blocking Servlet</servlet-name>
 
        <servlet-class>
 
            com.icesoft.faces.webapp.xmlhttp.BlockingServlet
 
        </servlet-class>
 
        <load-on-startup> 1 </load-on-startup>
 
    </servlet>
 

 
    <servlet-mapping>
 
        <servlet-name>Persistent Faces Servlet</servlet-name>
 
        <url-pattern>*.xhtml</url-pattern>
 
    </servlet-mapping>
 

 
    <servlet-mapping>
 
        <servlet-name>Persistent Faces Servlet</servlet-name>
 
        <url-pattern>/xmlhttp/*</url-pattern>
 
    </servlet-mapping>
 

 
    <servlet-mapping>
 
        <servlet-name>Persistent Faces Servlet</servlet-name>
 
        <url-pattern>/spring/*</url-pattern>
 
    </servlet-mapping>
 

 
    <servlet-mapping>
 
        <servlet-name>Blocking Servlet</servlet-name>
 
        <url-pattern>/block/*</url-pattern>
 
    </servlet-mapping>
 

 
    <session-config>
 
      <session-timeout>30</session-timeout>
 
    </session-config>
 

 
</web-app>
 
Notes on web.xml
Changes to faces-config.xml
<?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>
 
                <view-handler>
 
                        com.sun.facelets.FaceletViewHandler
 
                </view-handler>
 
		<view-handler>
 
			  com.icesoft.faces.facelets.D2DFaceletViewHandler
 
		</view-handler>
 
		<variable-resolver>
 
       org.springframework.web.jsf.DelegatingVariableResolver
 
    </variable-resolver>
 
	</application>
 

 
</faces-config>
 

In this file, be sure to have the appropriate JSF variable resolver specified. See the Spring Framework 2.1 reference Section 15.3, Integrating with JavaServer Faces.

Known Issues
Server-initiated Rendering

Using server-initiated rendering can cause problems with regard to Web Flow states. When a server-initiated render operation starts, the Web Flow executor key is retrieved from the UIViewRoot, and the Web Flow state is resumed. This is okay, and works properly, but it does cause problems if the Web Flow has reached a terminal state. In this case, the Web Flow cannot be resumed.

There might be several server-initiated rendering scenarios for your application. Currently, it is difficult to know when a page transition occurs as part of a partial submit; hence, it is difficult to know precisely when to stop the server-initiated rendering if the page transitions to a Web Flow terminal state.

Consider an example of an application with an outputText component displaying the time on the bottom of the page every 5 seconds. This type of component would be easy to add to a footer, so it is included on every page of the application. This would cause problems in the Web Flow sellitems demonstration application because when the application winds up in the shipping cost summary page, the Web Flow has reached a terminal state. If the ticking clock is still updating at this time, this will cause exceptions when it tries to restore the Web Flow as part of the server-initiated rendering pass.

The DisposableBean interface (and the deprecated ViewListener interface) allow the server-initiated rendering code to know when the user leaves a particular view. For more information on the DisposableBean interface, refer to The DisposableBean Interface.

Spring Web Flow 2.0.5

In Spring Web Flow 2.0.5, there is a known issue with ICEFaces ViewHandler delegation. To use ICEFaces with Spring Web Flow 2.0.5, use the following faces-config.xml file contents:

<application>
 
        <view-handler>
 
            com.sun.facelets.FaceletViewHandler
 
        </view-handler>
 
        <view-handler>
 
            com.icesoft.faces.facelets.D2DFaceletViewHandler
 
        </view-handler>
 
        <view-handler>
 
            org.springframework.faces.webflow.FlowViewHandler
 
        </view-handler>
 

 
        <variable-resolver>
 
		org.springframework.web.jsf.DelegatingVariableResolver
 
	 </variable-resolver>
 
    </application>
 

This will cause two instances of the FlowViewHandler to be instantiated, but they will not collide.



Copyright 2005-2009. ICEsoft Technologies, Inc.
TOC PREV NEXT INDEX