Posts tagged: Facelets

Eclipse Helios : UTF-8 pour Facelet

By , 03/12/2010

En changeant de version d’Eclipse, je me suis rendu compte que mes fichiers facelet (xhtml) avaient l’encoding UTF-8 par défaut. Le problème c’est que sur mon ancienne installation d’Eclipse ces mêmes fichiers étaient en CP1252 (encoding par défaut sous Windows). C’est dans un forum que j’ai compris que WTP associe automatiquement et systématiquement l’encoding UTF-8 aux fichiers facelet. Pour modifier l’encoding de ces fichiers :

  1. Window -> Preferences
  2. General -> Content Types
  3. Associer CP1252 aux types : Text -> HTML -> Facelet et Text -> HTML -> Facelet -> Facelet Composite Component

c:forEach (java.lang.OutOfMemoryError: Java heap space)

By , 04/10/2010

Il m’ait arrivé récemment d’avoir une erreur de mémoire sur une page xhtml alors que les autres interfaces de mon application fonctionnaient correctement. L’erreur provenait de mon tag <c:forEach/>. Voici la boucle provoquant le problème de mémoire :


<c:forEach value="#{myList}">
   ...
</c:forEach>

En réalité, j’avais transformé une boucle <ui:repeat/> en <c:forEach/> sans modifier le nom de l’attribut correspondant au bean sur lequel il faut faire l’itération : value pour <ui:repeat/> et items pour <c:forEach/>. Voici les deux bonnes syntaxes :


<ui:repeat value="#{myList}">
   ...
</ui:repeat>

<c:forEach items="#{myList}">
   ...
</c:forEach>

Je ne suis visiblement pas le seul à avoir eu ce problème, si vous voulez avoir plus d’information sur la cause exacte de cette exception voici comment j’ai trouvé la solution : http://wiki.foochal.org/index.php/ForEachHandler_OutOfMemoryError.

Cycle de vie Facelets et la JSTL

By , 28/09/2010

J’ai souvent lu dans des forums et des blogs que la JSTL ne s’intègre pas du tout avec Facelets et qu’il faut absolument éviter d’utiliser les deux technologies ensemble. C’est faux à condition de bien connaître Facelets :

Cycle de vie d’une requêtes Facelets

Rappelons d’abord le cycle de vie d’une requête JSF. Lorsque l’utilisateur demande une page JSF, sa requête provoque coté serveur l’exécution suivante :

  1. Restore view
  2. Apply request values
  3. Process validation
  4. Update model value
  5. Invoque application
  6. Render request

Avec Facelets, il y a un cycle de vie en deux phases :

  1. Compile : création d’un “component tree” dans une “UIViewRoot”
  2. Run (exécution du cycle de vie JSF)

On peut remarquer que Facelets fonctionne de la même façon que les JSP (compilation de la JSP puis exécution de cette dernière). Pourquoi ces deux phases existent-elles ? Facelets est composé des TagHandlers (compile-time) et des ComponentHandlers (invocation JSF). Voici la liste triée de ces composants :

Pour information, voici deux bons article sur le sujet pour aller plus loin dans les détails : http://www.ilikespam.com/blog/c:foreach-vs-ui:repeat-in-facelets et http://www.znetdevelopment.com/blogs/tag/facelets/.

Tag de la JSTL

Facelets n’implémente que certaines fonctions de la JSTL  :

  • <c:if/>
  • <c:forEach/>
  • <c:catch/>
  • <c:set/> (utilisation déconseillée)

Les autres tag de la JSTL ne fonctionnent pas car ils ne sont pas implémentés. C’est l’occasion de remarquer qu’en utilisant les tags JSTL dans une application Facelets, on ne se base pas sur la version standard des composants mais sur une version re-développée par Facelets.

Il faut donc se méfier car certains tag ne fonctionnent pas exactement de le même façon. Par exemple, l’attribut varStatus du tag <c:forEach/> pointe sur l’instance d’un objet de type com.sun.facelets.tag.jstl.core.IterationStatus et non de type javax.servlet.jsp.jstl.core.LoopTagStatus comme décrit dans la documentation de la JSTL. Certaines méthodes ne sont pas implémentées. Dans ce cas il est donc préférable de se fier qu’a la documentation de référence de Facelets et non celle de la JSTL. Pour la javadoc, je ne l’ai trouvé qu’en téléchargements Facelets ici.

