Skip to main content

Notes on upgrade to JSF 2.1, Servlet 3.0, Spring 4.0, RichFaces 4.3

This article is devoted to an upgrade of a common JSF Spring application. Time flies and there is already Java EE 7 platform out and widely used. It's sometimes said that Spring framework has become legacy with appearance of Java EE 6. But it's out of scope of this post. Here I'm going to provide notes about the minimal changes that I found required for the upgrade of the application from JSF 1.2 to 2.1, from JSTL 1.1.2 to 1.2, from Servlet 2.4 to 3.0, from Spring 3.1.3 to 4.0.5, from RichFaces 3.3.3 to 4.3.7. It must be mentioned that the latest final RichFaces release 4.3.7 depends on JSF 2.1, JSTL 1.2 and Servlet 3.0.1 that dictated those versions. This post should not be considered as comprehensive but rather showing how I did the upgrade. See the links for more details.
  1. Jetty & Tomcat.
  2. JSTL.
  3. JSF & Facelets.
  4. Servlet.
  5. Spring framework.
  6. RichFaces.
Jetty & Tomcat
First, I upgraded the application to run with the latest servlet container versions. For development I use maven jetty plugin that had to be upgraded in pom.xml from version 6:
<plugin>
  <groupId>org.mortbay.jetty</groupId>
  <artifactId>maven-jetty-plugin</artifactId>
  <version>6.1.26</version>
  <configuration>
    <connectors>
      <connector implementation="org.mortbay.jetty.nio.SelectChannelConnector">
        <port>8080</port>
        <maxIdleTime>30000</maxIdleTime>
      </connector>
    </connectors>
    <contextPath>/${project.artifactId}</contextPath>
    <systemProperties>
      <systemProperty>
        <name>org.apache.cocoon.mode</name>
        <value>dev</value>
      </systemProperty>
    </systemProperties>
  </configuration>
</plugin>
to version 9:
<plugin>
  <groupId>org.eclipse.jetty</groupId>
  <artifactId>jetty-maven-plugin</artifactId>
  <version>9.2.1.v20140609</version>
  <configuration>
    <scanIntervalSeconds>10</scanIntervalSeconds>
    <webApp>
      <contextPath>/${project.artifactId}</contextPath>
    </webApp>
    <systemProperties>
      <systemProperty>
        <name>org.apache.cocoon.mode</name>
        <value>dev</value>
      </systemProperty>
    </systemProperties>
  </configuration>
</plugin>
Besides, I could safely remove the following listeners from web.xml as the corresponding issue was fixed in the latest versions of tomcat:
<listener>
  <listener-class>com.sun.faces.config.ConfigureListener</listener-class>
</listener>

<listener>
  <listener-class>com.sun.faces.application.WebappLifecycleListener</listener-class>
</listener>

JSTL
As JSTL 1.2 is a maintenance release and I used only c:set tag, I had nothing to do except updating pom.xml:
<dependency>
  <groupId>javax.servlet</groupId>
  <artifactId>jstl</artifactId>
  <version>1.2</version>
</dependency>

JSF & Facelets
While you can find useful this extended JSF upgrade guide at stackoverflow, I'm going to show the changes I made below. First, I removed facelets dependency and updated jsf dependencies versions in pom.xml. Initially it was:
<dependency>
  <groupId>javax.faces</groupId>
  <artifactId>jsf-api</artifactId>
  <version>1.2_13</version>
</dependency>
<dependency>
  <groupId>javax.faces</groupId>
  <artifactId>jsf-impl</artifactId>
  <version>1.2_13</version>
</dependency>
<dependency>
  <groupId>com.sun.facelets</groupId>
  <artifactId>jsf-facelets</artifactId>
  <version>1.1.15</version>
</dependency>
As I use RichFaces, its latest version 4.3.7.Final provides richfaces-bom artifact with required JSF version specified as 2.1.28. Thus, I could simply omit version tags:
<dependency>
  <groupId>com.sun.faces</groupId>
  <artifactId>jsf-api</artifactId>
</dependency>
<dependency>
  <groupId>com.sun.faces</groupId>
  <artifactId>jsf-impl</artifactId>
</dependency>
Second, I updated faces-config.xml to comply JSF 2.1 spec. Initially it was:
<faces-config version="1.2" xmlns="http://java.sun.com/xml/ns/javaee"
              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
              http://java.sun.com/xml/ns/javaee/web-facesconfig_1_2.xsd">
  <application>
    <el-resolver>org.springframework.web.jsf.el.SpringBeanFacesELResolver</el-resolver>
    <view-handler>com.sun.facelets.FaceletViewHandler</view-handler>
    <!-- locale-config and resource-bundle here -->
  </application>

  <!-- converters here -->

  <navigation-rule>
    <!-- navigation-cases here -->
  </navigation-rule>
