Posts tagged: Java

Wiser : tester l’envoi d’un email

By , 21/10/2011

Wiser est un petit serveur SMPT facilement intégrable dans une classe de test unitaire (Junit, TestNg, etc.). Il réceptionne les messages et les sauvegardes dans un tableau au lieu de les envoyer sur le réseau. Ces messages sont ensuite disponibles pour vérification.

Avec ce serveur, il est possible de vérifier tous les types de mails même ceux qui contiennent des pièces jointes. Il est développé dans le projet subethasmtp.

Dans un projet maven il est nécessaire d’ajouter les dépendances suivantes :

<dependency>
    <groupId>org.subethamail</groupId>
    <artifactId>subethasmtp-wiser</artifactId>
    <version>1.2</version>
    <scope>test</scope>
</dependency>

<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.8.2</version>
    <scope>test</scope>
</dependency>

Il faut, ensuite, écrire une méthode qui va envoyer un email et la tester dans une classe JUnit. Je vous propose d’utiliser JavaMail. Remarque : vous pouvez aussi envoyer un email à partir d’un logiciel comme thunderbird s’il est configuré avec Wiser comme serveur SMTP.

 /**
  * Méthode qui envoie un email.
  */
public void sendEmail(String serveur, int port) throws AddressException, MessagingException {
   Properties prop = System.getProperties();
   prop.put("mail.smtp.host", serveur);
   prop.put("mail.smtp.port", String.valueOf(port));

   Session session = Session.getDefaultInstance(prop,null);
   InternetAddress[] internetAddresses =
   new InternetAddress[] {new InternetAddress("toi@xxx.com")};

   Message message = new MimeMessage(session);
   message.setFrom(new InternetAddress("moi@xxx.com"));
   message.setRecipients(Message.RecipientType.TO, internetAddresses);
   message.setSubject("Test");
   message.setText("test mail");

   Transport.send(message);
 }

 /**
 * Démarrage de Wiser avant l'éxécution du test.
 */
 @Before
 public void setUp() {
   wiser = new Wiser();
   wiser.setPort(2500); // port par défaut : 25
   wiser.start();
 }

 @After
 public void tearDown() {
   wiser.stop();
 }

 @Test
 public void testSendEmail() {
   try {
     sendEmail("localhost", 2500);   // Appel de la méthode qui envoie l'email.
     assertEquals(1, wiser.getMessages().size());

     for (WiserMessage message : wiser.getMessages()) {
       String envelopeSender = message.getEnvelopeSender();
       String envelopeReceiver = message.getEnvelopeReceiver();

       MimeMessage mess = message.getMimeMessage();

       // Il ne reste plus qu'a vérifier le contenu de l'email.
     }

   } catch (Exception e) {
     fail();
   }
 }

Vous pouvez retrouver mon projet exemple ici.

Dans la distribution de subethasmtp, vous retrouverez des exemples pour tester des emails plus compliqués avec notament des pièces jointes.

mod_jk : Apache & tomcat

By , 19/08/2011

A chaque fois que j’essaie de configurer un tomcat derrière un serveur apache, je tombe toujours sur les mêmes problèmes, je perds toujours du temps à retrouver les mêmes solutions dans les documentations. C’est pour cela que j’écris cet article que j’espère le plus simple et pratique que possible.

Après avoir installé les deux serveurs, il faut télécharger le module apache mod_jk (la version 1.2) sur ce site : http://tomcat.apache.org/download-connectors.cgi.

Déposer le fichier mod_jk.so (qui se trouve dans l’archive téléchargée) dans le répertoire $APACHE_HOME/modules/. Pour configurer ce connecteur, deux fichiers sont nécessaires

  • workers.properties : permet au connecteur de se connecter au serveur tomcat.
  • httpd.conf : permet au connecteur de rediriger les requêtes HTTP vers le serveur tomcat.

Voici un fichier worker.properties exemple :

  # La liste des workers
  worker.list= worker1, jkstatus

  # Configuration du worker1 : connexion à tomcat
  worker.worker1.type=ajp13
  worker.worker1.host=localhost
  worker.worker1.port=8009

  # Configuration de jkstatus : agrège des statistiques sur le connecteur
  worker.jkstatus.type=status

