JSF + Tiles, complément

J'avais déjà parlé de coupler les avantages de JSF et Tiles, je reviens aujourd'hui rajouter un petit complément.

J'avais en effet parlé d'un inconvénient majeur, l'impossibilité de lier directement le rendu d'une page à une définition de Tiles.

J'ai découvert aujourd'hui, en lisant le tutoriel sur le site Tiles, que l'API de Tiles fournissait une Servlet qui liait les URL de type *.tiles vers les définitions correspondantes. Par exemple, grâce à cette Servlet, il est par exemple possible d'accéder à une définition nommée index via l'URL /index.tiles.

Après quelques tests, il est possible de coupler cette Servlet avec JSF.

Première étape : Déclarer la Servlet de Tiles

Dans web.xml :
<servlet>
    <servlet-name>Tiles Dispatch Servlet</servlet-name>
    <servlet-class>org.apache.tiles.web.util.TilesDispatchServlet</servlet-class>
</servlet>
...
<servlet-mapping>
    <servlet-name>Tiles Dispatch Servlet</servlet-name>
    <url-pattern>*.tiles</url-pattern>
</servlet-mapping>

Ainsi, toutes les URL *.tiles seront liées aux définitions correspondantes.

Deuxième étape : Configurer JSF pour utiliser les URL *.tiles

La seconde étape va consister à modifier légèrement le comportement de JSF. Par défaut, pour générer la réponse d'une requête index.jsf, le framework va chercher la page index.jsp. Nous allons maintenant lui dire d'aller chercher index.tiles à la place. Requête à laquelle Tiles répondra en introduisant une définition (la définition nommée index dans notre cas).

Il faut pour cela modifier une propriété propre à JSF :
<context-param>
    <param-name>javax.faces.DEFAULT_SUFFIX</param-name>
    <param-value>.tiles</param-value>
</context-param>


Et voilà. Il ne reste plus qu'à essayer d'accéder à index.jsf. Le FacesContext est chargé, puis la main est passée à Tiles pour le rendu. Il suffit de déclarer nos JSP et nos définitions comme je l'ai précisé dans la première version.

Permalink  |  Commentaires (0)

JPA : Utilisation en dehors du module EJB

Récemment, j'ai eu à utiliser JPA pour un site Web. Pour plus de simplicité, je me suis tourné vers un conteneur EJB. Seulement, j'ai eu aussi besoin de créer une multitude de Stateful / Stateless Session Beans, alors que je n'avais vraiment pas besoin de ça. Une application Web toute simple me suffisait largement dans ce cas là.

J'ai alors entrepris de convertir mon application d'entreprise en application Web. Seulement, un problème est apparu assez rapidement : la gestion des transactions de JPA ! En effet, les transactions dont JPA à besoin étaient jusqu'à lors gérées par le conteneur EJB. QUe je n'utilisais plus maintenant.

Je vais donc entreprendre dans cet article un rapide "howto" de l'utilisation de JPA en dehors du module EJB.

1. Mise en place des entités

La première partie est commune à nos deux modes de fonctionnement. Il s'agit de créer nos entités JPA et de créer notre unité de persistance.

On commence avec une entité :
package com.aperigeek.jpa.entity;

@Entity
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    private String name;

    // Getters and setters

}

Puis, on passe à la création de notre unité de persistance (dans notre fichier persistence.xml) :
<persistence version="1.0" 
    xmlns="http://java.sun.com/xml/ns/persistence" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence 
        http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
  <persistence-unit name="AperigeekPU" transaction-type="RESOURCE_LOCAL">
    <provider>oracle.toplink.essentials.PersistenceProvider</provider>
    <non-jta-data-source>jdbc/aperigeek</non-jta-data-source>
    <class>com.aperigeek.jpa.entity.User</class>
    <exclude-unlisted-classes>true</exclude-unlisted-classes>
    <properties>
      <property name="toplink.ddl-generation" value="create-tables"/>
    </properties>
  </persistence-unit>
</persistence>

La différence par rapport à une unité de persistance gérée par le conteneur EJB est que nous n'allons par utiliser JTA pour la gestion des transactions. Les changements sont :
  • Le transaction-type de notre unité de persistance devient "RESOURCE_LOCAL", pour indiquer que nous allons gérer nous même nos transactions.
  • La DataSource est déclarée grâce aux balises <non-jta-data-source />,. Les DataSources que nous allons utiliser ne seront pas gérées par JTA.


