Catégorie : Java

GWT et éditeur de texte riche : impossible ?

Au cours du développement du produit, nous avons été confronté à un problème imprévu : l’intégration d’un éditeur de texte riche au sein d’une application écrite en GWT.

En effet, nous désirions laisser la possibilité à l’utilisateur de créer ou modifier une page web en mode WYSIWYG directement depuis l’application, mais l’éditeur proposé par GWT ne nous paraissait pas suffisant.

Après une rapide analyse des solutions existantes, nous avons tout d’abord décidé d’utiliser FCKeditor, celui-ci semblant offrir le plus grand nombre de fonctionnalités sur le marché à l’heure actuelle.
Nous sommes pour cela repartis de gwt-html-editor que nous avons adaptée à nos besoins. Cependant, si cette solution fonctionnait parfaitement lors de nos tests en hosted mode, dès le premier test de l’application déployée, nous avons rencontré des problèmes :

  • comportements différents selon les navigateurs
  • problèmes lors du premier chargement du composant
  • problèmes lors du rechargement du composant

Ces problèmes étant impossibles à résoudre facilement, nous avons décidé de tester les solutions concurrentes : XinhaTinyMCE et Yahoo! editor.
Mais celles-ci se sont avérées souffrir des même problèmes que FCKeditor. En effet, ces éditeurs ont été conçus pour fonctionner au sein d’une application web « classique », et ne sont pas adaptés pour une application entièrement enAJAX, comme celles réalisées en GWT.

Suite à ce constat, nous avons choisi de privilégier une solution hybride : la visualisation du texte riche se fait dans une iframe au sein de l’application, mais son édition se fait dans une page web classique présentée en popup.

Le composant s’articule autour de trois fichiers :

  • FCKRichEditorImpl.java, le composant en lui-même
  • iframeFckEditor.html, la page web affichant le rendu au sein d’une iframe (l’iframe permet d’avoir un style propre à la page affichée, ce que ne permettait pas l’utilisation d’un setInnerHTML (), par exemple)
  • pageFckEditor.html, la page en popup permettant d’éditer le texte grâce à FCKeditor

Cette solution fonctionne parfaitement et ne souffre pas des problèmes cités précédemment, mais elle en apporte cependant deux nouveaux :

  • moins bonne intégration de l’édition de texte avec le reste de l’application
  • possibilité de problème avec les bloqueurs de popup

C’est pourquoi nous restons à l’écoute du marché, et surveillons avec attention les nouvelles solutions disponibles.

Si vous désirez le code de notre solution n’hésitez pas à nous contacter

Dozer pour le mapping Bean à Bean

Nous utilisons Dozer au sein de notre application lorsque nous avons besoin de faire du mapping Bean à Bean et notamment lors de l’appel de services web publiés par nos partenaires.

Dozer offre des fonctionnalités assez poussées comme la possibilité de surcharger les setter/getter ou les méthodes de création de Bean.

L’une des fonctionnalités indispensables, mais pourtant assez mal documentée, lors du mapping avec des classes générées par XMLBean ou JAXB2, est la possibilité de mapper les inner class :

<mapping>
<class-a>com.viaxoft.Availability$Response</class-a>
...

Le $ remplace le point dans le chemin vers l’inner class.

Velocity au runtime : modification de template

Modification de template Velocity au runtime

Velocity est un moteur de template Open Source Java de la fondation Apache. Nous utilisons Velocity depuis pas mal de temps pour tout ce qui est rapport aux fusions (Mail, publipostage,…).
Jusqu’à présent nous l’utilisions sous sa forme la plus « traditionnelle », basée sur des fichier template (.vm), que nous chargions au runtime pour être fusionnés à une map de paramètres :

  // Initialisation du moteur velocity
VelocityEngine engine = new VelocityEngine();
engine.init();
// Chargement du template
Template template = engine.getTemplate( "test.vm" );
// Création du contexte
VelocityContext context = new VelocityContext();
context.put("nom", "Durand");
// Exécution du template dans une String
StringWriter writer = new StringWriter();
template.merge( context, writer );System.out.println( writer.toString() );

Dernièrement nous avons eu le besoin de composer une variable sur la base de plusieurs autres. Il s’agit de faire un peu plus que de la concaténation ; nous avons donc laissé nos utilisateurs créer leur propres variables de la sorte :

 politesse = &civilite &nom &prenom

Mais nous devions à ce moment là modifier nos template au runtime. Velocity offre pour cela une méthode evaluate qui permet d’évaluer un template (sous forme de String) :

StringWriter result = new StringWriter();
try {
velocityEngine.evaluate(velocityContext, result, "template", template);
} catch (Exception e)...

Ceci nous a permis de stocker les modèles en base de données sans avoir ensuite à recréer des InputStream ou autre pour les fusionner.

Nous modifions les modèles au runtime en leur ajoutant les variables créées par les utilisateurs.

GWT, Tomcat, Eclipse et Cypal Studio

GWT et son hosted mode