Voici quelques lignes à ajouter au fichier httpd.conf pour configurer mod_jk :

  LoadModule    jk_module  modules/mod_jk.so
  JkWorkersFile workers.properties
  JkLogFile     /usr/local/apache/logs/mod_jk.log
  JkLogLevel    info
  JkLogStampFormat "[%a %b %d %H:%M:%S %Y] "

Une fois cette communication faite il faut rendre les applications tomcat visibles depuis Apache. Cette étape peut être aussi bien réalisée à partir du fichier httpd.conf que worker.properties. Par exemple, voici la directive à ajouter au fichier de configuration du serveur Apache :

   JkMount /my-webapplication/* worker1
   JkMount /my-webapplication worker1
   JkMount /jkstatus* jkstatus

Il existe beaucoup d’autre façons de configurer ces deux serveurs. Pour plus d’information voici quelques sites qui décrivent dans les détails les différentes configurations possibles :

Eclispe IDE : MoreUnit

By , 29/06/2011

Il y a quelques mois, on m’a fait découvrir le plugin eclipse MoreUnit. Comme je le trouve très pratique, je profite de mon blog pour en parler. Il permet de gagner du temps pour le développement et l’exécution des tests unitaires. Il facilite aussi l’association entre les classes destinées à l’exécution et celles qui vont les tester. Ce plugin est disponible sur le marketplace.

Si l’option Decorate Classes with Test Case est activée (Window > Preferences… > General > Appearance > Label Decorations), les classes qui sont testées sont représentées avec un icon différent :

La même marque verte apparaît au niveau de la marge de l’éditeur Java au début des méthodes testées :

A partir d’une classe, un menu contextuel permet les actions suivantes :

  • Ouvrir la classe de test associée
  • Générer la classe de test si celle-ci n’existe pas
  • Exécuter la classe de test en entier
  • Exécuter les méthodes de test associées à une sélection de méthodes de la classe d’origine

Le plugin sait aussi prendre en compte les refactorings de la classe testée :

  • Si la classe testée est renommée, la classe de test est renommé elle aussi
  • Idem, si la méthode testée est renommée, les méthodes de test le sont aussi
  • Si la classe testée change de package, la classe de test change aussi de package

Enfin, la dernière fonctionnalité que je trouve très utile dans certains contextes, MoreUnit peut générer les mocks des objets utilisés dans la classe testée. Il est compatible avec Mockito et EasyMock. Il ne reste plus qu’a les paraméter.

tomcat-maven-plugin : debug

By , 29/04/2011

Le plugin tomcat de Maven est très pratique lors du développement d’une application web. Voici comment le configurer :

 <!-- Embedded Tomcat (package tomcat:run) -->
 <!-- Standalone Tomcat (package tomcat:deploy) -->
 <plugin>
   <groupId>org.codehaus.mojo</groupId>
   <artifactId>tomcat-maven-plugin</artifactId>
   <configuration>
     <path>/${project.build.finalName}</path>
     <!-- Embedded port -->
     <port>9090</port>
   </configuration>
 </plugin>

Le plugin démarre le serveur dans la sa propre JVM. Pour pouvoir débuger votre application, il faut donc uniquement démarrer Maven avec l’option de debug comme cela :

mvn tomcat:run -DXdebug -DXnoagent -Djava.compiler=NONE -DXrunjdwp:transport=dt_socket,address=3998,suspend=n,server=y

Ou bien, si vous utilisez eclipse avec le plugin m2eclipse : cliquer avec le bouton droit de votre souris sur le projet : Debug As -> Maven build … .

Tests unitaires et multithreading

By , 17/04/2011

Comment savoir si une méthode développée fonctionne bien dans un contexte multithread ? Pour répondre à cette question je vous propose cet exemple qui se base sur une classe simple utilisant une instance  statique de SimpleDateFormat qui n’est pas un objet threadsafe. Cette classe possède deux méthodes l’une n’est pas threadsafe l’autre l’est grâce à un bloc “synchronisé”.

public class DateUtil {
 /** Static pour bénéficier d'une instance partagée par l'ensemble des threads.*/
 private static DateFormat df = new SimpleDateFormat("dd/MM/yyyy");

 public static Date parse(String date) throws ParseException {
   Date result = null;
   result = df.parse(date);
   return result;
 }

 public static Date parseThreadSafe(String date) throws ParseException {
   Date result = null;
   // Ce bloc garantit que la méthode fonctionne en multithread.
   synchronized (df) {
     result = df.parse(date);
   }
   return result;
 }
}

