Category: Java J2EE

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

Richfaces et Ajax

By , 03/11/2010

Sur une interface web faisant des appels AJAX, il est parfois très complexe de comprendre ce qu’il se passe lors des saisies utilisateurs et des multiples rafraichissements. Les développeurs  qui utilisent Richfaces ont à leur disposition un composent JSF plus qu’intéressant depuis la version 3.0.0 : <a4j:log/>. Il affiche tout simplement les échanges entre le client et le serveur dans la page HTML résultat. Voici une possibilité d’utilisation :

<4j:log level="ALL" popup="false" width="400" height="200" />

En utilisant ce “logger”, j’ai remarqué qu’il était souvent nécessaire d’utiliser une queue AJAX dans les interfaces utilisant massivement cette technologie. Là encore, Richfaces propose un composant clé en main pour implémenter cette queue : <a4j:queue/>.

Vous pouvez retrouver ces composants dans le showroom de Richfaces : <a4j:log/> et <a4j:queue/>.

JSF : Unicode Encoding

By , 13/10/2010

Par défaut, l’implémentation de référence de JSF (Mojarra 1.2) convertit tous les caractères non ASCII en entités HTML. Cela peut provoquer des problèmes d’encoding. Il est possible de modifier ce comportement en ajoutant le paramètre com.sun.faces.disableUnicodeEscaping dans le fichier web.xml avec l’une de ces valeurs :

  • true : aucun caractère ne sera transformé
  • false : tous les caractères non ASCII seront encodés en entités HTML quelque soit l’encoding de la réponse (c’est le comportement par défaut)
  • auto : suivant le type d’encoding de la réponse :
    • UTF : pas d’encoding effectué
    • ISO-8859-1 : les caractères sont transformés en entité HTML

Voici comment cela se traduit dans le fichier web.xml :

<context-param>
    <param-name>com.sun.faces.disableUnicodeEscaping</param-name>
    <param-value>true<param-value>
</context-param>

De mon coté, je n’ai jamais eu de problème avec le mode par défaut à l’exception d’un développement qui utilisait Fiji et amChart car amChart n’affiche pas les entités HTML en caractères latins.

Traitements longs et batchs sur un serveur d’application Java

By , 09/10/2010

La question posée dans ce article est de savoir s’il est opportun d’utiliser JavaJ2EE et donc un serveur d’application pour des traitements longs. Je pense notamment à des traitements batch ou à des traitements lourds provoqués par une demande d’un utilisateur sur une page web. Pour répondre à cette question il faut comprendre le fonctionnement d’un serveur d’application.

Principe de fonctionnement

Lorsqu’un serveur d’application reçoit à une demande cliente (HTTP, RMI, etc.), il utilise une thread pour y répondre puis la libère à la fin du traitement. Vous pouvez vérifier ce comportement avec une requête HTTP ou bien un MBean. Pour visualiser les threads dans les log il faut paramétrer le PatternLayout Log4J avec %t. Lorsque toutes les threads sont occupées, le serveur ne peut plus répondre aux demandes clientes.

Pour information, sur un serveur d’application, le nombre de thread est limité mais configurable. Par exemple, le nombre maximum de threads sur JBoss est de 100 par défaut.

Traitements longs

Dans un serveur d’application, certaines ressources ont une durée de vie ou d’activité limitée. Par exemple, une transaction sur une base de données ne peut pas excéder 5 minutes par défaut sur une serveur JBoss sous peine de provoquer l’exception suivante :

Transaction is not active: tx=TransactionImple < ac, BasicAction: -3f57f10b:911:49fb4a4b:3e status: ActionStatus.ABORT_ONLY >; - nested throwable: (javax.resource.ResourceException: Transaction is not active: tx=TransactionImple < ac, BasicAction: -3f57f10b:911:49fb4a4b:3e status: ActionStatus.ABORT_ONLY >)

