Remote connection manager : mRemoteNG

By , 10/05/2011

Depuis quelques années j’ai adopté putty connection manager pour gérer dans un même logiciel toutes mes connexions réseaux. Il permet de mutualiser toutes les fenêtres putty dans une même interface à onglets. Mais je me suis vu obligé de trouver une alternative car ce logiciel n’a plus l’air d’être développé. Pire encore, je n’ai pas réussi à exécuter la dernière version que j’ai trouvé sur un site de téléchargement tiers…

Je me suis alors rendu compte que ce n’était pas l’offre qui manquait. J’ai essayé mRomteNg et je l’ai tout de suite adopté.  Il peut se connecter en mode terminal ou graphique selon le protocole utilisé. D’ailleurs voici l’ensemble des protocoles supportés :

  • RDP (Remote Desktop/Terminal Server)
  • VNC (Virtual Network Computing)
  • ICA (Citrix Independent Computing Architecture)
  • SSH (Secure Shell)
  • Telnet (TELecommunication NETwork)
  • HTTP/HTTPS (Hypertext Transfer Protocol)
  • rlogin
  • Raw Socket Connections

De plus je trouve l’interface très intuitive avec ses trois “écrans” :

  • “Connections” : liste des connections enregistrées
  • “Config” : propriété de la connexion sélectionnée
  • Et un écran général composé de plusieurs onglets : un par session

Voici un aperçu de mRemoteNG :

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

yuml.me

By , 15/04/2011

J’ai découvert il y a quelques temps un site internet intéressant pour la génération de petits diagrammes UML : http://yuml.me/. Sur la base d’un langage descriptif très simple il est possible de générer trois types de diagrammes en ligne :

  • Classe
  • Cas d’utilisation
  • Etat ou workflow

Je trouve que les graphiques générés sont propres et originaux. Par exemple :

[Customer]->[Billing Address]

Code source : [Customer]-(Login)

Le serveur permettant de générer ces graphiques est disponible gratuitement à l’adresse http://yuml.me/diagram/scruffy/<type du diagramme : class, activity, usecase>/draw ou directement en remplaçant draw par votre code source. Le code source est expliqué en bas de ces trois pages.

Ainsi, l’URL http://yuml.me/diagram/scruffy/class/[Customer]+1->*[Order], [Order]++1-items >*[LineItem], [Order]-0..1>[PaymentMethod] pointera sur l’image suivante :

Je vous laisse imaginer la simplicité de l’intégration de ce genre d’images sur un site internet grâce à la balise HTML <img/>.

Java : Problème de certificat SSL

By , 04/04/2011

Lorsqu’un traitement Java fait appel à un site internet sécurisé avec le protocole HTTPS,  la JVM vérifie si le certificat SSL est validé par un organisme tiers. Pour cela, il existe dans la JRE une librairie avec des certificats de confiance : $JAVA_HOME/jre/lib/security/cacerts. Voici une erreur possible lors d’un échange entre un client et un serveur SSL :

sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

Lorsque cette erreur arrive, cela veut dire que le certificat délivré par le serveur n’est pas vérifié par une autorité tierce reconnue par la JVM. Pour résoudre ce problème, il y a deux solutions :

  • Annuler la vérification du certificat
  • Ajouter le certificat à la liste des certificats reconnus de la JVM

Annuler la vérification des certificats

Je vous propose d’annuler la vérification de façon programmatique. Pour cela, il faut créer un “TrustManager” qui ne va rien vérifier puis l’utiliser dans le contexte de session SSL.

// Créer un "trust manager" qui ne valide pas les certificats
TrustManager[] trustAllCerts = new TrustManager[]{
    new X509TrustManager() {
        public java.security.cert.X509Certificate[] getAcceptedIssuers() {
            return null;
        }
        public void checkClientTrusted(
            java.security.cert.X509Certificate[] certs, String authType) {
        }
        public void checkServerTrusted(
            java.security.cert.X509Certificate[] certs, String authType) {
        }
    }
};

// Utiliser le manager qui ne valide pas les certificat
try {
    SSLContext sc = SSLContext.getInstance("SSL");
    sc.init(null, trustAllCerts, new java.security.SecureRandom());
    HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
} catch (Exception e) {
}

// Accéder à la page en HTTPS
try {
    URL url = new URL("https://hostname/index.html");
} catch (MalformedURLException e) {
}

Je rappelle qu’en supprimant l’étape de vérification, le client devient sensible aux attaques du type man-in-the-middle. Je déconseille donc cette solution dans le cas général.

Ajouter le nouveau certificat à la JVM

Pour ajouter le certificat dans la JVM, il faut l’exporter depuis votre navigateur. Par exemple, avec Firefox, il faut se rendre dans la fenêtre des options puis  dans le menu Avancé -> Chiffrement cliquer sur le bouton Afficher les certificats. Dans la fenêtre suivante, il est possible d’exporter un certificat.