Pour information, visiblement, dans JSF2.0, Facelets utilise désormais la version standardisée de la JSTL.

Workaround sur l’utilisation de <c:set/>

Lorsque l’on commence à utiliser la JSTL on est vite tenté d’utiliser des variables dans les boucles <c:forEach/> d’où l’utilisation du tag déconseillé <c:set/>. Il est cependant possible de contourner le problème en utilisant une autre fonctionnalité de Facelets. En effet, il est possible d’utiliser le tag <ui:include/> avec des paramètres pour contourner l’utilisation de la fonctionnalité déconseillée de la JSTL. Sans compter que cela permet de découper les pages XHTML en petits fragments ce qui peut rentre le code plus facile à lire et à maintenir.

Utiliser les fonctions JSTL avec l’EL de JSF

By , 09/09/2010

La JSTL est très utile dans le développements des pages JSP et JSF. Elle permet d’avoir à disposition une multitude de fonctionnalités sans avoir à repasser par une classe Java (opérations sur les dates, les chaines de caractères, etc.) voici un lien vers la javadoc : http://download.oracle.com/docs/cd/E17802_01/products/products/jsp/jstl/1.1/docs/tlddocs/index.html. Pour utiliser ces fonctions dans une page JSF avec du JSP :

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<%@ page contentType="text/html" %>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<html>
     <h:outputText value="${fn:toLowerCase('CALIFORNIA')}"/>
</html>

Pour utiliser ces mêmes fonctions dans une page avec Facelets :

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:ui="http://java.sun.com/jsf/facelets"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:z="http://www.qualcomm.com/jsf/core"
      xmlns:c="http://java.sun.com/jstl/core"
      xmlns:fn="http://java.sun.com/jsp/jstl/functions">
          <h:outputText value="#{fn:toLowerCase('CALIFORNIA')}"/>
</html>

weblets

By , 02/07/2010

En travaillant sur une librairie JSF faite maison, j’ai rapidement souhaité packager des fichiers CSS et des images. Avec richFaces, il est possible de charger un fichier CSS se situant dans un JAR avec le composant <a4j:loadStyle />, mais je n’ai pas trouvé la même fonctionnalité pour récupérer une image packagée dans un JAR. C’est alors que j’ai découvert weblets :

Component libraries for web application frameworks often need to provide resource files along with implementation classes. For example, JavaServer Faces Renderers often need JavaScript, CSS and image resources.

Il s’agit donc d’un framework qui met à la disposition d’une application web les ressources contenues dans un JAR “tag-librairie”. Cette technologie est compatible avec JSF, JSP, JavaScript, CSS, etc. Elle est utilisable dans une application basée sur JSF ou sur des servlets.

La librairie

