Google App Engine / JSF 2 / Facelets / Primefaces

Retour sur GWT

Après quelques semaines sur GWT, je me suis vite lassé. Si on n'a pas d'éediteur graphique digne de ce nom ou une librairie intéressante de widget,on perd pas mal de temps à réaliser des applications dignes de ce nom ( à moins de s'appeler google biensûr...) Je suis donc revenu aux fondamentaux et me voila revenu sur JSF. J'en ai profité pour tester la version 2.0 sur Google App Engine. Et la c'est le drâme. C'est un vrai parcours du combattant ou un champ de mines, à vous de voir.

Problèmes rencontrés

Pas mal de problèmes que j'ai eu ont été résolus en me référant sur ce tutoriel ou sur cette page chez google

Pour faire simple, voici un résumé des problèmes

  • La version 1.3.2 de l'appengine ne fonctionnait pas chez moi avec netbeans :-( Obligé de passer en 1.3.1
  • L'implémentation standard de JSF2 n'est pas supporté par défaut dans GAE car elle utilise la classe InitialContext qui n'est pas supportée.
  • Il y a pas mal de paramètres à ajouter dans le web.xml ( cf ci-après )
  • Pas de page de debug de facelets car nous sommes obligé de travailler dans un mode différent de DEVELOPMENT
  • Le scope VIEW n'est pas "trop" supporté
  • Problème XALAN ( voir après)

Dépendances à ajouter

Commons-logging

Petite dépendance nécessaire et qui n'apparaît qu'à l'éxecution

log4j

Idem

facestrace

Très utile pour le debug. De plus ce composant est bien intégré à primefaces. Il suffit d'ajouter le paramètre de requête HTTP trace=true pour que la console facestrace apparaisse.

xalan

Si comme moi vous avez l'erreur suivante

    com.sun.faces.config.ConfigurationException: CONFIGURATION FAILED! 
    com.sun.org.apache.xalan.internal.xsltc.runtime.BasisLibrary is a restricted class. Please see the Google App 
    Engine developer's guide for more details.

Vous devez ajouter les librairies serializer.jar et xalan.jar provenant du projet xalan dans le répertoire WEB-INF/lib de votre webapp.

Ma Configuration

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" 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">
    <display-name>
        wine cellar
    </display-name>
    <description>
        wine cellar
    </description>
    <!-- ***** GAE 1.3.0 appears to handle server-side state saving. *****  -->
    <context-param>
        <param-name>javax.faces.STATE_SAVING_METHOD</param-name>
        <param-value>client</param-value>
    </context-param>
    <context-param>
        <param-name>javax.faces.PROJECT_STAGE</param-name>
        <param-value>Production</param-value>
    </context-param>
    <context-param>
        <param-name>javax.faces.DEFAULT_SUFFIX</param-name>
        <param-value>.xhtml</param-value>
    </context-param>
    <context-param>
        <param-name>com.sun.faces.expressionFactory</param-name>
        <param-value>com.sun.el.ExpressionFactoryImpl</param-value>
    </context-param>
    <context-param>
        <description>
            Set this flag to true if you want the JavaServer Faces
            Reference Implementation to validate the XML in your
            faces-config.xml resources against the DTD. Default
            value is false.
        </description>
        <param-name>com.sun.faces.validateXml</param-name>
        <param-value>true</param-value>
    </context-param>
    <!-- ***** Accommodate Single-Threaded Requirement of Google AppEngine  -->
    <context-param>
        <description>
            When enabled, the runtime initialization and default ResourceHandler
            implementation will use threads to perform their functions. Set this
            value to false if threads aren't desired (as in the case of running
            within the Google Application Engine).
 
            Note that when this option is disabled, the ResourceHandler will not
            pick up new versions of resources when ProjectStage is development.
        </description>
        <param-name>com.sun.faces.enableThreading</param-name>
        <param-value>false</param-value>
    </context-param>
    <!-- primefaces -->
    <context-param>
        <param-name>com.sun.faces.allowTextChildren</param-name>
        <param-value>true</param-value>
    </context-param>
    <!-- Faces Servlet -->
    <context-param>
        <param-name>com.sun.faces.enableMultiThreadedStartup</param-name>
        <param-value>false</param-value>
    </context-param>
    <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>Resource Servlet</servlet-name>
        <servlet-class>
            org.primefaces.resource.ResourceServlet
        </servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>Resource Servlet</servlet-name>
        <url-pattern>/primefaces_resource/*</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>Faces Servlet</servlet-name>
        <url-pattern>/faces/*</url-pattern>
        <url-pattern>*.jsf</url-pattern>
    </servlet-mapping>
    <session-config>
        <session-timeout>30</session-timeout>
    </session-config>
    <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
        <welcome-file>index.xhtml</welcome-file>
        <welcome-file>index.html</welcome-file>
    </welcome-file-list>
</web-app>

Le fichier faces-config.xml

<faces-config version="2.0"
    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_0.xsd">
<application>
    <locale-config>
      <default-locale>en</default-locale>
    </locale-config>
  </application>
 
    <managed-bean>
...
    </managed-bean>
 
</faces-config>

Limitations

Et oui il y a des limitations à tout ça : L'un des gros plus de la spec JSF2 est la scope view qui permet de conserver l'état d'un composant au sein d'une page dans n'importe quelle étape du cycle de vie JSF. Bref, c'est entre le scope session et le scope request. GAE ne semble pas trop le supporter. Il est même préférable de n'utiliser que le scope request. Personnellement j'ai du adapter mon design à un mode réellement sans état. GAE ne supporte pas le PROJECT_STAGE Development Il faut donc le paramétrer tel quel

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

Cette configuration semble occulter la page d'erreur standard de facelets qui est très utile pendant le développement. Heureusement facestrace est la.

Enfin, l'une des grosses limitations est la suppression des données entre chaque arrêt/relance du SDK GAE. Je n'ai pas encore cherché trouvé comment les garder en mémoire.

Conclusion

A cette armé mexicaine de composants, il ne me manque qu'une solution d'IoC ( probablement CDI ) et surement un framework d' AOP. GAE fournit déjà pas mal de composants permettant de gérer les objets en mémoire et d'améliorer les perfs.

La suite dans un prochain numéro...

Vus : 919
Publié par Littlewing : 368