Enfin pour importer le certificat dans la JVM il faut exécuter cette commande :

keytool -keystore $JAVA_HOME/jre/lib/security/cacerts -file certificat.crt -alias certificat

Le mot de passe par défaut est “changeit”.

Astuce

Pour débugger une conversation SSL, il faut ajouter l’option JVM suivante : -Djavax.net.debug=all

Maven et SeamTest

By , 22/03/2011

L’intégration des tests unitaires SeamTest dans un projet Maven est assez compliquée. Voici un exemple concret :

Présentation du projet

Avant de rentrer dans des détails techniques, je préfère vous parler de l’application qui va me servir de base pour intégrer mon test SeamTest.

Vision fonctionnelle

J’ai choisi de me baser sur l’exemple “hello world” du livre Seam Framework: Experience the Evolution of Java EE 2nd edition. Vous pouvez retrouver les sources des exemples du livre à l’adresse suivante : http://solutionsfit.com/blog/books/. Malheureusement, l’auteur utilise Ant et non Maven pour gérer la compilation de ses projets.

J’ai rajouté l’utilisation d’un service EJB Stateless pour démontrer la possibilité d’utiliser SeamTest dans un contexte technique hétérogène. Voici le diagramme des cas d’utilisation de l’application :

Cas d'utilisation de l'application

Vision maven

Le projet est composé d’un module père ayant trois modules fils :

