Migrer une application JSF 1.2 / Richfaces 3 vers JSF 2 / Richfaces 4

Migration Plutôt que faire un énième article présentant les nouveautés de JSF 2. J’ai décidé d’attaquer le problème sous un autre angle.

En effet, lorsque j’ai voulu tester ce que propose JSF 2 et le mettre en application, je suis parti de l’application Personne du blog qui est une application JSF 1.2 (avec Richfaces 3.3.3) pour la migrer vers JSF 2 et Richfaces 4.

Il est possible d’utiliser Richfaces 3.3.x avec JSF 2 mais tout n’est pas compatible, alors autant tout migrer en même temps :)

Je vais donc vous présenter dans cet article un cas concret de migration d’une application JSF 1.2 vers JSF 2.

Pour appuyer mon propos, je me base sur la version 1.2.1 du projet Personne pour la partie JSF 1.2 et la version 1.3.0 pour la partie JSF 2.

Le projet utilise également Spring, mais aucune modification n’est à effectuer de ce coté pour la migration. Ceci est vrai pour la configuration à proprement dite. Dans le cycle de vie des beans, c’est une autre histoire et nous reviendrons dessus dans l’article.

Si vous souhaitez en savoir plus sur la création d’un projet avec Spring et JSF, vous pouvez lire cet article => Faire communiquer Spring et JSF

 

Sommaire

Dépendances Maven

Modification du web.xml

Modification du faces-config.xml

Modification coté xhtml

Modification coté Java

Conclusion

 

Dépendances Maven


Tout d’abord, les dépendances Maven de JSF et Richfaces ont changé. Voici donc les nouvelles dépendances pour JSF 2:

<dependency>
    <groupId>com.sun.faces</groupId>
    <artifactId>jsf-api</artifactId>
    <version>2.1.7</version>
</dependency>
<dependency>
    <groupId>com.sun.faces</groupId>
    <artifactId>jsf-impl</artifactId>
    <version>2.1.7</version>
</dependency>

Richfaces 4 utilise le principe de BOM Maven. Il faut donc ajouter cette dépendance dans la section dependencyManagement du pom.xml:

<dependency>
    <groupId>org.richfaces</groupId>
    <artifactId>richfaces-bom</artifactId>
    <version>4.2.0.Final</version>
    <scope>import</scope>
    <type>pom</type>
</dependency>

Puis celles ci dans la section dependencies. Remarquez que grâce au principe du bom, nous n’avons pas besoin de spécifier les versions des dépendances:

<dependency>
    <groupId>org.richfaces.ui</groupId>
    <artifactId>richfaces-components-ui</artifactId>
</dependency>
<dependency>
    <groupId>org.richfaces.core</groupId>
    <artifactId>richfaces-core-impl</artifactId>
</dependency>

Remplacez également la dépendance suivante:

<dependency>
    <groupId>com.sun.el</groupId>
    <artifactId>el-ri</artifactId>
    <version>1.0</version>
</dependency>

Par:

<dependency>
    <groupId>javax.el</groupId>
    <artifactId>el-api</artifactId>
    <version>2.2</version>
</dependency>

Facelets étant maintenant intégré dans JSF 2, il faut supprimer les dépendances liées à Facelets.

 

Modification du web.xml


Maintenant que nos dépendances sont à jour, passons au web.xml. Il s’agit principalement d’un changement de nom pour les listeners et les context-params du web.xml, je vous propose donc un tableau de comparaisons entre ancienne et nouvelle valeur:

Ancienne valeur Nouvelle valeur
facelets.BUFFER_SIZE javax.faces.BUFFER_SIZE
facelets.REFRESH_PERIOD javax.faces.FACELETS_REFRESH_PERIOD
facelets.RESOURCE_RESOLVER javax.faces.FACELETS_RESOURCE_RESOLVER
facelets.RESOURCE_RESOLVER javax.faces.FACELETS_RESOURCE_RESOLVER
org.richfaces.SKIN org.richfaces.skin

 

Il existe d’autres changements de nom, mais il s’agit d’un article sur un cas concret, je ne ferais donc pas la liste complète de ces changements.

