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...