Il n’y a qu’une seule règle à suivre pour le packaging de la librairie : le fichier de configuration weblets-config.xml doit être dans le répertoire META-INF. Voici un exemple de fichier de configuration :

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd">
    <web-app>
      <description>Weblets Demo</description>

      <servlet>
        <servlet-name>Weblets Servlet</servlet-name>
        <servlet-class>net.java.dev.weblets.WebletsServlet</servlet-class>
      </servlet>

      <!-- The  Weblets servlet mapping must be path based otherwise  Weblets will fail! -->
      <servlet-mapping>
        <servlet-name>Weblets Servlet</servlet-name>
        <url-pattern>/weblets/*</url-pattern>
      </servlet-mapping>

    </web-app>

Ce fichier ressemble étrangement au fichier web.xml. Ici, toutes les ressources qui sont dans le package org.myapp.faces.renderer.html.resources seront disponibles à l’adresse http://…../root-webapp-context/faces/weblets/myressources/*. Le nom de la weblet est myweblet. Il peut y avoir plusieurs weblets dans un même fichier de configuration.

Je n’aime pas la paraphrase, vous trouverez toutes les explications utiles à cette adresse : https://weblets.dev.java.net/doc_11/longdoc/packingweblets.html

Mise en place sur une application web JSF

Dans une application JSF, la weblets se déploie automatiquement. Il n’y a que deux limitations :

  • Utiliser la servlet JSF de l’implémentation de référence :  javax.faces.webapp.FacesServlet
  • Utiliser le mapping de servlet JSF /faces/*

Voici un exemple de fichier web.xml :

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
  <description>Weblets Demo</description>

  <servlet>
    <servlet-name>Faces Servlet</servlet-name>
    <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
  </servlet>

  <servlet-mapping>
    <servlet-name>Faces Servlet</servlet-name>
    <url-pattern>/faces/*</url-pattern>
  </servlet-mapping>

</web-app>

Si vous utiliser Seam comme moi, votre mapping de servlet est certainement *.seam. Il faut s’avoir qu’il est possible de définir plusieurs mappings différents sans aucun problème. Pour plus d’explication je vous invite à visiter la documentation officielle : https://weblets.dev.java.net/doc_11/longdoc/setup.html

Utilisation dans l’application JSF

L’utilisation dans votre application JSF est très simple. Dans une page facelets :

#{weblet.url['weblets.demo']['/welcome.js']} <!– avec weblets.demo = le nom de la weblet et /welcome.js le chemin de la resource –>

Dans un fichier CSS :

background-image: url( weblet:resource( "weblets.demo" , "/myimage.png" ) );

Maven

Enfin, comme toute librairie qui se respecte, voici comment l’utiliser avec maven : Ajouter le repository java.net à votre pom.xml :

<repository>
 <id>maven2-repository.dev.java.net</id>
 <name>Java.net Repository for Maven</name>
 <url>http://download.java.net/maven/2/</url>
 <layout>default</layout>
 </repository>
<pre>

Ajouter les deux dépendances suivantes :

<dependency>
 <groupId>net.java.dev.weblets</groupId>
 <artifactId>weblets-api</artifactId>
 <version>1.1</version>
 </dependency>
 <dependency>
 <groupId>net.java.dev.weblets</groupId>
 <artifactId>weblets-impl</artifactId>
 <version>1.1</version>
 </dependency>

Pour terminer cet article, j’ajouterai que j’ai eu beaucoup de difficultés pour mettre en place ma librairie car la documentation n’est pas tout à fait correcte ou plutôt, elle induit en erreur le développeur de temps en temps. Il ne faut pas avoir peur de checkouter les sources pour s’inspirer des exemples, la racine du repository subversion est : https://weblets.dev.java.net/svn/weblets avec l’utilisateur guest sans mot de passe. Cela vous fera certainement gagner du temps.

org.myapp.faces.renderer.html.resources

Facelets et JSTL

By , 06/06/2010

Il est important de savoir que l’utilisation de Facelets est compatible avec l’utilisation de certaines fonctionnalités de la JSTL.

En lisant la documentation de Facelets, j’ai découvert que seulement cinq fonctions sont implémentées :

  • c:if
  • c:forEach
  • c:catch
  • c:set

J’ai aussi remarqué que leurs utilisations n’est pas toujours possible. Par exemple, il n’est pas possible de demander un c:if dans un ui:repeat. Dans ce cas, j’ai du remplacé le ui:repeat par un c:forEach pour que mon instruction conditionnelle soit prise en compte.

Ecrire un document XML avec Facelets

By , 05/06/2010

Générer un document XML à partir d’un application web Java est très simple. Il suffit d’écrire une servlet qui va écrire du XML sur la réponse HTTPResponse avec le bon type de contenu. Voici un exemple :

try {
 FacesContext ctx = FacesContext.getCurrentInstance();
 final HttpServletResponse resp = (HttpServletResponse)ctx.getExternalContext().getResponse();
 String xml = "<settings>...</settings>";
 resp.setContentType("text/xml");
 resp.setContentLength(xml.length());
 resp.getOutputStream().write(xml.getBytes());
 resp.getOutputStream().flush();
 resp.getOutputStream().close();
 ctx.responseComplete();

} catch (IOException e) {
 e.printStackTrace();
}

L’opération s’avère plus difficile lorsqu’il faut l’écrire à partir d’une page XHTML en utilisant Facelets. Voici une solution possible :

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<f:view xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core" contentType="text/xml">

<settings>...</settings>

</f:view>

La déclaration de la dtd HTML (deuxième et troisième lignes) n'est pas nécessaire sauf si vous utilisez des caractères latins ("é", "è", etc.) car facelets les traduit automatiquement en caractères HTML du style "&eacute;" et cela provoque l'erreur "Erreur d'analyse XML : entité non définie" sans ce fichier dtd.

OfficeFolders theme by Themocracy