Le context-param facelets.DEVELOPMENT a changé de manière plus importante. Il s’agissait auparavant d’indiquer si l’on était en développement ou non.

Son remplaçant est un peu plus complexe. Voici son code:

<context-param>
    <param-name>javax.faces.PROJECT_STAGE</param-name>
    <param-value>Development</param-value>
</context-param>

Ce paramètre indique toujours le mode de l’application mais de manière plus précise. Voici les valeurs que peut prendre ce paramètre:

Enfin, Facelets ayant été supprimé, vous pouvez supprimer le context-param et le filter suivants:

  • org.ajax4jsf.VIEW_HANDLERS
  • org.ajax4jsf.Filter

 

Modification du faces-config.xml


La seule modification nécessaire dans le faces-config.xml est de changer la version de ce dernier.
Concrètement remplacer:

<faces-config 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"
    version="1.2">

Par:

<faces-config 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"
    version="2.1">

Voila, c’est tout pour ce fichier :)

 

Modification coté xhtml


La partie configuration à proprement dite est maintenant prête. Attaquons nous maintenant au code même de l’application. Nous allons faire ceci en deux parties: le code des xhtml dans ce chapitre et le code Java dans le chapitre suivant.

Jsf étant une technologie de présentation, c’est clairement vos pages xhtml qui seront les plus impactées par cette migration.

Les principales modifications vont concerner les composants Richfaces, les composants Jsf étant compatibles d’une version à l’autre en grande majorité.

Un point avant de voir les modifications Richfaces. Les éléments HTML purs ont également besoin d’être déclarés dans les namespaces de votre page, sans quoi des erreurs seront remontées à l’exécution. Pour se faire rajouté ce namespace dans le ui:composition de votre page:

xmlns="http://www.w3.org/1999/xhtml"

Ce qui vous donnera un ui:composition de cette forme:

<ui:composition
    xmlns="http://www.w3.org/1999/xhtml"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:a4j="http://richfaces.org/a4j"
    xmlns:rich="http://richfaces.org/rich"
    xmlns:ui="http://java.sun.com/jsf/facelets"
    template="/templates/default.xhtml">

Jsf 2 apporte les fonctionnalités Ajax qui manquaient à la version 1.2. Richfaces 3 comblaient ces manques en apportant ces propres fonctionnalités Ajax.

Afin d’éviter un doublon entre les deux modes, Richfaces 4 supprime des tags apportant l’Ajax. D’autres tags sont également supprimés et vous devez donc fournir un équivalant. Voici les tags supprimés impactant l’application:

  • a4j:keepAlive est remplacé par le scope View de Jsf 2, nous reviendrons dessus dans le chapitre suivant.
  • a4j:form. Utilisé uniquement le tag h:form
  • rich:spacer. Pas d’équivalent mais remplacez le par une simple <div> avec une classe css.
  • a4j:loadStyle est remplacé par h:outputStylesheet
  • a4j:loadScript est remplacé par h:outputScript
  • rich:modalPanel est renommé rich:popupPanel

Comme je l’ai dit plus haut, Jsf 2 apporte des fonctionnalités Ajax. Le principal tag concernant cette fonctionnalité est f:ajax. Vous pouvez remplacer tous vos a4j:support par ce tag mais Richfaces propose son propre tags qui étend les fonctionnalités de f:ajax: le tag a4j:ajax.

Ce tag est simplement la mise à jour de a4j:support en standardisant ses attributs avec ce que propose Jsf 2. Ainsi les principaux changements concernant les attributs de tags sont:

  • action devient listener. La signature de la méthode du listener coté Java devient:
public void function(AjaxBehaviorEvent event);
  • reRender devient render. Il s’utilise de la même façon que dans Richfaces 3.
  • Les paramètres de l’attribut event sont standardisés. Ils perdent le « on » de leur nom. Ainsi « onclick » devient « click », « onchange » devient « change » est ainsi de suite. Ceci afin de correspondre aux spécifications Jsf 2.