La seule solution est de découper son traitement en plusieurs traitements plus petit ou de modifier le timeout. Dans ce dernier cas, il faut faire attention car un timeout top grand peut avoir des effets néfastes sur les performances de l’application. Voici comment gérer les démarcations de transaction pour découper un traitement long en plusieurs petits traitements :

Client (sans transaction) -> EJB (transaction supportée : TransactionAttributeType.SUPPORTS) -> EJBs (nouvelle transaction pour chaque appel EJB : TransactionAttributeType.REQUIRED ou TransactionAttributeType.REQUIRES_NEW)

Dissociation entre le web et les traitements lourds

Après avoir vu le principe de fonctionnement d’un serveur d’application et comment développer un traitement long sans provoquer d’exception de timeout, il ne faut pas oublier qu’une application web peut être utilisée par un grand nombre d’utilisateurs. Si les requêtes HTTP provoquent des traitements longs cela peut rapidement provoquer une indisponibilité du serveur.

Une des solutions possibles est d’utiliser deux serveurs d’applications différents : un serveur d’application pour les traitements lourds et un pour l’IHM. Les échanges entre ces deux serveurs doivent se faire en asynchrone pour ne pas pénaliser la partie web de l’application. Ainsi une augmentation du nombre d’utilisateur n’impactera pas votre application, à moins de mal configurer le serveur s’occupant de l’IHM.

Au final, tout n’est qu’une question de paramétrage des serveurs. Il ne faut pas oublier qu’avec un serveur d’application le clustering est toujours possible, et dans ce cas, le nombre de threads disponibles pour traiter les demandes augment lui aussi.

Vous pouvez utiliser le serveur d’application pour exécuter seulement des batchs. il faut alors vous assurer que le nombre de threads disponibles sur le serveur soit assez grand et que vos traitements successifs n’engendrent pas de problèmes de mémoire ou de réservation de ressources, car votre serveur ne sera pas réinitialisé au début de chaque traitement.

Cas du conteneur embarqué

Si vous préférez avoir une JVM par traitement et donc une architecture plus proche d’un batch classique, des conteneurs embarqués sont désormais disponibles et ils fonctionnent très bien. J’ai déjà testé openEJB et JBossEmbedded, glassfish, etc. je n’ai jamais remarqué de problème sur leur utilisation. De plus, dans ce cas, comme il y a une JVM non partagée par traitement, les problèmes de disponibilités lié à l’utilisation de thread n’existe plus. J’ajouterai que l’utilisation d’un conteneur embarqué est très simple, voici un exemple avec openEJB :

Créer un project maven avec l’archetype quickstart et ajouter openEJB dans les dépendances. Voici l’allure du fichier POM :

    <dependencies>
        <dependency>
            <groupId>org.apache.openejb</groupId>
            <artifactId>openejb-core</artifactId>
            <version>3.1.2</version>
                <exclusions>
                    <exclusion>
                        <groupId>org.apache.activemq</groupId>
                        <artifactId>activeio-core</artifactId>
                    </exclusion>
                </exclusions>
        </dependency>
    </dependencies>

L’exclusion d’activeMq est nécessaire car l’artefact n’existe pas sur le repository maven. L’étape suivante est de rajouter deux fichiers de configuration : jndi.properties avec la ligne

java.naming.factory.initial = org.apache.openejb.client.LocalInitialContextFactory

et un fichier “vide” META-INF/ejb-jar.xml qui ne contient que la ligne :

<ejb-jar/>

Ce fichier XML vide indique au conteneur de rechercher les EJBs présents dans le classpath. Le serveur embarqué se démarre et déploie les  services EJB tout seul et vous n’avez plus qu’a les appeler :

    public class App {
       public static void main( String[] args ) {
          try {
             Context context = new InitialContext();
             HelloWorldService helloWorldService =
                (HelloWorldService) context.lookup("HelloWorldServiceHandlerLocal");
             System.out.println(helloWorldService.sayHello("Smith"));
          } catch (NamingException e) {
             // TODO Auto-generated catch block
             e.printStackTrace();
          }
    }
}