</faces-config>
I modified the root declaration, removed FaceletViewHandler, added from-view-id to fix validation issue and replaced converters with annotations. Well, actually I didn't use JSF @FacesConverter annotation but used Spring @Component instead. Similarly, all managed beans were annotated with @Controller before so I didn't have to add @ManagedBean annotations during the upgrade. Using Spring annotations is allowed as a replacement for both JSF 1.2 and 2.0 thanks to SpringBeanFacesELResolver. As a matter of fact, Spring and JSF 2 are heavily overlapping regarding the annotation support. Finally, this is the new version:
<faces-config version="2.1" xmlns="http://java.sun.com/xml/ns/javaee"
              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
              http://java.sun.com/xml/ns/javaee/web-facesconfig_2_1.xsd">
  <application>
    <el-resolver>org.springframework.web.jsf.el.SpringBeanFacesELResolver</el-resolver>
    <!-- locale-config and resource-bundle here -->
  </application>

  <navigation-rule>
    <from-view-id>*</from-view-id>
    <!-- navigation-cases here -->
  </navigation-rule>
</faces-config>
Third, I modified web.xml to get rid of Facelets 1.x related context-param tags. Initially it was:
<context-param>
  <param-name>facelets.RECREATE_VALUE_EXPRESSION_ON_BUILD_BEFORE_RESTORE</param-name>
  <param-value>false</param-value>
</context-param>

<context-param>
  <param-name>facelets.LIBRARIES</param-name>
  <param-value>/WEB-INF/springsecurity.taglib.xml</param-value>
</context-param>
As you can see, I use Spring Security taglib there that should be still declared:
<context-param>
  <param-name>javax.faces.FACELETS_LIBRARIES</param-name>
  <param-value>/WEB-INF/springsecurity.taglib.xml</param-value>
</context-param>
Fourth, the taglib springsecurity.taglib.xml should be modified as well. I won't paste the code here as the change just consists in renaming two Spring classes: Jsf12FaceletsAuthorizeTagHandler to FaceletsAuthorizeTagHandler and Jsf12FaceletsAuthorizeTagUtils to FaceletsAuthorizeTagUtils. You can find the final version of the taglib in spring samples here.
Finally, I replaced head with h:head and body with h:body in all xhtml files.

Servlet
To upgrade Servlet, first I updated pom.xml as usual. Initially it was:
<dependency>
  <groupId>javax.servlet</groupId>
  <artifactId>servlet-api</artifactId>
  <version>2.5</version>
  <scope>provided</scope>
</dependency>
As I use RichFaces, the servlet version is already specified as 3.0.1 in its bom artifact. Thus, I can simply add the dependency without version tag:
<dependency>
  <groupId>javax.servlet</groupId>
  <artifactId>javax.servlet-api</artifactId>
  <scope>provided</scope>
</dependency>
Then I updated the root declaration of web.xml. Below you can see both versions:
<web-app xmlns="http://java.sun.com/xml/ns/javaee" 
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
         http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
         version="2.5">
<web-app xmlns="http://java.sun.com/xml/ns/javaee" 
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
         http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
         version="3.0">
Finally, as there is a custom listener in the application, I added @WebListener annotation to that class and removed the listener from web.xml.

Spring framework
As for the Spring framework upgrade, the changes were absolutely minimal in my case. First, I updated Spring versions in pom.xml including Security, Web Services and Web Flow dependencies. Initially it was:
<properties>
  <spring.version>3.1.3.RELEASE</spring.version>
  <spring.security.version>3.1.3.RELEASE</spring.security.version>
  <spring.ws.version>2.1.1.RELEASE</spring.ws.version>
  <spring.webflow.version>2.3.1.RELEASE</spring.webflow.version>
</properties>
The updated code is:
<properties>
  <spring.version>4.0.5.RELEASE</spring.version>
  <spring.security.version>3.2.4.RELEASE</spring.security.version>
  <spring.ws.version>2.2.0.RELEASE</spring.ws.version>
  <spring.webflow.version>2.4.0.RELEASE</spring.webflow.version>
</properties>
Second, it appeared wsdl4j:wsdl4j:1.6.1 artifact was required but missing after the upgrade so I added it to the dependencies.
Finally, I replaced versioned schema locations with non-versioned in root declarations of all Spring configuration files.