Il faut noter également l’apparition de l’attribut execute. Vous allez spécifier dans votre attribut quels éléments vont être envoyés au serveur lors de l’exécution de votre requête. Les paramètres possibles sont:

  • @all qui enverra toute la page
  • @this qui enverra uniquement le champ sur lequel s’applique le a4j:ajax
  • @form qui enverra tout le formulaire ou le champ se trouve
  • @none. Aucun élément ne sera envoyé
  • @region qui enverra les éléments du a4j:region si vous l’utilisez

Vous pouvez également saisir une liste d’ids correspondant à des éléments de votre page. Ces éléments seront alors envoyés au serveur.

 

Un autre changement impactant pour vos pages xhtml est la gestion des fichiers css et javascript. Auparavant, vous pouviez placer vos fichiers où vous le vouliez et le tag de chargement les retrouvait afin de les charger dans votre page.

Maintenant avec l’utilisation des tags h:outputStylesheet et h:outputScript, vous devez obligatoirement placer vos fichiers dans les répertoires suivants (dans le cas d’un war):

webapp
--resources
----js
----css

Vos javascripts étant dans le répertoire « js » et vos css dans le répertoire « css ».

 

Dernière indication concernant la migration de vos pages et Richfaces. Cette librairie de composant ne supporte plus Internet Explorer 6 (ce qui est très bien comme ça :) ), néanmoins, si vous devez toujours supporter ce navigateur, c’est un paramètre à prendre en compte.

Sachez également que Richfaces 4 ne propose pas à ce jour la compression de ses javascripts (ce que faisait Richfaces 3). Cela viendra certainement, mais ça sera à vous de le faire aujourd’hui.

 

Modification coté Java


Dernière étape de notre migration Jsf 1.2 vers Jsf 2: la modification du code Java.

Comme je l’ai signalé plus haut, Richfaces ne gère plus le KeepAlive, l’annotation @KeepAlive allant avec est donc supprimée. Cette suppression est dû à la mise en place par Jsf du scope View qui fait à peux près la même chose. Si vous souhaitez utiliser les nouvelles annotations Jsf, vous devrez annoter vos beans utilisant le KeepAlive par:

@ManagedBean
@ViewScoped

Si vous utilisez Spring pour manager vos beans, vous devrez implémenter le scope View de Jsf vous même.

Si vos beans sont peu typés Jsf, c’est,  avec le changement de signature des méthodes actions, à peut près les seules modifications que vous aurez à effectuer dans votre code Java.

 

Conclusion


C’est finit pour cette migration. Techniquement, cette migration se passe plus bien. Toutefois si vous avez une application complexe avec de grosses pages xhtml, elle peut vous coûter beaucoup de temps (et donc d’argent) surtout si vous utilisez beaucoup de fonctionnalités Ajax.

Si vous utilisiez Richfaces seulement pour ses capacités Ajax, il n’est peut être pas utile de garder ce framework. En effet, tout ce que propose Richfaces 3 en matière d’Ajax existe à présent de base dans Jsf 2. Néanmoins, les composants apportés par Richfaces 4 sont toujours intéressants.

Comme je l’ai dit au début de l’article, je présente un cas concret de migration depuis l’application « Personne » du blog. L’article ne présente donc pas une liste exhaustive de toutes les modifications que vous pourriez avoir à effectuer.

Néanmoins les problèmes principaux que vous pourriez rencontrer sont présentés.

Je vous invite à regarder le code source de la version 1.3.0 du projet « Personne » afin de voir l’exemple dans son ensemble ;)

 

Liens utiles:

Javadoc des tags Jsf 2: http://javaserverfaces.java.net/nonav/docs/2.0/pdldocs/facelets/

Javadoc des tags Richfaces 4.2: http://docs.jboss.org/richfaces/latest_4_2_X/vdldoc/

Guide de migration Richfaces 3 vers Richfaces 4: http://www.jboss.org/richfaces/docs/3-x-4-x-migration

Démonstration des tags Richfaces 4: http://richfaces-showcase.appspot.com/richfaces/component-sample.jsf