Création d’une application de type CRUD avec JSF et JPA

Extrait du synopsis :

Cet article a pour objectif de vous présenter la tâche de création d’une application complète de type CRUD ( Create, Read, Update, Delete ) permettant d’effectuer les opérations de création, consultation, suppression et modification d’une entité et ce en utilisant le framework web JSF et le framework de persistance JPA .

L’article complet est par ici : Création d’une application de type CRUD avec JSF et JPA

JSF et Facelets

Extrait du synopsis :

Cet article a pour objectif de vous présenter la technologie de présentation Facelets ainsi que de vous guider dans les tâches de configuration et d’utilisation de cette technologie.

L’article complet est par ici : JSF et Facelets

Stratégie publicitaire agressive d’ICEfaces

ICEfaces, la boite derrière le jeu de composants JSF ICEfaces (innovant soit dit en passant) est en train de faire quelques mouvements agressifs ces derniers jours histoire de promouvoir leur produit mais aussi leur support commercial.

Dans mon cas, ça a commencé Lundi dernier (le 22) : j’ai reçu un mail de leur part comme quoi un compte en mon nom dans leur site a été crée … je me rappelle que j’avais crée un compte il y’a une année déjà pour pouvoir télécharger leur produit. ils ont utilisé la première partie de mon adresse email comme login et un mot de passe standard.

[Suite:]

Aujourd’hui, je viens de recevoir un second email comme quoi ils ont entendu que je travaillais sur un projet utilisant ICEfaces (wow ! moi même je le savais pas) et qu’ils voudraient me contacter (par téléphone) pour m’expliquer les avantages dont je disposerais si je m’abonne à leur programme de support commercial.

Je ne suis pas le seul, ça s’est sûr … et j’hésite sur comment je dois prendre cela :D je veux dire que c’est naturel qu’ils essaient de faire connaitre et adopter leurs produits … mais aussi agressivement ? me créer un compte à ma place ? Mais surtout (leur second mail) :

Hello Jawher,

I noticed that you are working on a project with ICEfaces

Edit:
En fait non, grâce à l’explication de lepack (un membre d’ICEfaces peut être ?), le fait qu’on m’ait automatiquement crée un compte dans le site d’ICEfaces est dû plutôt au fait que j’ai téléchargé la RefCard de JSF de Dzone. Or, dans la page de téléchargement, il est clairement signalé qu’en téléchargeant la chose, on serait automatiquement enrolé dans la communauté ICEfaces.

=> My bad ! J’aurais vraiment du lire plus attentivement les modalités ^^
Merci d’avoir répondu et de m’avoir rectifié !

—-

[Java] JSF 2.0 va inclure un ViewScope

Ryan Lubke a publié un (autre) billet sur son blog où il présente (encore) quelques nouveautés du futur JSF 2.0. Ce qui m’a vraiment intéressé cette fois-ci est l’introduction du view scope qui vient s’ajouter aux autrez scopes classiques (Session, Request, Application).

Basiquement, il s’agit d’un scope lié à une page, où une donnée qui y est stockée est gardé trant qu’on est sur une même vue, et est effacée dès qu’on navigue vers une autre vue.

[Suite:]

Ceux qui ont utilisé Tomahawk reconnaîtront le composant saveState qui présente une fonctionnalité simailaire.

L’introduction de ce nouveau scope est une excellente nouvelle car il serait vraiment utile (pensez aux listes alimentées depuis la base de données dans un managed bean par exemple, l’édition sur place, etc. ou on devait passer par le scope session (le marteau pour écraser la mouche)). Dommage que ça a pris 4 ou 5 ans à l’EG de JSF de s’en rendre compte :D

—-

Gestion des sessions expirées dans JSF (rebelote)

J’avais précédemment traité ce thème dans un autre billet, mais je dois avouer que la méthode que j’y avais présenté n’étatit pas vraiment solide ou fiable.

Donc, suite à quelques recherches et expérimentations, j’ai pu mettre en place un autre filtre beaucoup plus solide qui permet d’intercepter les erreurs de sessions expirées dans JSF (qui sont plus qu’abondants avec ce dernier :) ) pour afficher une page personnalisée au lieu de la mooche page d’erreur par défaut du serveur utilisé.

[Suite:]

