Posts tagged: JSF

Seam : Exporter une dataTable à l’interieure d’une subview

By , 30/09/2010

Lorsqu’un développeur utilise Seam, il a à sa disposition tout un panel de composant pour l’aider à développer. Par exemple le composant dataTable Exporter permet d’exporter un tableau JSF (h:dataTable, rih:dataTable, etc.) sous la forme d’un fichier Excel. Voici la syntaxe directement récupérée de la documentation de référence de Seam :

<h:form id="theForm">
    <h:dataTable id="theDataTable" value="#{personList.personList}"
        var="person">
         ...
    </h:dataTable>
</h:form>
...
<h:commandLink
    value="Export"
    action="#{excelExporter.export('theForm:theDataTable')}" />

Lorsque la table se trouve dans une sous vue (<f:subview/>) ou tout autre composant qui joue un rôle de conteneur de nom (NamingContainer), il faut que le paramètre de la méthode d’export soit sous la forme idNamingContainer1:idNamingContainer2:…:…:idDataTable. De cette manière, la table est identifiée de façon unique dans la RootView.

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.

Fiji 2.0 : Intégration de Flex avec JSF

By , 17/09/2010

Le framework fiji de Exadel a fait l’actualité en septembre 2008 car il permettait d’intégrer des composants Flex au framework Java JSF. La vitrine de composant graphique basée sur Amchart était très bien faite. C’est sur ce point que je trouvais Fiji prometteur. Après l’avoir essayé, j’étais assez déçu car fiji n’est pas déployé sur les repositories Maven, la release publiée se base sur des versions SNAPSHOT, elle dépend de Richfaces, etc. De plus depuis fin 2008, j’ai eu l’impression que le projet était abandonné car il n’y eu jamais d’autre release.

Par hasard, je suis tombé sur cet article du blog de Max Katz, il y a quelques jours. On peut y apprendre qu’il travaille sur une version 2.0 open source du fameux framework. A priori la publication de la version est proche. J’espère rédiger un petit tutoriel basé sur une application J2EE6 intégrant des graphiques Amchart lors de la publication.

Comment utiliser le timezone du compensant JSF convertDateTime

By , 10/09/2010

Par défaut, JSF utilise le timezone GMT dans le composant convertDateTime. C’est problématique lorsqu’un développeur veut afficher des dates qui ne sont pas formatées en GMT. Pour une application en France cela occasionne un décalage d’un jour dans le passé. En recherchant une solution sur google j’ai trouvée des personnes qui créent leur propre convertisseur. En fait, il est en fait plus facile d’utiliser l’attribut timezone du composent.

L’attribue timezone attend directement une chaine de caractère et non un objet de type java.util.TimeZone comme je le pensais au début. Par exemple, voici comment mettre le timezone sur Paris :


<h:outputText value="#{commande.date}">
   <f:convertDateTime pattern="dd/MM/yyyy" timeZone="Europe/Paris" />
 </h:outputText>

Problème d’export Excel avec le Datatable exporter de Seam

By , 09/09/2010

Seam permet d’exporter très simplement des dataTable JSF en CSV ou en Excel. Pour cela il suffit de déclarer une dataTable et un lien qui fait référence au bon composant Seam :


<h:form id="theForm">
      <h:dataTable id="theDataTable" value="#{personList.personList}"
            var="person">
                  ...
      </h:dataTable>
</h:form>

...

<h:commandLink
      value="Export"
      action="#{excelExporter.export('theForm:theDataTable')}"
      />

Cette fonctionnalité est très pratique mais lorsqu’il y a un problème il est parfois très compliqué de trouver l’erreur. J’ai ainsi découvert par hasard que les colonnes doivent être composées de composants JSF et non de chaines de caractères simples pour apparaître dans l’export. Dans l’exemple suivant, seule la première colonne apparaîtra dans l’export :


<h:form id="theForm">
      <rich:dataTable id="theDataTable" value="#{personList.personList}"
                  var="person">
            <rich:column>
                  <f:facet name="header"><h:outputText value="Name"/></f:facet>
                  <h:outputText value="#{person.name}" />
            </rich:column>
            <rich:column>
                  <f:facet name="header"><h:outputText value="Age"/></f:facet>
                  #{person.age}
            </rich:column>
      </rich:dataTable>
</h:form>

Pour information, ce comportement est aussi valable pour le facet header. Ce comportement est enregistré en tant que “nouvelle fonctionnalité” dans le JIRA de Seam : https://jira.jboss.org/browse/JBSEAM-3213

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