À noter que j'utilise dans cet exemple Toplink (le gestionnaire de persistence par défaut de GlassFish). Les valeurs de la balise <provider> et de la propriété toplink.ddl-generation sont donc spécifique à Toplink.

2. Récupération d'un EntityManager

Étant donné que nous ne sommes plus dans un contexte géré par le conteneur, nous allons devoir récupérer nos EntityManagers à la main. Le code pour récupérer un EntityManager est assez simple. Il suffit de passer par un EntityManagerFactory, qui nous est fourni directement par une méthode statique de la classe Persistence.

EntityManagerFactory emf = Persistence.createEntityManagerFactory("AperigeekPU");
EntityManager em = emf.createEntityManager();

Autre étape très importante : tous les EntityManagerFactory et EntityManager doivent être fermés ! Cette étape de fermeture des ressources est d'habitude laissée au conteneur. Dans notre cas, nous allons devoir le faire nous même :
em.close();
emf.close();

Inconvénient propre à cette technique : une fois tous les EntityManagerFactory et EntityManager fermés, le gestionnaire de persistance s'arrête, pour redémarrer à la prochaine création d'un EntityManagerFactory. Je suis donc parti dans la création d'une Servlet, qui aura pour mission de créer un EntityManager au démarrage de l'application, et de le libérer à l'arrêt de l'application.

3. Servlet de chargement, et classe PersistenceManager

Avant de créer une Servlet, j'ai d'abord créé une classe, PersistenceManager, chargée de créer des EntityManagerFactory et EntityManager, et de les fermer ensuite.

Le code de cette classe est assez simple :
public class PersistenceManager {
    
    private static EntityManagerFactory emf;
    
    private static EntityManager em;
    
    public static EntityManager getEntityManager() {
        return (em);
    }
    
    public static void loadEntityManager() {
        emf = Persistence.createEntityManagerFactory("AperigeekPU");
        em = emf.createEntityManager();
    }
    
    public static void releaseEntityManager() {
        em.close();
        emf.close();
    }

}

Nous allons maintenant créer une Serlvet, qui devra appeler les méthodes PersistenceManager.loadEntityManager() au chargement de l'application et PersistenceManager.releaseEntityManager() au déchargement :
public class PersistenceLoaderServlet extends GenericServlet {