seamtest-parent
|– seamtest-ear
|– seamtest-ejb
`– seamtest-webapp

Vous pouvez checkouter les sources à l’adresse suivante : https://subversion.assembla.com/svn/everythingiswrong/seamtest-parent/.

Dans le reste de l’article, je vais me focaliser sur le module seamtest-ejb car c’est lui qui contient le composant Seam, la persistance et l’EJB Stateless à tester.

Composant Seam à tester

Nous allons tester le composant qui va :

  • Enregistrer une nouvelle personne dans la base de données
  • Rechercher toutes les personnes de la base de données
@Stateful
@Name("manager")
public class ManagerAction extends Manager {
  @In
  private Person person;

  @Out
  private List<Person> fans;

  @EJB
  private CalculService calculService;

  @PersistenceContext
  private EntityManager em;

  //Méthode à tester.
  public void sayHello () {
    em.persist (person);
    fans = em.createQuery("select p from Person p").getResultList();
  }

  // Méthode pour vérifier l'injection de l'EJB Stateless dans le composant Seam
  public int additionner(int a, int b) {
    return (int) calculService.addition(a, b);
  }

  @Remove
  @Destroy
  public void destroy() {
  }
}

Installation et configuration

Pour information, SeamTest utilise le serveur JBoss embedded.

Installation de JBoss Embedded

Cette installation se résume à la copie du répertoire booststrap qui est dans la distribution de Seam (par exemple ici) dans le répertoire src/test.

Le fichier “pom.xml”

Ce fichier doit contenir l’ensemble des librairies qui vont permettre de démarrer et d’exécuter le serveur JBoss embedded. Il doit aussi prendre en compte le répertoire de bootstrap ajouté précédemment dans les ressources des tests.

<dependencies>
  ...
  <!-- dépendances des tests unitaites : http://community.jboss.org/thread/18299 -->
  <!-- dependencies related to JBoss Embedded for Seam 2.X.X -->
  <dependency>
    <groupId>org.jboss.seam.embedded</groupId>
    <artifactId>jboss-embedded-all</artifactId>
    <version>beta3.SP12</version>
    <scope>test</scope>
    <exclusions>
      <exclusion>
        <groupId>org.jboss.microcontainer</groupId>
        <artifactId>jboss-deployers-client-spi</artifactId>
      </exclusion>
      <exclusion>
        <groupId>org.jboss.microcontainer</groupId>
        <artifactId>jboss-deployers-core-spi</artifactId>
      </exclusion>
    </exclusions>
  </dependency>
  <dependency>
    <groupId>org.jboss.seam.embedded</groupId>
    <artifactId>hibernate-all</artifactId>
    <version>beta3.SP12</version>
    <scope>test</scope>
  </dependency>
  <dependency>
    <groupId>org.jboss.seam.embedded</groupId>
    <artifactId>thirdparty-all</artifactId>
    <version>beta3.SP12</version>
    <scope>test</scope>
  </dependency>

  <!-- dependencies related to JBoss MicroContainer -->
  <!-- java.lang.NoClassDefFoundError: javax/faces/application/Application -->
  <dependency>
    <groupId>javax.faces</groupId>
    <artifactId>jsf-api</artifactId>
    <version>1.2_09</version>
    <scope>test</scope>
  </dependency>

  <!-- java.lang.NoClassDefFoundError: org/jboss/el/ExpressionFactoryImpl -->
  <dependency>
    <groupId>org.jboss.el</groupId>
    <artifactId>jboss-el</artifactId>
    <version>1.0_02.CR4</version>    <!-- http://seamframework.org/Community/IllegalAccessErrorAfterUpgradingTo212CR1 -->
    <scope>test</scope>
  </dependency>

  <!-- dependencies related to TestNG -->
  <dependency>
    <groupId>org.testng</groupId>
    <artifactId>testng</artifactId>
    <version>5.8</version>
    <classifier>jdk15</classifier>
    <scope>test</scope>
  </dependency>
</dependencies>
<build>
  <testResources>
    <testResource>
      <directory>src/test/resources</directory>
      <filtering>true</filtering>
    </testResource>
    <testResource>
      <directory>src/test/bootstrap</directory>
      <filtering>false</filtering>
    </testResource>
    <testResource>
      <directory>src/test/bootstrap</directory>
      <filtering>true</filtering>
      <includes>
        <include>**/*.xml</include>
      </includes>
    </testResource>
  </testResources>
  ...
</build>

Remarque : à l’heure actuelle la version la plus récente du conteneur est la beta3.SP12.

Fichiers de tests

Dans la pratique, on ajoute toujours un fichier seam.properties vide dans le classpath des jar contenant des composants Seam. Dans le cas du test, ce fichier doit contenenir au minimum l’information sur le nom JNDI des EJB :

org.jboss.seam.core.init.jndiPattern = #{ejbName}/local

La classe de test doit étendre SeamTest. Elle peut ensuite utiliser l’EL pour référencer les composants Seam :

public class ManagerActionTest extends SeamTest {
  private static Logger LOGGER = Logger.getLogger(ManagerActionTest.class);

  @Test
  public void testSayHello() {
    try {
      new ComponentTest() {
        @Override
        protected void testComponents() throws Exception {
          setValue("#{person.name}", "Yan");
          invokeMethod("#{manager.sayHello}");
          List<Person> fans = (List<Person>) getValue("#{fans}");
          assertNotNull(fans);
          assertEquals(1, fans.size());
          assertEquals("Yan", fans.get(0).getName());
          // Test le service EJB
          assertEquals(3, invokeMethod("#{manager.additionner(1, 2)}"));
        }
      }.run();
    } catch (Exception e) {
      LOGGER.error("TEST KO : " + e.getMessage());
      fail("TEST KO : " + e.getMessage());
    }
  }
}

En utilisant Hibernate, vous pouvez exécuter des scripts SQL au déploiement de votre test en ajoutant un fichier import.sql dans le classpath de test (src/test/resources). Cela dit,  dans ce cas, je conseillerai plutôt d’utiliser l’intégration avec DBUnit.

Exécution

Pour exécuter les tests il faut lancer la commande mvn clean test.

Variantes

Intégration avec DBUnit

L’intégration est possible entre seamTest et DBUnit. La classe de test doit étendre DBunitSeamTest et implémenter la méthode prepareDBUnitOperations(). Il faut aussi donner à TestNg la nom JNDI de la source de données vers la base de données ainsi que le type de la base de données (HSQL ou MYSQL). Pour cela, il faut configurer le plugin surefire comme cela :

<build>
  ...
  <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>2.4.3</version>
    <configuration>
      <systemProperties>
        <property>
          <name>datasourceJndiName</name>
          <value>java:/DefaultDS</value>
        </property>
        <property>
          <name>database</name>
          <value>HSQL</value>
        </property>
      </systemProperties>
      <argLine>-Dsun.lang.ClassLoader.allowArraySyntax=true</argLine>
    </configuration>
 ...
</build>

Remarque : deux propriétés pour déclarer le type de la source de données et son nom JNDI ainsi qu’un argument pour permettre au serveur JBoss Embedded de s’éxécuter avec une JDK 1.6 (par défaut ce serveur n’est compatible qu’avec une JDK1.5).

Pour information, DBUnit propose deux implémentations différentes pour décrire les données d’une base : le FlatXmlDataSet et le XmlDataSet (http://dbunit.sourceforge.net/components.html).  SeamTest ne support que le FlatXmlDataSet.

Dépendances sur des projets ou modules de type EJB

Dans le cas où votre module dépende d’un autre module EJB, il faut arriver à déployer la dépendance de type EJB dans le conteneur JBoss embedded. Il est possible de faire cette opération avec le plugin maven maven-dependency-plugin comme cela :

<build>
  ...
  <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-dependency-plugin</artifactId>
    <executions>
      <execution>
        <id>copy</id>
        <phase>process-test-resources</phase>
        <goals>
          <goal>copy</goal>
        </goals>
        <configuration>
          <artifactItems>
            <artifactItem>
              <groupId>...</groupId>
              <artifactId>...</artifactId>
              <version>...</version>
              <type>...</type>
              <classifier>...</classifier>
              <overWrite>false</overWrite>
              <outputDirectory>${project.build.directory}/test-classes/deploy</outputDirectory>
            </artifactItem>
          </artifactItems>
        </configuration>
      </execution>
    </executions>
  </plugin>
  ...
</build>

Remarque : la copie de la dépendance se déroule avant la phase d’exécution des 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/).

Profiler une application J2EE avec JBoss et TPTP

By , 10/03/2011

Cet article va vous expliquer comment utiliser Eclipse pour vérifier les performances d’une application sous JBoss. Je vous laisserai découvrir les écrans de reporting par vous même car ils dépendent de votre code source.

Installation

Il est nécessaire d’installer les plugins suivant dans eclipse :

Puis il faut créer un serveur JBoss depuis la vue Server.

TPTP

JBoss TPTP

Exécution

Pour exécuter le profilage, il faut démarrer votre serveur JBoss avec le bouton Profile. Eclipse vous demande de choisir le type d’informations à mesurer. Une seule possibilité à la fois (je n’ai pas encore compris pourquoi je ne peux pas avoir plusieurs data collector en même temps…) :

Avant de cliquer sur le bouton Finish, n’hésitez pas à ajouter ou modifier les filtres par défaut en double-cliquant sur Java Profiling. Cela va vous permettre de focaliser votre attention sur votre code et non celui des librairies tierces que vous utilisez :

Après le démarrage de votre serveur en mode profile, le collecteur de données se synchronise à intervalle de temps régulier. Pour éviter d’enregistrer des informations inutiles, vous pouvez le mettre en pause par exemple.

Problèmes rencontrés et astuces

JRebel

Il faut savoir que JRebel ne fonctionne pas lorsqu’on utilise TPTP. Donc si vous utilisez cet outil, il faudra le désactiver (démarrer votre serveur JBoss sans les paramètres JRebel) pour pouvoir profiler votre application.

Profiles indisponibles

Si lorsque vous essayez de démarrer votre serveur en mode profile vous avez une exception vous parlant de collecteur de données, vérifier que vos plugins soient bien à jour.

Performances

TPTP est très gourmand en mémoire donc ne vous étonnez pas de voire les performances de votre application chuter rapidement. J’ai aussi remarqué que les performances d’éclipse s’effondrent rapidement lors de l’analyse des données quand celles-ci sont très volumineuses.

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/

find -exec

By , 21/02/2011

Je ne sais jamais comment utiliser la commande Unix find pour exécuter une autre commande sur la base des fichiers trouvés. C’est une commande très pratique et puissante. Donc un échec se traduit forcément par une grande frustration.

En lisant l’explication du manuel (man find), je comprends rapidement le principe suivant : lorsqu’un fichier est trouvé, la commande suivant l’option -exec est exécutée. Il faut échapper les caractères spéciaux comme le point virgule de fin de commande pour éviter qu’ils ne soient interprétés par le shell lui même. Enfin, les caractères {} servent à utiliser le fichier trouvé par la commande find. Par exemple, voici comment déplacer tous les fichiers .txt d’un répertoire vers un autre :

Il y a trois fichiers txt et un fichier log dans le répertoire test. Le répertoire test2 est vide :

*@*:/home/*$ ll test
total 0
-rwxrwxrwx 1 root root 0 2011-02-20 23:28 txt1.log
-rwxrwxrwx 1 root root 0 2011-02-20 23:27 txt1.txt
-rwxrwxrwx 1 root root 0 2011-02-20 23:28 txt2.txt
-rwxrwxrwx 1 root root 0 2011-02-20 23:28 txt3.txt
*@*:/home/*$ ll test2/
total 0
*@*:/home/*$ find test/ -name *.txt
test/txt1.txt
test/txt2.txt
test/txt3.txt

Pour déplacer les fichiers txt du répertoire test vers le répertoire test2 on utilise la commande mv :

*@*:/home/*$ find test/ -name *.txt -exec mv {} test2/ ;

On vérifie l’opération :

*@*:/home/*$ ll test
total 0
-rwxrwxrwx 1 root root 0 2011-02-20 23:28 txt1.log
*@*:/home/*$ ll test2/
total 0
-rwxrwxrwx 1 root root 0 2011-02-20 23:27 txt1.txt
-rwxrwxrwx 1 root root 0 2011-02-20 23:28 txt2.txt
-rwxrwxrwx 1 root root 0 2011-02-20 23:28 txt3.txt

OfficeFolders theme by Themocracy