En gros, voici une version simplifiée du filtre :

import java.io.IOException; 
 
 
 
import javax.servlet.Filter; 
 
import javax.servlet.FilterChain; 
 
import javax.servlet.FilterConfig; 
 
import javax.servlet.ServletException; 
 
import javax.servlet.ServletRequest; 
 
import javax.servlet.ServletResponse; 
 
import javax.servlet.http.HttpServletRequest; 
 
import javax.servlet.http.HttpServletResponse; 
 
 
 
import org.slf4j.Logger; 
 
import org.slf4j.LoggerFactory; 
 
public class TimeoutFilter implements Filter { 
  private static final Logger log = LoggerFactory 
      .getLogger("webapp.timeoutFilter"); 
 
  private static final String TIMOUT_PAGE = "timeout.html"; 
  private static final String LOGIN_PAGE = "login.faces";  
 
  public void init(FilterConfig filterConfig) throws ServletException { 
  } 
 
  public void doFilter(ServletRequest request, ServletResponse response, 
      FilterChain filterChain) throws IOException, ServletException { 
    if ((request instanceof HttpServletRequest) 
        && (response instanceof HttpServletResponse)) { 
      HttpServletRequest hRequest = (HttpServletRequest) request; 
      HttpServletResponse hResponse = (HttpServletResponse) response; 
 
      if (checkResource(hRequest)) { 
        String requestPath = hRequest.getRequestURI(); 
        if (checkSession(hRequest)) { 
            String timeoutUrl = hRequest.getContextPath() + "/" 
                + TIMOUT_PAGE; 
            log.info("Session is invalid! redirecting to timeoutpage : {}", 
                    TIMOUT_PAGE); 
 
            hResponse.sendRedirect(timeoutUrl); 
            return; 
        } 
 
 
    } 
    filterChain.doFilter(request, response); 
  } 
 
  private boolean checkResource(HttpServletRequest request) { 
    String requestPath = request.getRequestURI(); 
    log.debug("reqPath={}", requestPath); 
    return !(requestPath.contains(TIMOUT_PAGE) ||  
        requestPath.contains(LOGIN_PAGE) ||  
      requestPath.equals(hRequest.getContextPath() + "/")); 
 
  } 
 
  private boolean checkSession(HttpServletRequest request) { 
    return request.getRequestedSessionId() != null 
        && !request.isRequestedSessionIdValid(); 
 
  } 
 
  public void destroy() { 
  } 
 
} 

Quelques notes:

  • J’utilise SLF4J pour le logging
  • Je commence par vérifier s’il s’agit bien d’une requête HTTP
  • Si c’est le cas, je vérifies si la ressource demandée (request.getRequestURI()) est une ressource protégée via la méthode checkResource(). En fait, c’est à vous de décider quelle ressource protéger. Dans cet exemple, je suppose que toute page exceptée celle du timeout, du login et la racine est protégée.
  • Je vérifies ensuite l’état de la session en contrôlant que l’identifiant (jsessionid) est non null, et qu’il est valide
  • Si c’est pas bon, alors je redérige vers la page de timeout (via request.sendRedirect)

Toutefois, cette implémentation n’est pas encore parfaite, car il peut arriver des cas où la session est valide sans que l’utilisateur ne soit authentifié.

Pour résoudre ceci, j’ajoute un autre test (après le premier) qui récupère un bean session (un managed bean JSF en fait, mais managé par Spring) pour vérifier qu’il n’est pas null et qu’un champ particulier est renseigné :

if (hRequest.getSession(false) != null) { 
 
  final WebApplicationContext ac = WebApplicationContextUtils 
 
    .getWebApplicationContext(hRequest.getSession(false).getServletContext()); 
 
  if (ac == null) { 
 
    //redériger vers la page du timeout ... 
 
  } else { 
 
    LoginCtrl loginCtrl = (LoginCtrl) ac.getBean("loginCtrl"); 
 
    if (loginCtrl == null || !loginCtrl.isLoggedIn()) { 
 
    if (!(requestPath.contains(LOGIN_PAGE) || requestPath 
 
      .equals(hRequest.getContextPath() + "/"))) { 
 
      //redériger vers la page du timeout ...        
 
    } 
 
  } 
}

Il faut juste bien vérifer de passer false à getSession : ça m’a fait perdre quelques millions de neuronnes pour comprendre ce qui se passait car j’avais ajouté cette innoncente instruction :

 
log.debug(hRequest.getSession(true); 

erf …

Après, il est possible de peaufiner encore la chose, en ajoutant par exemple un test qui emêche un utilisateur déjà connecté de se reconnecter, i.e. d’accèder à la page de login, chose indispensable quand on bosse avec Spring par exemple, où une manipulation pareille ne recharche pas les beans en scope session …

—-

Sortie de Mojarra (JSF RI) 2.0 EDR

La première implémentation de référence du futur JSF 2.0 (Mojarra) vient de sortir en version EDR (Early Dravt Review).
Pour rappel, j’avais parlé de quelques nouveautés du futur JSF 2.0 dans ce billet.

[Suite:]

=> Annonce
=> Télécharger
=> Release Notes

Notez qu’Ed Burns (le spec Lead de JSF 2.0) a réalisé dans son blog un index de ressources parlant de JSF 2.0.
=> C’est par ici.

—-

[Java] Mojarra: Groovy pour PHPiéser le

Ryan Lubke vient d’annoncer dans son blog qu’à partir de cette nuit, les nightly build de la prochaine version de Mojarra (== Sun JSF RI) 1.2_09 inclueront une nouveauté de taille: un mode développement configurable dans web.xml via un context-param (comme celui de Wicket par exemple) qui permet d’utiliser Groovy pour ecrire les managed beans mais surtout de développer une application JSF en mode PHP-like, i.e. modifier ses classes/pages, et faire un F5 dans le navigateur pour voir le résultat … A dieu le malfamé et lourd cycle de développement inhérent à Java EE (redéploiement à chaque modification, voir même redémarrage du serveur)

[Suite:]

Pour ceux qui se plaigneront du fait qu’ils ne connaissent pas la sntaxe de groovy, la réponse est simple: il suffit d’ecrire en Java, ce qui est déjà du Groovy. D’ailleurs, il vaut mieux écrire son code Groovy en Java natif vu qu’à la fin du prototypage, et pour des performances optimales, il faudrait désactiver le mode développement et recoder les classes Groovy en Java.
=> Vous voyez où je veux parvenir: en y allant avec du Java natif, ceci reviendrait à un simple copier/coller ;)

Presque tout serait rechargeable à chaud, des managed beans jusqu’au renderers et listeners, en passant par les validators/converters et même les composants.

Autre point: il est fortement conseillé d’utiliser FAcelets comme technologie de présentation (y’en a déjà qui font du JSF avec JSP ???), car il n’y a pas de rechargement à chaud pour les TagHandlers du JSP ou encore des TLDs.

La mise en place de ceci se présente comme suit:

  1. Inclure groovy-1.5.5-all.jar dans son classpath
  2. Ajouter ceci à son web.xml:

    <context-param> 
        <param-name>com.sun.faces.developmentMode</param-name> 
        <param-value>true</param-value> 
    </context-param> 
    <filter> 
        <filter-name>GroovyFilter</filter-name> 
        <filter-class>com.sun.faces.scripting.GroovySupportFilter</filter-class> 
    </filter> 
    <filter-mapping> 
         <filter-name>GroovyFilter</filter-name> 
         <url-pattern>/*</url-pattern> 
         <dispatcher>REQUEST</dispatcher> 
         <dispatcher>FORWARD</dispatcher> 
         <dispatcher>INCLUDE</dispatcher> 
         <dispatcher>ERROR</dispatcher> 
    </filter-mapping>

    (En gros, un context-param et un filtre + son mapping)

  3. Créer un répertoire “groovy” dans WEB-INF dans lequel placer les fichiers .groovy.

Notez que lorsqu’on référence les beans Groovy dans faces-config, il faut ajouter l’extension .groovy au nom qualifié.

Notez enfin qu’il s’agit encore d’une fonctionnalité encore à son inception, et que c’est loin d’être solide/fiable.

—-

Sortie de Richfaces 3.2

La nouvelle version de JBoss Richfaces 3.2 est sortie apportant plus de 900 bugs corrigés ainsi que de nouvelles fonctionnalités (le tri/filtrage sur dataTable, l’EL côté client, colonnes dynamiques) et de nouveaux composants (composant d’upload de fichiers, des composants d’edition in-place, etc.)

=> Annonce
=> What is New
=> Live Demo

—-

JSF : the good, the bad and the ugly …

Bonjour,
Après avoir travaillé sur 3 applications JSF (faisant partie du même projet) ces 5 derniers mois, et maintenant que c’est fini (enfin, presque …), j’aimerais parler du the good, the bad and the ugly, bref, une sorte de retour d’expérience sur l’utilisation de JSF.

[Suite:]

Je vais commencer par the good.

  • Les managed beans: là, c’est le bonheur. Du java pur et dur, on est libre de s’exprimer comme on veut (héritage/composition/délégation, etc.). Ajoutez Spring dans l’equation et on est proches de l’orgasme cérébral !
    Enfin, avec quelques limitations bien sûr (signature des actions, etc.).
  • Richfaces/Ajax4jsf: J’en ai parlé à maintes reprises dans le forum, mais je tiens à en reparler ici: Impossible AMHA de battre Ajax4jsf comme moyen de faire de l’ajax via une taglib. J’ai bien dit pour une taglib car j’ai vu comment on procède avec Wicket, et c’est beaucoup plus puissant, mais c’est normal car on passe par Java.
  • L’approche composants: je ne suis pas spécialement doué en HTML/CSS, et n’o n’avait pas une personne pareille dans l’équipe. C’est pour cela que j’ai énormément apprécié le fait qu’avec quelques lignes XML pour décrire le composant dans la page JSF, j’obtiens à l’exécution des trucs à couper le souffle côté visuel (Merci Richfaces)

Trois points seulement … mais c’est déjà ça :)

Mais je pense que vous êtes nombreux à attendre l’autre partie plutôt, the bad and the ugly ;)

  • Tooling: là, c’est un véritable cauchemar. On est sous eclipse europa, qui offre quelques fonctionnalités d’un IDE JSF, mais il en est encore loin … très loin. En fait, ça a tourné au vinaigre dès qu’on ne fait plus du JSF de base (sans jeux de composants additionnels ni facelets ni Spring).
    Mais dès qu’on essaies de faire quelque chose de puissant, eclipse nous a complètement laché.
    Il perd complètement les boules avec facelets, ce qui est tout simplement choquant, vu qu’aucun développeur JSF sérieux n’oserait faire sans facelets.
    D’ailleurs, eclipse s’est amélioré au fils des versions de maintenance (3.3.1.1 et 3.3.2), dans le sens où il accepte par exemple les pages xhtml dans l’editeur des règles de navigation, chose qu’il refusait avant, où qu’il offre l’auto-completion sur les jeux de composants standards (core et html) dans une page xhtml, mais il refuse de fonctionner pour facelets et tout autre jeu de composants.
    Exit l’aspect IDE et nous revoilà à l’époque de notepad, où on est censé taper des pages de quelques dizaines de lignes d’XML sans se tromper dans le nom d’un composant où d’un attribut.

    De plus, mais là c’est vivable, si on fait gérer ses managed beans par Spring, eclipse ne peut plus faire de l’auto-completion sur les ELs. D’ailleurs, il ne le fait plus du moment qu’on est dans une page xhtml et non pas JSP.

  • Ca figure dans la liste des bonnes chose, mais également ici: le fait qu’on bosse sur les composants et que ça génère du HTML. J’en ai vu des vertes et des pas mûres à cause de cela, et le pire que tu ne peux rien y faire: des liens qui ne marchent pas, générant des erreurs JavaScript, des inputs qui ne sont pas envoyés lors d’un submit, des composant qui violent leur contrat, notamment les valueChangeListeners sur les inputText, etc.
    On se retrouvait alors obligés à faire de l’acrobatie en essayant de contourner ces problèmes avec des solutions plus sordides l’une que l’autre.
  • Je sais que ça devrait être résolu dans JSF 2.0, ou encore déjà avec Seam et RestFaces, mais l’aspect fortement stateful de JSF peut vraiment devenir ennuyant, surtout si l’application est destinés à un utilisateur non forcément informaticien. Vas lui expliquer qu’il vaut mieux éviter le bouton retour du navigateur ou les F5 :) ou encore qu’il doit suivre une séquence particulière dans les pages pour arriver au résultat, et qu’il ne peut pas bookmarker des pages, etc.
  • Les maudits erreurs de “View has Expired”, et la gestion des erreurs en général qui est, et c’est un doux euphémisme, exécrable.
  • Facelets: je l’ai déjà dit à maintes occasions: JSF sans Facelets c’est comme les oeufs avant la maîtrise du feu, mais la gestion/rapport d’erreurs de facelets est parfois cryptique et n’aide aucunement à leur localisation/correction.
    Par exemle, si dans un include on se trompe du nom du fichier à inclure, on obtient un beau 404 quand on essaie d’accèder à la page mère au lieu d’un message indiquant clairement l’origine de l’erreur… ainsi que dans d’autre cas où on obtenait des messages d’erreur cryptés sur 128 bits sans même le numéro de la ligne en cause.
  • Difficile de faire quoi que soit d’utile avec le scope request. On se retrouve obligé de passer au scope session.
  • Bouffeur de CPU: J’en parle dans ce billet.
  • Mais le point noir à mon avis est la difficulté sordide de la tache de développement de composants personnels … C’est vrai que facelets essaies de simplifier ça, mais ça permet pas de développer de véritables composants personnels.

Impressionnant cette liste, non ? En relisant ce billet, je sens que c’est injuste pour JSF, car on a tout de même fait pas mal de trucs puissants avec, et ce en un temps record, ce qui est ne serait pas forcément la conclusion tirée par quelqu’un lisant ce billet :(

Pour résumer et rectifier un peu le tir, je dirais qu’avec JSF, on est pas loin de la règle de 80/20, mais que je transformerais en 80/60 au risque de casser sa beauté :)

  • On fait 80% du boulot en 60% du temps attribué
  • Et on se retrouve à combattre les 20% restantes du boulant dans le 40% du temps restant

Enfin, pour conclure, je ne suis aucunement en train de lancer une croisade contre JSF, loin de là même: JSF est toujours une option valable à envisager pour un nouveau projet. Seulement, comme tuotes les autres technos, JSF a ses défauts et un prix à payer.

—-

Comment gérer le Timeout de la session avec JSF

Dans l’application sur laquelle je travaille, j’ai eu un ennuyeux problème avec le Session Timeout, surtout avec IE 6 (tiens, c’est bizarre ça ;))
Bref, j’ai pas trouvé grand chose en googlant la chose, alors j’ai du concocter ma propre solution fait maison que voici:

[Suite:]

Je passe par un filtre mappé avec la Faces Servlet dont voici le code:

public class TimeoutFilter implements Filter { 
  private static final Logger log = Logger.getLogger(TimeoutFilter.class); 
 
  public void init(FilterConfig conf) throws ServletException {} 
  public void destroy() {} 
 
  public void doFilter(ServletRequest request, ServletResponse response, 
      FilterChain chain) throws IOException, ServletException { 
    HttpServletRequest r = ((HttpServletRequest) request); 
    if (r.getSession(false) == null) { 
      r.getSession(); 
      ((HttpServletResponse) response).sendRedirect(r.getContextPath()+"/timeout.html"); 
    } else { 
      chain.doFilter(request, response); 
    } 
  } 
}

En gros, voici ce qu fait ce filtre:

  1. Je castes le paramètre request en HttpServletRequest.
  2. Je récupère la session en cours sans pour autant la créer si elle n’existe pas (d’ou le false passé à getSession)
  3. Si pas de session, alors j’en crée une nouvelle et je redirige vers une page html qui affiche “Session expirée, reconnectez vous, bla bla bla”.
  4. Sinon, je ne fais rien, je passe la main aux autres filtres de la chaîne.

Il faut ensuite déclarer ce filtre dans web.xml et l’associer à la Faces Servlet:

<filter> 
  <display-name>Timeout Filter</display-name> 
  <filter-name>timeout</filter-name> 
  <filter-class>TimeoutFilter</filter-class> 
</filter> 
<filter-mapping> 
  <filter-name>timeout</filter-name> 
  <servlet-name>Faces Servlet</servlet-name> 
</filter-mapping>

Et voilou, le tour est joué: plus d’écran moche d’exception de Tomcat lors du timeout.

—-