La classe de test utilise la librairie TestNg et non JUnit car cette dernière ne propose pas de support du multithread. De son coté, TestNg permet de paramétrer une méthode de test avec, entre autre, deux paramètres :

  • invocationCount : le nombre d’invocation de la méthode (valeur par défaut : 1)
  • threadPoolSize : la taille du pool de threads qui vont exécuter la méthode (valeur par défaut : 0)
public class DateUtilTest {

 @Test(threadPoolSize=20, invocationCount=100)
 public void testParse() {
   try {
     for (int i = 10; i < 20; i++) {
       assertEquals(new SimpleDateFormat("dd/MM/yyyy").parse("01/01/20" + i),
         DateUtil.parse("01/01/20" + i));    
     }
   } catch (ParseException e) {
     fail("TEST KO : " + e.getMessage());
   }
 }

 @Test(threadPoolSize=20, invocationCount=100)
 public void testParseThreadSafe() {
   try {
     for (int i = 10; i < 20; i++) {
       assertEquals(new SimpleDateFormat("dd/MM/yyyy").parse("01/01/20" + i),
         DateUtil.parseThreadSafe("01/01/20" + i));    
     }
   } catch (ParseException e) {
     fail("TEST KO : " + e.getMessage());
   }
 }

}

Les boucles for servent à augmenter la probabilité d’appel simultanés des méthodes testées. Le résultat de l’exécution est assez simple a analyser car les seules méthodes qui tombent en erreur sont celles qui exécutent la méthode sans le bloc synchronisé.

Vous pouvez retrouver le projet maven à l’adresse suivante : https://subversion.assembla.com/svn/everythingiswrong/multithread-tests

Test unitaires : mauvaises pratiques (TDD anti-pattern)

By , 20/03/2011

Depuis pas mal de temps, je me pose des questions sur les bonnes pratiques à mettre en œuvre dans le développement de mes tests unitaires. N’ayant jamais rencontré de personne ayant beaucoup d’expérience dans le domaine, je me suis toujours restreint à développer des tests :

  • Rapides à développer
  • Faciles à maintenir
  • limités à une fonctionnalité