Pour plus de précisions, voici l’URL où vous pouvez retrouver mon exemple : https://subversion.assembla.com/svn/everythingiswrong/tutorial-embedded-openejb/

Conclusion

Pour conclure cet article, je dirais qu’utiliser un serveur d’application pour ses batchs ou traitements longs est très intéressant car cela vous permet de disposer de la stack Java J2EE. Cela peut  éventuellement vous permettre de mutualiser du code entre traitement batch et IHM, si vous avez une application qui nécessite les deux. Si l’utilisation d’un “vrai” serveur d’application vous fait peur, il est toujours possible d’utiliser un conteneur embarqué pour bénéficier, là aussi, de la stack logiciel fournie par Java J2EE.

Les traitements longs sur les serveurs d’applications J2EE ne sont donc qu’une question de paramétrage. Ils ne sont pas à proscrire, surtout si vous utilisez un conteneur embarqué.

Pour ceux qui ne sont toujours pas convaincus, voici 4 articles intéressants sur les batchs J2EE et le multithreading dans un serveur J2EE :

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.

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.

JSF, Facelets : duplicateComponentId

By , 29/09/2010

Lors d’un développement, j’ai été confronté à un problème de duplication d’identifiant de composant. J’utilisais des rafraichissements AJAX sur une page XHML (Facelets)  qui incluait une autre page XHTML.

...
<c:forEach items="#{maList}" var="monObjet">
    <ui:include src="page.xhtml">
        <ui:param name="title" value="#{monObjet.title}" />
    </ui:include>
</c:forEach>
...

La duplication se trouvait sur un composant de la page inclue. En cherchant sur les blogs et les forums j’ai trouvé comment rendre indépendant les identifiants des composants de la page inclue entre les itérations et la page “mère”. Il faut utiliser le composant <f:subwiev/> de cette manière :

...
<c:forEach items="#{maList}" var="monObjet">
    <f:subview>
        <ui:include src="page.xhtml">
            <ui:param name="title" value="#{monObjet.title}" />
        </ui:include>
    </f:subview>
</c:forEach>
...

D’après ce que j’ai lu, l’utilisation de <f:subview/> est recommandée mais non obligatoire. Il garantit qu’aucun identifiant de composant dans la page inclue ne rentrera en conflit avec les identifiants des composants de la page “mère”. Attention les composants de la subview ne pourront pas faire de références aux composants en dehors de cette même subview.

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.

Maven, Nexus et les versions snapshots inconnues des plugins

By , 27/09/2010

Aujourd’hui, j’ai constaté un comportement étrange de Maven. Mon installation de maven pointe sur un repository nexus interne en local. Le groupe public de Nexus contient le repository des plugins snapshot d’apache.

Lorsque Maven essaie de récupérer un plugin comme maven-scm-plugin Nexus lui propose la dernière version snapshot. Cependant mon projet Maven n’est pas configuré pour accepter les versions snapshots. Le message d’erreur qui suit, annonce que le plugin n’est pas trouvé avec le numéro de version correspondant à la dernière version snapshot existante.

Pour corriger le problème, il faut seulement supprimer le repository snapshot du group public de Nexus. La bonne pratique à en déduire est de ne jamais mettre des versions snapshots dans un repository ayant des versions non snapshots.

Information complémentaire : Pour savoir comment activer les versions snapshots dans un projet Maven : http://maven.apache.org/guides/development/guide-testing-development-plugins.html

Transformer du HTML en text standard

By , 20/09/2010

Il est de temps en temps utile de convertir du texte avec des caractères spéciaux en texte HTML. J’ai eu le problème inverse et j’ai trouvé une solution “séduisante” grâce à la librairie apache commons-lang : StringEscapeUtils.unescapeHtml(). Pour utiliser cette librairie dans un projet Maven il faut ajouter la dépendance suivante :


<dependency>
    <groupId>commons-lang</groupId>
    <artifactId>commons-lang</artifactId>
    <version>2.5</version>
</dependency>

OfficeFolders theme by Themocracy