Auteur : Eric

Fusion de fichiers PDF

Le format de fichiers pdf est l’un des plus répandus à l’heure actuelle.

En effet, il permet de transmettre des documents en étant sûr :

  • qu’ils seront lisibles à l’arrivée (il existe des lecteurs de fichiers pdf pour la quasi totalité des plateformes existantes à l’heure actuelle)
  • que le formatage sera conservé (pas de problème de mise en page, de polices manquantes,…).%%%

Nous pouvons donc être amenés à générer ou manipuler des fichiers au format pdf au sein de nos applications, et notamment à rassembler plusieurs fichiers pdf en un seul, pour en faciliter l’impression ou l’envoi par e-mail.

Pour cela, nous utilisons la librairie iText, qui est l’une des plus répandues pour la génération et la manipulation de fichiers pdf en Java.

Par exemple, fusionner deux documents nommés « fichierEntree1.pdf » et « fichierEntree2.pdf », et les sauvegarder dans un fichier nommé « fichierSortie.pdf » est réalisé grâce au code suivant :

Document document = new Document();
PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream("fichierSortie.pdf"));
PdfReader pdfr = new PdfReader("fichierEntree1.pdf");
PdfReader pdfr2 = new PdfReader("fichierEntree2.pdf");
document.open();
PdfContentByte cb = writer.getDirectContent();
for (int i=1; i<=pdfr.getNumberOfPages(); i++) {
document.newPage();
cb.addTemplate(writer.getImportedPage(pdfr, i),0,0);
}
for (int i=1; i<=pdfr2.getNumberOfPages(); i++) {
document.newPage();
cb.addTemplate(writer.getImportedPage(pdfr2, i),0,0);
}
document.close();

Enquête sur l’utilisation des méthodes agiles en France

Le Scrum User Group France vient de lancer une enquête sur l’utilisation des méthodes agiles en France :

Nous avons pour ambition de faire une photographie la plus juste possible de l’adoption et de l’utilisation des méthodes agiles en France ainsi que le niveau de satisfaction des praticiens.
Pour qu’elle soit significative, nous souhaitons qu’un maximum d’entreprises utilisatrices répondent.
Pour cette raison, nous sollicitons votre aide afin d’y répondre bien entendu mais aussi par le biais de la diffusion de cette enquête à d’autres utilisateurs qui pourraient partager leur expérience en répondant au questionnaire.

L’enquête se trouve ici, la réponse ne prend pas plus de 5 minutes.

Vous pouvez désigner Karine Mazet comme marraine, elle n’a pas encore de Wii :).

Tomcat : utilisation de multi instances

Nous utilisons Tomcat comme moteur de Servlet.

L’installation d’un Tomcat standard est assez simple, mais on en atteint très vite les limites.
En effet, selon l’environnement, on va avoir besoin de plusieurs instance de Tomcat ; par exemple, pour toute la phase en amont de la pré-prod / prod, on souhaite gérer des environnements d’intégration, de recettte, de montée en charge, …

La première solution est de multiplier les installations de Tomcat. C’est très simple à mettre en place , mais lorsque l’on change de version du serveur, on doti modifier toutes les installations.