    @Override
    public void service(ServletRequest arg0, ServletResponse arg1) throws ServletException, IOException {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public void init() throws ServletException {
        PersistenceManager.loadEntityManager();
    }

    @Override
    public void destroy() {
        PersistenceManager.releaseEntityManager();
    }

}

Suivie d'une déclaration très simple dans web.xml :
<servlet>
    <servlet-name>PersistenceLoaderServlet</servlet-name>
    <servlet-class>com.aperigeek.jpa.servlet.PersistenceLoaderServlet</servlet-class>
    <load-on-startup>2</load-on-startup>
</servlet>

Deux choses sont notables :
  • L'attribut load-on-startup est à 2, pour permettre à la Servlet d'être chargée au déploiement de l'application.
  • Il n'y a aucun mapping pour cette Servlet. Elle n'est en effet pas vouée à être appelée pour répondre à une requête. C'est pour cette même raison que la méthode service() de notre servlet lève une exception.

4. Utilisation de notre EntityManager

Et enfin, dernière étape, utilisation de notre EntityManager. Nous allons devoir :
  • Récupérer nos EntityManagers à la main. N'étant plus gérés par le conteneur, nous n'allons pas pouvoir les injecter en tant que dépendance dans nos beans.
  • Gérer les transactions. Pour la même raison que ci-dessus, les transactions devront être gérées à la main.

Un rapide exemple, pour stocket un User en base de données :
public void addUser(User user) {
    EntityManager em = PersistenceManager.getEntityManager();
    em.getTransaction().begin();
    em.persist(user);
    em.getTransaction().commit();
}

On récupère ici nos EntityManagers grâce à la méthode PersistenceManager.getEntityManager(). Ensuite, avant chaque opération en base de données, nous devons démarrer une transaction (em.getTransaction().begin();), puis commiter les modifications (em.getTransaction().commit();).


Voilà rapidement les étapes à suivre pour utiliser JPA dans un contexte non-géré par le conteneur. Les même étapes peuvent être suivies pour utiliser JPA dans une application Java SE, en modifiant la Servlet par un autre mécanisme permettant de charger notre EntityManager au lancement et de le libérer à la fermeture de l'application.

Permalink  |  Commentaires (0)

Glassfish et NetBeans : Présent et futur

Nous sommes dans une période de sortie ! Hier, NetBeans 6.1 pointait le bout de son nez. Aujourd'hui, c'est GlassFish v2ur2 qui fait son entrée. Période idéale pour faire un point sur ces deux nouvelles versions, puis pour regarder un peu en avant afin de voir ce que l'avenir nous réserve...

NetBeans

La version 6.1 apporte son lot de fonctionnalités. J'en avais déjà parlé, les améliorations sont au rendez vous.

Parmi toutes les nouvelles fonctionnalités, mes préférées :
  • Amélioration des performances
    • Démarrage (beaucoup) plus rapide
    • Consomme moins de mémoire
    • Beaucoup plus réactif
  • Support de MySQL
    • Administration de serveur MySQL intégré
  • Partage de projets
    • Les librairies sont directement inclues dans votre projet
    • Les chemins pour accéder aux librairies sont relatifs

La liste complète est disponible sur le site de NetBeans.

Quelques nouvelles fonctionnalités qui viendront après la version 6.1 sont déjà prévues :
  • Support de PHP
    • Auto-complétion, coloration syntaxique, ...
    • Débuggeur de JavaScript
  • Amélioration de l'éditeur SQL
    • L'éditeur SQL devrait fonctionner main dans la main avec l'éditeur PHP
    • L'auto-complétion de requêtes SQL devrait apparaître
  • Amélioration des performances (encore)

GlassFish

La version 2ur2 n'est qu'une mise à jour de maintenance. Les nouveautés ne sont donc pas très nombreuses.

Cependant, GlassFish 3 se prépare, et nous réserve d'ores et déjà de belles surprises.

La première amélioration, et pas des moindres, GlassFish v3 sera beaucoup plus rapide à lancer. Les premiers tests tendent vers un temps démarrage du serveur d'application inférieur à une seconde. Comme quoi beaucoup de progrès ont été faits.

De plus, GlassFish devrait être embarquable dans n'importe quelle autre application Java. Un petit exemple de ce qui pourrait être fait grâce à GlassFish v3 (via Bistro !) :
GlassFish glassfish = new GlassFish();
glassfish.minimallyConfigure(8080);

GFApplication app = glassfish.deploy(new File("mon_appli.war"));

// ...

app.undeploy();
glassfish.stop(); 

Une fonctionnalité assez pratique. Tomcat était déjà assez souvent utilisé en tant que conteneur de Servlet embarqué. C'est maintenant tout un serveur d'application qui pourra être embarqué dans une application.

Pour résumer, les futures version de NetBeans et de GlassFish tendent toutes les deux vers une amélioration des performances, mais réservent elles aussi leur lot de surprises.

Permalink  |  Commentaires (0)

JSF + Tiles

Combiner JSF et Tiles, c'est possible !

Voici comment j'ai réussi à mixer les deux :

1. Télécharger Tiles

La page de téléchargement est ici. J'ai utilisé la 2.0.5.

Une fois l'archive téléchargée et extraite, il faut récupérer les fichiers JAR de l'archive (situés à la racine et dans /lib, et les copier dans votre projet.

Ayant créé mon projet sous Glassfish, les librairies de JSF sont directement inclues dans le serveur d'application.

2. Configurer Tiles

La configuration de Tiles se passe en deux étapes. Une première étape consiste à déclarer une Servlet qui sera chargée au démarrage. La seconde étape consistera à déclarer un écouteur. Tout ça dans notre application Web.

Première chose, déclarer la Servlet de Tiles. Dans notre fichier web.xml :
<servlet>
    <servlet-name>TilesServet</servlet-name>
    <servlet-class>org.apache.tiles.web.startup.TilesServlet</servlet-class>
    <init-param>
        <param-name>org.apache.tiles.impl.BasicTilesContainer.DEFINITIONS_CONFIG</param-name>
        <param-value>/WEB-INF/tiles-defs.xml</param-value>
    </init-param>
    <load-on-startup>2</load-on-startup>
</servlet>

Ensuite, l'écouteur (toujours dans web.xml) :
<listener>
    <listener-class>org.apache.tiles.web.startup.TilesListener</listener-class>
</listener>

3. Utiliser Tiles !

Dernière étape : tester l'installation !

On déclare une définition dans notre fichier /WEB-INF/tiles-defs.xml :
<definition name="test" template="/WEB-INF/pages/test.jsp">
</definition>

On crée ensuite le template correspondant à notre définition. S'agissant d'une simple page de test, j'ai fait plutôt simple :
<%@taglib uri="http://java.sun.com/jsf/html" prefix="h" %>

<h2><h:outputText value="Tiles works !" /></h2>

Il ne reste plus qu'à inclure nos définitions dans nos pages JSF :
<%@page contentType="text/html" pageEncoding="UTF-8" %>

<%@taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
<%@taglib uri="http://tiles.apache.org/tags-tiles" prefix="tiles" %>

<f:view>
    <f:subview id="test">
        <tiles:insertDefinition name="test" flush="false" />
    </f:subview>
</f:view>

4. Inconvénients et astuces

Tiles est un framework très bien intégré à Struts. Il est possible, en utilisant Struts, de lier directement le rendu d'une action vers une définition Tiles.

Cela n'est malheureusement pas possible en JSF.

Une petite astuce permet cependant de passer à coté de cet inconvénient. Il s'agit de créer une JSP visible (en dehors de /WEB-INF) qui inclue directement la définition à utiliser. Au lieu de créer un lien vers une définition, il faudra alors créer un lien vers la JSP qui inclue cette définition.

Permalink  |  Commentaires (0)

Installer ICEfaces pour les nuls

C'est bien joli de faire des beaux billets de blog, mais t'aurais pu commencer par "Installer ICEfaces pour les nuls" :D
Martin

Et me voilà encore lancé dans un billet sur ICEfaces. Au programme aujourd'hui, l'installation de cette magnifique librairie.

Étape 1 : Création d'un projet Web sous NetBeans

On commence par créer un projet :
  • Nouveau projet
  • Projet Web
  • Web application
  • On lui donne on nom (ICEcalendar de mon coté)
  • Un emplacement (/home/viv/Desktop de mon coté [j'aime bien remplir mon bureau])
  • On lui donne un serveur d'application pour se déployer (GlassFish v2ur1 de mon coté)
  • On choisit les frameworks : JSF
  • Et on clique sur "Finish"

Étape 2 : Ajout des librairies

Pour commencer, il va falloir télécharger la librarie sur le site de ICEfaces (attention, inscription obligatoire).

Une fois l'archive ICEfaces-1.7.0-bin.zip téléchargée, nous allons récupérer les archives JAR de ICEfaces et les inclure dans notre projet. Nous allons donc extraire l'archive et copier tous les .jar situés dans /icefaces/lib vers notre projet NetBeans. Pour ce faire : Dans le projet, sur "Librairies" : Clic droit, "Add JAR/Folder...", et sélectionner tous les .jar à rajouter.

Étape 3 : Configuration de ICEfaces

Enfin, une fois les librairies ajoutées, passons à la configuration.

La seule véritable configuration à faire réside dans web.xml. Il faut configurer correctement les servlets de ICEfaces afin qu'elles puissent intercepter les requêtes des utilisateurs.

Personnellement, je pense que ce fichier de configuration est amplement suffisant pour travailler uniquement avec ICEfaces et JSF. À modifier en fonction des besoin de votre application (servlets personnalisées à rajouter le cas échéant, etc...).

Notes sur le fichier de configuration ci dessus :
  • La servlet de ICEfaces est configurée pour écouter les requêtes *.iface. L'URL pour accéder à /ma/page.jsp en utilisant ICEfaces sera donc /ma/page.iface.
  • La servlet de JSF est configurée pour écouter les requêtes *.jsf.

Étape 4 : Utilisation de ICEfaces

Quelques étapes à réaliser pour pouvoir utiliser ICEfaces dans vos pages JSP :
  • Pensez à importer la taglib dans chacune de vos JSP. L'URI complète de la taglib est http://www.icesoft.com/icefaces/component
  • Pensez aussi à importer les feuilles de style CSS de ICEfaces, grâce à la ligne <link href="./xmlhttp/css/rime/rime.css" rel="stylesheet" type="text/css" />. La feuille de style rime est ma préférée, mais d'autres sont disponibles.

Il est maintenant temps de tester notre installation de ICEfaces. Pour cela, quoi de mieux que d'essayer d'utiliser un calendrier ou de l'auto-complétion ?

En bonus, voici joint :

Permalink  |  Commentaires (1)