![]() |
![]() |
![]() |
![]() |
![]() |
Spring Framework 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.
Spring integration with ICEfaces should be considered preliminary only. The Spring Webflow (http://www.springframework.org/webflow) has recently released milestone versions 2.0 and 2.5, which are a substantial change to the framework and all integration efforts therein. ICEFaces support for version 1 (currently 1.0.5) of Spring Webflow is therefore preliminary, and not subject for improvement.
The easiest way to produce a working ICEfaces/Spring application is to copy the demonstration application available from http://downloads.icefaces.org. This application is based on the original Spring Sellitems demonstration application, and consists of a simple webflow example coupled with ICEfaces components and a demonstration of some pages with enhanced capability using partial submits to access server business logic without full-page transitions. Using the build mechanism in place from the Spring examples allows Ivy to resolve any JAR dependencies. In the demonstration application, a project.properties file contains the directory location of some Springcommon build files. The downloaded demonstration application is intended to go into the following directory:
{Spring base directory}/Spring-webflow-1.0.N/projects/spring-webflow-samples
where N is the version of Spring webflow in use.
Putting the demonstration application in this location allows the build files to work with the existing Spring build resources.
Generally speaking, Spring Webflow 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 Webflow State as long as the interaction doesn't return a navigation result that is the same as the result defined for the Spring Webflow. 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:
- Changing the default Spring variable resolver to the following, as per the
<variable-resolver>org.springframework.web.jsf.DelegatingVariableResolver</variable-resolver>. This allows defining beans defined in a webflow to be accessed during a JSF lifecycle. The opposite, defining beans used by Spring in the faces-config file, defeats other aspects of Spring configuration.- Changing web.xml to point to ICEfaces Servlets, and additionally defining a listener that allows access to Session scoped beans. This is required because the entrance into the JSF lifecycle is done through ICEfaces servlets, and not the Spring DispatcherServlet.
- Changing the JSP pages to include the ICEfaces taglib definitions and optionally using ICEfaces components to enhance page functionality.
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"> <context-param> <param-name>contextConfigLocation</param-name> <param-value> classpath:org/springframework/webflow/samples/sellitem/services-config.xml /WEB-INF/webflow-config.xml </param-value> </context-param> <context-param> <param-name>com.icesoft.faces.standardRequestScope</param-name> <param-value>true</param-value> </context-param> <!-- Bootstraps the root Spring Web Application Context, responsible for deploying managed beans defined in the configuration files above. These beans represent the services used by the JSF application. --> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener- class> </listener> <!--MyFaces listener that starts up the JSF engine by reading faces-config.xml --> <listener> <listener-class> org.apache.myfaces.webapp.StartupServletContextListener </listener-class> </listener> <listener> <listener-class> com.icesoft.faces.util.event.servlet.ContextEventRepeater </listener-class> </listener> <!-- Listener for initializing contexts in 3rd party servlet environment --> <listener> <listener-class> org.springframework.web.context.request.RequestContextListener </listener-class> </listener> <context-param> <param-name> com.icesoft.faces.synchronousUpdate </param-name> <param-value>true</param-value> </context-param> <context-param> <param-name> com.icesoft.faces.concurrentDOMViews </param-name> <param-value>false</param-value> </context-param> <context-param> <param-name> com.icesoft.faces.actionURLSuffix </param-name> <param-value>.iface</param-value> </context-param> <!-- The front controller for the JSF application, responsible for handling all application requests --> <servlet> <servlet-name>Faces Servlet</servlet-name> <servlet-class>javax.faces.webapp.FacesServlet</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>*.iface</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>Persistent Faces Servlet</servlet-name> <url-pattern>*.faces</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>Persistent Faces Servlet</servlet-name> <url-pattern>/xmlhttp/*</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>Blocking Servlet</servlet-name> <url-pattern>/block/*</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>Persistent Faces Servlet</servlet-name> <url-pattern>*.jsp</url-pattern> </servlet-mapping> <welcome-file-list> <welcome-file>index.html</welcome-file> </welcome-file-list> </web-app>
- ICEfaces servlets handle all requests from the browser.
- Synchronous request handling with concurrent DOM views are disabled.
<faces-config> <application> <navigation-handler> org.springframework.webflow.executor.jsf.FlowNavigationHandler </navigation-handler> <variable-resolver> org.springframework.web.jsf.DelegatingVariableResolver </variable-resolver> <!--<variable-resolver> org.springframework.webflow.executor.jsf.DelegatingFlowVariableResolver </variable-resolver>--> </application> <lifecycle> <phase-listener> org.springframework.webflow.executor.jsf.FlowPhaseListener </phase-listener> </lifecycle> </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.
Using server-initiated rendering can cause problems with regard to Webflow states. When a server-initiated render operation starts, the Webflow executor key is retrieved from the UIViewRoot, and the Webflow state is resumed. This is okay, and works properly, but it does cause problems if the Webflow has reached a terminal state. In this case, the Webflow 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 Webflow 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 Webflow sellitems demonstration application because when the application winds up in the shipping cost summary page, the Webflow 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 Webflow 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.
It is best to avoid server-initiated rendering within Spring Webflow applications for now. Once we understand the ramifications of Webflow 2.0, we'll be able to make using server-initiated rendering easier. In the meantime, using ICEfaces components with simple AJAX functionality should offer plenty of design flexibility.
![]() |
Copyright 2005-2008. ICEsoft Technologies, Inc. http://www.icesoft.com |
![]() |
![]() |
![]() |
![]() |