Une autre solution assez simple apportée par Tomcat, est la possibilité de définir plusieurs instances de Tomcat pour une même installation. Nous allons décrire dans ce billet comment le mettre en place :

  • La première chose à faire est de définir un scipt de démarrage/arrêt par instance de Tomcat.
    • On crée un fichier $TOMCAT_HOME/bin/startupMonInstance.sh qui sera identique au startup.sh auquel on ajoute :
    • (le chemin peut être complètement indépendant de l’arborescence Tomcat)
      On peut également modifier les paramètres de la JVM de chaque instance en ajoutant dans ce script la variable CATALINA_OPTS.
    • Et un fichier $TOMCAT_HOME/bin/shutdownMonInstance.sh qui sera identique au shutdown.sh auquel on ajoute :
  • On copie les fichiers de configuration $TOMCAT_HOME/conf/*.* dans le répertoire monInstance/conf
  • On modifie les ports du fichier monInstance/conf /server.xml pour pouvoir lancer les différents tomcats en même temps.

Au démarrage de chaque instance, Tomcat se charge de créer les répertoires manquants, notamment le webapps.

GWT et PureMVC

Utilisation de PureMVC

La mise en œuvre d’une application RIA robuste, maintenable, réutilisable et évolutive nécessite l’utilisation des modèles de conceptions éprouvés. Notre application est réalisée en GWT basée sur une architecture multi-couche. Voici quelques unes des exigences auxquelles doit répondre notre application :

  • Faible couplage entre les différentes couches,
  • Chaque composant de l’application doit avoir un rôle clair et précis,
  • Accès transparent à des services distants ou co-localisés,
  • Une mise en cache des données utilisées fréquemment afin d’accroître les performances.

Afin de répondre à ces exigences, notre choix s’est porté sur le framework PureMVC. Ce framework met en œuvre le méta Pattern MVC. Il permet de découpler vues et modèles en instaurant entre eux un protocole d’échanges basé sur le pattern Observateur. Ce modèle de conception établit un type d’interaction Diffusion / Souscription.

Le framework PureMVC permet de séparer la couche Vue de notre application en trois tiers bien distincts : le modèle, la vue et le contrôleur. Ces trois tiers sont mis en œuvre par trois classes appelées ModelView et Controller. Elles constituent les acteurs centraux du framework. Ces acteurs collaborent entre eux par le biais d’une Façade.
La classe Façade détient les références des trois acteurs centraux. Chaque acteur est couplé avec des collaborateurs. La façade initialise les acteurs centraux et procède à une phase d’enregistrement des collaborateurs :

  • Model — registerProxy (<IProxy>)
  • Vue — registerMediator (<IMediator>)
  • Controller — registerCommand(<notificationName>, <ICommand>)

Le modèle détient des références des classes Proxy. Chaque proxy communique avec des services distants et sert de cache des données fréquemment utilisées. La vue détient des références des classes Mediator. Un médiateur représente des composants visuels. Enfin le contrôleur détient des références des classes Command. Les commandes peuvent interagir directement avec des classes Proxy ou envoyer des notifications.

Voici un schéma qui illustre la manière dont sont orchestrés les échanges entre les différents acteurs du framework PureMVC :

PureMVC

L’Esprit Agile a soufflé

L’Esprit Agile a soufflé sur Marseille ce Mardi 17 Mars dans l’Amphi de l’ECM.

Ce premier évènement du genre dans la région a été une belle réussite avec un peu plus de 80 personnes présentes.
Nous remercions encore une fois tous les participants, intervenants, partenaires et bien sûr les étudiants de l’ECM avec qui nous avons organisé cette rencontre.

Equipe

Merci à Jean-Marie pour les photos

Les présentations et vidéo seront disponibles la semaine prochaine sur le site de l’Esprit Agile.

Nous espérons ne pas en rester à cet évènement ponctuel, mais fédérer des utilisateurs de méthodes agiles ou les personnes et entreprises intéressées au sein d’une association dont le but serait de favoriser les échanges et la mise en place de méthodes agiles.

Je vous invite donc à nous contacter si cette démarche vous intéresse, cela nous permettra de pousser un peu plus cette démarche.

Lire un fichier dont on ne connaît pas l’encodage

Lorsque l’on développe une application, on est souvent amené à lire des fichiers provenant de diverses sources (utilisateurs, autres programmes,…), et dont on ne connaît pas forcément le format, notamment l’encodage.

Java ne fournit pas en standard de moyen de détecter l’encodage d’un fichier, mais grâce aux nombreuses librairies externes disponibles, il est possible de résoudre ce problème.

Nous avons, pour notre part choisi d’utiliser la librairie ICU, développée par IBM, et ce pour plusieurs raisons :

  • c’est une librairie très répandue, et utilisée par de nombreux projets majeurs (gage de sa fiabilité)
  • elle est distribuée sous une licence open source non restrictive, et soutenue par IBM (gage de sa pérennité)
  • nous utilisons BIRT à l’intérieur de notre application, qui dépend lui-même d’ICU, et nous avions donc déjà cette librairie au sein de notre projet.

Voici comment nous l’utilisons dans l’application :

String fileName = "...";
final CharsetDetector detector = new CharsetDetector();
detector.setText(new BufferedInputStream (new FileInputStream(fileName)));
Reader fileReader = detector.detect().getReader();

En faisant cela, nous obtenons donc un reader classique java, qui nous permettra de lire le fichier sans se préoccuper de l’encodage, et de ne pas avoir de problème avec le traitement des caractères non ASCII.
Dans cet exemple, l’utilisation d’un BufferredInputStream est nécessaire, en effet, ICU va lire une partie du fichier pour déterminer l’encodage, puis revenir au début du fichier grâce à la méthode reset() lorsqu’on lui demande un reader, méthode que l’on ne peut pas utiliser sur un FileInputStream.

Compilation GWT et gestion de la mémoire

Nous utilisons le plugin maven googlewebtoolkit2, pour compiler notre application GWT, sans paramétrage spécifique ou optimisation.

La taille de l’application devenant de plus en plus importante, nous sommes tombés sur un classique

java.lang.OutOfMemoryError: PermGen space.

Premier problème trouver comment modifier les paramètres de la JVM.

Il suffit de rajouter dans la configuration du plugin la balise extraJvmArgs

Malgré une augmentation de l’espace mémoire alloué, nous avions toujours la même erreur (des 32Mo par défaut à 1024Mo). Nous avons donc essayé de jouer sur les autres paramètres impactant le PermGen space. Et en rajoutant le –Xmn50M nous somme parvenu à compiler à nouveau l’application.


Mais nos espoirs ont été de courte durée…Nous nous sommes trouvés avec une compilation aléatoire qui passait de temps en temps…

Nous avons donc choisit de tester la compilation avec une JVM concurrente de celle de Sun : JRockit (initialement BEA, Oracle depuis 2008).
JRockit se veut plus performante que la JVM SUN. Il y a peu d’études intépendantes qui montrent les apports réels en termes performance. Nous avons donc décidé de réaliser les tests nous même.
Suite à quelques essais, force est de constater qu’avec cette JVM nous avons une compilation qui fonctionne sans aucun problème toutes les nuits avec un temps de traitement légèrement inférieur.

ViaXoft correspondant du SUG en région PACA

Nous avons le plaisir d’être le correspondant (ou plutôt la correspondante en la personne de Karine  smile SUG ) du French SUG en région PACA.

Le French Scrum User Group est un groupe d’utilisateurs de Scrum en France, où vous pouvez venir échanger sur Scrum et les méthodes agiles, et partager vos expériences sur vos projets. Ce groupe est parrainé par Jeff Sutherland, l’un des pères fondateurs de Scrum, et par la Scrum Alliance.

Hibernate : mapping d’une colonne en Set

Le mapping avec Hibernate

L’utilisation d’une relation many-to many avec hibernate permet de rendre transparent la table d’association.

Dans l’exemple suivant, la table EDITION_LIVRE sera mappée de manière transparente :
Livre Many Many Hibernate
La mapping de la table LIVRE sera le suivant :

‹set name="editions" table="EDITION_LIVRE"›
‹key column="LIVRE_ID" /›
‹many-to-many column="EDITION_ID" /›
‹/set›

Et Livre contiendra un Set<Edition>, mais l’objet EditionLivre n’existera pas…

A la vue de ce type de mapping, on peut être intéressé de faire la même chose pour un mapping many to one.
En effet, plutôt que de me retrouver avec un Set d’objet dont nous n’avons besoin que pour de l’affichage, nous préférerions avoir un Set de String. Par exemple, si on prend une relation de ce type :

Livre Set Hibernate
Et qu’on ne veut pas avoir à mapper l’objet LivreMotcle, il suffit de définir dans le fichier de mapping Livre le Set suivant :

‹set name=”mots" table="LIVRE_MOTCLE"›
‹key column="LIVRE_ID" /›
‹element column="MOT" type="string"/›
‹/set›

On obtient alors un Set<String> mots dans l’objet Livre.

Comparaison de chaines grâce à un Collator

Utiliser un Collator pour la comparaison de chaines

Lors de la manipulation de données, il est souvent nécessaire de comparer des chaines de caractère, pour réaliser des tris par exemple. Cependant, plusieurs problèmes peuvent se poser, comme la différence de casse et la présence de lettres diacritées (possédant un accent ou une cédille, par exemple).

Si pour les problèmes de casse, il est possible de s’en sortir avec les méthodes equalsIgnoreCase() et compareToIgnoreCase() de la classe String, il n’en va pas de même pour les problèmes de diacritiques. En effet, non seulement il est très difficile de prévoir tous les cas, mais en plus ce problème est dépendant de la langue utilisée (alors qu’il y a moins de 20 mots comportant des diacritiques en anglais, la quasi-totalité des mots vietnamiens en comportent).

Heureusement, Java propose un outil nommé Collator (du verbe anglais « to collate », ordonner, ranger, vérifier l’ordre) permettant de gérer ce problème de façon simple. En effet, le Collator permet de faire une comparaison intelligente en tenant compte de la locale, mais aussi des diacritiques et de la casse.

Voici un petit exemple pour illustrer son fonctionnement :

package com.viaxoft.test.collator;import java.text.Collator;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Locale;public class TestCollator {
public static void main (String [] args) {
final List pays = new ArrayList ();
pays.add("zimbabwe");
pays.add("angola");
pays.add("Australie");
pays.add("Zambie");
pays.add("éthiopie");
pays.add("États-Unis");
pays.add("Égypte");
pays.add("Sénégal");
pays.add("Serbie");Collections.sort(pays);
printTitle("Tri par défaut");
printList(pays);
Collections.sort(pays, new Comparator () {
public int compare(String o1, String o2) {
return o1.compareToIgnoreCase(o2);
}
});
printTitle("Tri en ignorant la casse");
printList(pays);

final Collator frCollator = Collator.getInstance(Locale.FRENCH);
Collections.sort(pays, new Comparator () {
public int compare(String o1, String o2) {
return frCollator.compare(o1, o2);
}
});
printTitle("Tri avec un Collator");
printList(pays);

frCollator.setStrength(Collator.TERTIARY);
printTitle("Comparaison avec un Collator "TERTIARY"");
compareWithCollator ("egypte", "egypte", frCollator);
compareWithCollator ("Egypte", "egypte", frCollator);
compareWithCollator ("égypte", "egypte", frCollator);
compareWithCollator ("Égypte", "egypte", frCollator);
compareWithCollator ("Égypte", "Sénégal", frCollator);

frCollator.setStrength(Collator.SECONDARY);
printTitle("Comparaison avec un Collator "SECONDARY"");
compareWithCollator ("egypte", "egypte", frCollator);
compareWithCollator ("Egypte", "egypte", frCollator);
compareWithCollator ("égypte", "egypte", frCollator);
compareWithCollator ("Égypte", "egypte", frCollator);
compareWithCollator ("Égypte", "Sénégal", frCollator);

frCollator.setStrength(Collator.PRIMARY);
printTitle("Comparaison avec un Collator "PRIMARY"");
compareWithCollator ("egypte", "egypte", frCollator);
compareWithCollator ("Egypte", "egypte", frCollator);
compareWithCollator ("égypte", "egypte", frCollator);
compareWithCollator ("Égypte", "egypte", frCollator);
compareWithCollator ("Égypte", "Sénégal", frCollator);
}

private static void printTitle (final String title) {
System.out.println("");
System.out.println(title);
System.out.println(title.replaceAll(".", "-"));
}

private static void printList (final List list) {
int i=1;
for (String str : list) {
System.out.println(i+". "+str);
i++;
}
}

private static void compareWithCollator (final String str1, final String str2, final Collator collator) {
if (collator.equals(str1, str2))
System.out.println(str1+"=="+str2);
else
System.out.println(str1+"!="+str2);
}
}

 

Et le résultat de l’exécution de ce programme :

Tri par défaut

  1. Australie
  2. Serbie
  3. Sénégal
  4. Zambie
  5. angola
  6. zimbabwe
  7. Égypte
  8. États-Unis
  9. éthiopie

Tri en ignorant la casse

  1. angola
  2. Australie
  3. Serbie
  4. Sénégal
  5. Zambie
  6. zimbabwe
  7. Égypte
  8. États-Unis
  9. éthiopie

Tri avec un Collator

  1. angola
  2. Australie
  3. Égypte
  4. États-Unis
  5. éthiopie
  6. Sénégal
  7. Serbie
  8. Zambie
  9. zimbabwe

Comparaison avec un Collator « TERTIARY »
egypte==egypte
Egypte!=egypte
égypte!=egypte
Égypte!=egypte
Égypte!=Sénégal

Comparaison avec un Collator « SECONDARY »
egypte==egypte
Egypte==egypte
égypte!=egypte
Égypte!=egypte
Égypte!=Sénégal

Comparaison avec un Collator « PRIMARY »
egypte==egypte
Egypte==egypte
égypte==egypte
Égypte==egypte
Égypte!=Sénégal

Comme on s’y attendait, la liste des pays n’est pas triée correctement avec les comparateurs de base de la classe String, mais l’est avec le Collator.
Cet exemple montre également l’influence de la propriété « strength » (force, puissance en anglais) sur le test d’égalité du collator : en « TERTIARY », on tient compte de la casse et des diacritiques, en « SECONDARY » seulement des diacritiques, et en « PRIMARY » ni de l’un ni de l’autre. Il faudra donc également prendre en compte ce paramètre lors de l’utilisation d’un Collator, et le choisir en fonction du besoin.

Loading...
X