C’est dans ce contexte que j’ai cherché sur internet des propositions de bonnes pratiques sur les tests unitaires automatisés. J’ai trouvé mieux : des pratiques à éviter (http://blog.james-carr.org/2006/11/03/tdd-anti-patterns/).

Fiji 2.0 : Intégration de FusionCharts et JSF

By , 01/03/2011

Après avoir parlé de Fiji il y a quelques mois, j’ai souhaité développer un petit exemple pour mettre en pratique l’intégration Flex dans une page JSF 2. Pour cela j’ai choisis d’intégrer un graphique FusionCharts dans une page JSF. Pour information, FusionCharts est une librairie graphique qui permet de développer des graphiques à partir d’un fichier XML (lignes, histogrammes, cartes du monde, etc.).

Mise en place du projet

Pour faire simple, j’ai choisis de commencer une nouvelle application Java J2EE6 grâce au squelette de projet weld : org.jboss.weld.archetypes:weld-jsf-servlet-minimal. Je suis ensuite aller chercher les librairies tierces suivantes :

Développement

Mon but est de reproduire le premier exemple de graphique proposé sur la gallerie du site internet de FusionCharts :

Tout d’abord, il faut déposer la librairie Fiji 2.0 dans le répertoire src/main/webapp/WEB-INF/lib puis un graphique fusionChart (*.swf) dans un répertoire web du projet. Ensuite, deux fichiers sont nécessaires :

  • Un fichier XHTML pour générer le XML qui décrit le graphique
  • Un fichier XHTML pour  décrire la page JSF qui va intégrer le graphique

Voici le fichier XHTML qui va décrire le graphique :

<?xml version="1.0" encoding="UTF-8"?>

<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">

 <graph yAxisName='Sales Figure' caption='Top 5 Sales Person' numberPrefix='$'
    decimalPrecision='1' divlinedecimalPrecision='0' limitsdecimalPrecision='0'>
   <ui:repeat var="item" value="#{dynaGraphique.listPersonne}">
      <set name='#{item.name}' value='#{item.sales}' color='#{item.color}' />
   </ui:repeat>
 </graph>

</f:view>

On peut remarquer que j’utilise le tag <ui:repeat/> pour itérer sur une liste de données qui va représenter plusieurs séries sur mon histogramme. Ci-dessous, le fichier qui décrit le même graphique en static :

<?xml version="1.0" encoding="UTF-8"?>
<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">

   <graph yAxisName='Sales Figure' caption='Top 5 Sales Person' numberPrefix='$'
      decimalPrecision='1' divlinedecimalPrecision='0' limitsdecimalPrecision='0'>
        <set name='Alex' value='25000' color='AFD8F8' />
        <set name='Mark' value='35000' color='F6BD0F' />
        <set name='David' value='42300' color='8BBA00' />
        <set name='Graham' value='35300' color='FF8E46' />
        <set name='John' value='31300' color='008E8E' />
   </graph>

</f:view>

Les deux classes java qui vont contenir les données pour le graphique. Vous allez retrouver les données précédentes dans la première classe :

@Model
public class DynaGraphique {
 private List<Personne> listPersonne = new ArrayList<Personne>();

 @PostConstruct
 public void initialize() {
   listPersonne.add(new Personne("Alex", 25000, "AFD8F8"));
   listPersonne.add(new Personne("Mark", 35000, "F6BD0F"));
   listPersonne.add(new Personne("David", 42300, "8BBA00"));
   listPersonne.add(new Personne("Graham", 35300, "FF8E46"));
   listPersonne.add(new Personne("John", 31300, "008E8E"));
 }
 // Getter et Setter

}
public class Personne {
 private String name;
 private int sales;
 private String color;

 public Personne() {
 }

 public Personne(String name, int sales, String color) {
 super();
 this.name = name;
 this.sales = sales;
 this.color = color;
 }
//Getter et Setter ...
...
}

Le fichier XHTML qui va générer la page JSF :

<?xml version="1.0" encoding="UTF-8"?>
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
   xmlns:ui="http://java.sun.com/jsf/facelets"
   xmlns:f="http://java.sun.com/jsf/core"
   xmlns:h="http://java.sun.com/jsf/html"
   xmlns:fiji="http://exadel.com/fiji"
   template="/WEB-INF/templates/default.xhtml"
   xmlns:a4j="http://richfaces.org/a4j">
      <ui:define name="content">
         <!-- static : voir le fichier fusionChart/fusion01.jsf -->
         <fiji:swf src="fusionChart/FCF_Column3D.swf" bgcolor="#FFFFFF" width="520" height="400">
            <f:param name="dataURL" value="fusionChart/fusion01.jsf" />
         </fiji:swf>
         <!-- dynamique -->
         <fiji:swf src="fusionChart/FCF_Column3D.swf" bgcolor="#FFFFFF" width="520" height="400">
            <f:param name="dataURL" value="fusionChart/fusion02.jsf" />
         </fiji:swf>
      </ui:define>
</ui:composition>

Pour information, il ne faut pas oublier de préciser les attributs bgcolor, width et height pour éviter une erreur d’exécution de Fiji.

Exécution du projet

Pour exécuter le projet, j’utilise la commande maven mvn compile tomcat:run. L’application est alors disponible à l’adresse : http://localhost:9090/jsf.servlet.minimal.

Vous pouvez checkouter le projet à l’adresse suivante : http://subversion.assembla.com/svn/everythingiswrong/tutorial-fiji-fusionchart/

jaxb2-maven-plugin : plusieurs exécutions successives de jaxb2:xjc

By , 11/02/2011

Dans ce ticket, je vais expliquer comment bien configurer le plugin jaxb2-maven-plugin dans le cas où l’on souhaite transformer des fichiers XSD en classes java vers des packages différents. Il faut savoir qu’avec ce plugin il n’est pas possible de définir plusieurs packages de destination dans une même exécution.

Dans l’exemple choisi, je génère deux classes Java à partir de deux fichier XSD vers deux packages différents :

<plugin>
  <groupId>org.codehaus.mojo</groupId>
  <artifactId>jaxb2-maven-plugin</artifactId>
  <executions>
    <execution>
      <id>id1</id>
      <phase>generate-sources</phase>
      <goals>
        <goal>xjc</goal>
      </goals>
      <configuration>
        <clearOutputDir>false</clearOutputDir>
        <staleFile>${project.build.directory}/generated-sources/jaxb/.staleFlag-id1</staleFile>
        <schemaDirectory>${basedir}/src/main/resources/id1</schemaDirectory>
        <packageName>id1</packageName> <!-- The name of your generated source package -->
      </configuration>
    </execution>
    <execution>
      <id>id2</id>
      <phase>generate-sources</phase>
      <goals>
        <goal>xjc</goal>
      </goals>
      <configuration>
        <clearOutputDir>false</clearOutputDir>
        <staleFile>${project.build.directory}/generated-sources/jaxb/.staleFlag-id2</staleFile>
        <schemaDirectory>${basedir}/src/main/resources/id2</schemaDirectory>
        <packageName>id2</packageName> <!-- The name of your generated source package -->
      </configuration>
    </execution>
  </executions>
  <dependencies>
     <dependency>
       <groupId>xerces</groupId>
       <artifactId>xercesImpl</artifactId>
       <version>2.8.1</version>
     </dependency>
  </dependencies>
</plugin>

A noter que pour chaque exécution :

  • Il est nécessaire d’utiliser un identifiant unique. Sinon maven n’arrivera pas à exécuter le plugin.
  • Il faut impérativement utiliser l’option staleFile pour associer un fichier différent à chaque exécution (ce fichier sert au plugin pour savoir si les classes Java sont déjà générées). Sans cela, la seconde exécution ne génèrera pas de classe Java.
  • Il faut indiquer au plugin de ne pas nettoyer le répertoire de génération avant l’exécution (option clearOutputDir à false) car c’est son comportement par défaut. Sans cela, la seconde exécution supprimera les classes générées pas la première.

Voici l’adresse de l’exemple associé : https://subversion.assembla.com/svn/everythingiswrong/tutorial-jaxb2-maven-plugin/.

Eclipse : autocompletion sur les imports statiques

By , 13/12/2010

Eclipse propose l’autocompletion sur les méthodes des objets importés statiquement qu’après les avoir déclarés manuellement. Par exemple, pour utiliser les asserts JUnit dans un test TestNg, il faut ajouter l’import statique suivant avant de pouvoir bénéficier de l’aide à la saisie :

import static org.testng.AssertJUnit.*;

Pour profiter de l’autocompletion sans ajouter cette ligne au préalable, il faut se diriger dans le menu : Window -> Preferences puis Java -> Editor -> Content Assist -> Favorites et ajouter le nouveau type org.testng.AssertJUnit.

Utiliser l’annuaire JNDI d’un JBoss embedded

By , 12/12/2010

Il est toujours difficile de paramétrer les conteneurs embarqués. Encore plus lorsque ces derniers ne sont plus très récents et donc pas très bien documentés. C’est pourquoi je vous propose cet article  qui va vous apprendre à enregistrer une chaine de caractère (java.lang.String) dans l’annulaire JNDI de JBoss embedded. Pour cela, il faut ajouter ce code XML dans le fichier embedded-jboss-beans.xml de votre classpath :

<bean name="" class="org.jboss.ejb3.embedded.JndiBinder">
    <property name="target">La valeur de la variable</property>
    <property name="bindTo">variableName</property>
    <property name="serializable">true</property>
</bean>

Voici un exemple concret : https://subversion.assembla.com/svn/everythingiswrong/embedded-jboss-jndi-exemple.

Pour plus d’information sur le conteneur embarqué  de JBoss que j’utilise dans l’exemple : http://docs.jboss.org/ejb3/embedded/embedded.html.

OfficeFolders theme by Themocracy