GWT offre un mode de de développement « embarqué » (le hosted mode) qui permet de faire tourner l’application au sein de la machine virtuelle Java et ainsi garder tous les avantages d’un IDE tel qu’Eclipse et notamment le debugger.

Mais pour l’intégration de module plus avancés tels que la sécurité avec Acegi, il est primordial de déployer l’application sur un tomcat externe afin de configurer au mieux ce dernier. Voici un lien vers un très bon post, détaillant au sein d’Eclipse la création d’un projet GWT en s’appuyant sur le plugin Cypal. Ceux qui ont déjà galéré sur ce type de déploiement apprécieront :
Creating your first GWT app with Cypal Studio for GWT.
Merci à Prakash pour ce billet.

L’intégration d’Acegi au trio GWT, Spring, Hibernate fera l’objet d’un prochain post.

Gestion des logs

Au sujet de la gestion des logs

La gestion des logs est un sujet qui est souvent sous estimé de la part des équipes de développement. Avec l’utilisation des outils de développement moderne et leur débugger intégré, les logs applicatives ont bien moins d’intérêts au moment du développement. Par contre, lorsque l’application est testée ou déployée, les logs reprennent tout leur sens.

L’apparition de framework Java tels que Log4J ou celui intégré au JDK facilite grandement la vie du développeur, mais l’écriture de logs reste toujours à la discrétion de ce dernier.

L’AOP (Programmation Orientée Aspect) apporte une réponse à cette problématique. Nous pouvons grâce à celle-ci générer des logs à chaque entrée/sortie de méthode et à chaque levée d’exception. Voici un exemple d’implémentation de gestion des logs utilisant Spring et Spring AOP :

Nous définissons tout d’abord un greffon (advice) qui implémente MethodBeforeAdvice, AfterReturningAdvice et ThrowsAdvice. Ceci nous permet de redéfinir les trois méthodes before, afterReturning et afterThrowing afin de générer les logs à chaque entrée/sortie de méthode et à chaque levée d’exception.

package com.viaxoft.ext.logging;

import java.lang.reflect.Method;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.aop.AfterReturningAdvice;
import org.springframework.aop.MethodBeforeAdvice;
import org.springframework.aop.ThrowsAdvice;

public class LoggingAdvice implements MethodBeforeAdvice, AfterReturningAdvice,
ThrowsAdvice {
private static Log logger = null;

public LoggingAdvice() {
}

public void before(Method arg0, Object[] arg1, Object arg2)
throws Throwable {
logger = LogFactory.getLog(arg2.getClass());
logger.info("Entrée dans la méthode : " + arg0.getName());
}

public void afterReturning(Object arg0, Method arg1, Object[] arg2,
Object arg3) throws Throwable {
logger = LogFactory.getLog(arg3.getClass());
logger.info("Sortie de la méthode : " + arg1.getName());
}

public void afterThrowing(Method m, Object[] args, Object target,
Throwable ex) {
logger = LogFactory.getLog(target.getClass());
logger.error("Exceptiondans la méthode : " + m.getName() + " L'exception : "
+ ex.getMessage());
}
}

Nous devons ensuite définir notre aspect sous forme de bean au sein du fichier de config Spring. Nous utilisons l’implémentation RegexpMethodPointcutAdvisor qui nous permet de matcher les méthodes sur lesquelles notre aspects doit s’appliquer grâce à une expression régulière :

<bean id="loggingAdvisor"   class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<property name="advice" ref="loggingAdvice" />
<property name="patterns" value=".*" />
</bean>

A noter ici que nous générons la log pour toutes les méthodes. On pourrait imaginer générer plusieurs niveau de log (DEBUG, INFO, …), en fonction de la méthode à laquelle on s’adresse ; par exemple les méthodes du layer DAO seraient en DEBUG, alors que celles de la couche service en INFO.

L’implémentation RegexpMethodPointcutAdvisor permet de définir à la fois l’aspect et la coupe au sens AOP.

Nous définissons également le greffon :

<bean id="loggingAdvice"
class="com.viaxoft.ext.logging.LoggingAdvice">
</bean>

Il ne nous reste plus ensuite qu’à tisser les aspects. Nous utilisons DefaultAdvisorAutoProxyCreator pour un tissage automatique :

<bean   class="org.springframework.aop.framework.autoproxy.
DefaultAdvisorAutoProxyCreator" />

Le résultat dans le fichier de log :

juin 06 08:54:25 INFO iaxoft.dao.impl.AddressDaoImpl before Entrée dans la méthode: saveAddress
juin 06 08:54:25 INFO ernate.impl.SessionFactoryImpl before Entrée dans la méthode: openSession
juin 06 08:54:25 INFO ernate.impl.SessionFactoryImpl afterReturning Sortie de la méthode : openSession
juin 06 08:54:25 INFO ernate.impl.SessionFactoryImpl before Entrée dans la méthode: getTransactionManager
juin 06 08:54:25 INFO ernate.impl.SessionFactoryImpl afterReturning Sortie de la méthode : getTransactionManager
juin 06 08:54:25 INFO iaxoft.dao.impl.AddressDaoImpl afterReturning Sortie de la méthode : saveAddress
Loading...
X