RichFaces
The upgrade of RichFaces from 3.3.3 to 4.3.7 appeared to be very troublesome as I had to fix many issues afterwards. The official migration guide helps but does not cover every detail. First, I updated pom.xml from:
<properties>
  <richfaces.version>3.3.3.Final</richfaces.version>
</properties>
<dependencies>
  <dependency>
    <groupId>org.richfaces.framework</groupId>
    <artifactId>richfaces-impl</artifactId>
    <version>${richfaces.version}</version>
  </dependency>
  <dependency>
    <groupId>org.richfaces.ui</groupId>
    <artifactId>richfaces-ui</artifactId>
    <version>${richfaces.version}</version>
  </dependency>
</dependencies>
to:
<properties>
  <richfaces.version>4.3.7.Final</richfaces.version>
</properties>
<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>org.richfaces</groupId>
      <artifactId>richfaces-bom</artifactId>
      <version>${richfaces.version}</version>
      <scope>import</scope>
      <type>pom</type>
    </dependency>
  </dependencies>
</dependencyManagement>
<dependencies>
  <dependency>
    <groupId>org.richfaces.core</groupId>
    <artifactId>richfaces-core-impl</artifactId>
  </dependency>
  <dependency>
    <groupId>org.richfaces.ui</groupId>
    <artifactId>richfaces-components-ui</artifactId>
  </dependency>
</dependencies>
Second, I modified web.xml:
  • removed context-param with name org.ajax4jsf.VIEW_HANDLERS
  • removed RichFaces filter and corresponding filter-mapping
Third, there were many RichFaces component changes, so I did the following:
  • changed namespace from xmlns:rich="http://richfaces.ajax4jsf.org/rich" to xmlns:rich="http://richfaces.org/rich"
  • renamed rich:toolTip to rich:tooltip and removed attribute direction="top-right"
  • renamed rich:toolBar to rich:toolbar and rich:toolBarGroup to rich:toolbarGroup
  • renamed rich:modalPanel to rich:popupPanel
  • renamed attribute value to label of rich:menuItem
  • renamed attribute reRender to render
  • replaced attribute width="x" with style="width: x" on rich:dataTable and rich:column
  • replaced Richfaces.showModalPanel('x') with #{rich:component('x')}.show();
  • replaced Richfaces.hideModalPanel('x') with #{rich:component('x')}.hide();
  • replaced rich:componentControl[@event="onclick"] with attribute onclick on the target element
  • removed attribute selfSorted and changed attribute sortOrder to use enumeration values instead of literals

Comments

  1. Thank you for this useful post. I followed this steps and came across the problem which was caused by the version of the following dependency

    com/ocpsoft/prettyfaces-jsf12/3.3.3/prettyfaces-jsf12-3.3.3.jar

    when I replaced it with

    com/ocpsoft/prettyfaces-jsf2/3.3.3/prettyfaces-jsf2-3.3.3.jar

    for the second version of JSF, the problem has gone.
    Thank you

    ReplyDelete

Post a Comment

Popular posts from this blog

Connection to Amazon Neptune endpoint from EKS during development

This small article will describe how to connect to Amazon Neptune database endpoint from your PC during development. Amazon Neptune is a fully managed graph database service from Amazon. Due to security reasons direct connections to Neptune are not allowed, so it's impossible to attach a public IP address or load balancer to that service. Instead access is restricted to the same VPC where Neptune is set up, so applications should be deployed in the same VPC to be able to access the database. That's a great idea for Production however it makes it very difficult to develop, debug and test applications locally. The instructions below will help you to create a tunnel towards Neptune endpoint considering you use Amazon EKS - a managed Kubernetes service from Amazon. As a side note, if you don't use EKS, the same idea of creating a tunnel can be implemented using a Bastion server . In Kubernetes we'll create a dedicated proxying pod. Prerequisites. Setting up a tunnel.

DynamicReports and Spring MVC integration

This is a tutorial on how to exploit DynamicReports reporting library in an existing  Spring MVC based web application. It's a continuation to the previous post where DynamicReports has been chosen as the most appropriate solution to implement an export feature in a web application (for my specific use case). The complete code won't be provided here but only the essential code snippets together with usage remarks. Also I've widely used this tutorial that describes a similar problem for an alternative reporting library. So let's turn to the implementation description and start with a short plan of this how-to: Adding project dependencies. Implementing the Controller part of the MVC pattern. Modifying the View part of the MVC pattern. Modifying web.xml. Adding project dependencies I used to apply Maven Project Builder throughout my Java applications, thus the dependencies will be provided in the Maven format. Maven project pom.xml file: net.sourcefo