Le coin du développeur

Mon premier plugin ElasticSearch : RSS River

by on sept.14, 2011, under CouchDB, Divers, Elastic Search, Java, Maven

Il existe dans ElasticSearch la notion de river (rivière) qui comme son nom le laisse supposer permet de voir s’écouler des données depuis une source jusqu’à ElasticSearch.

Au fur et à mesure que les données arrivent, la rivière les transporte et les envoie à l’indexation dans Elastic Search.

En standard, il existe 4 rivières :

  • CouchDB qui permet d’indexer toutes les nouveautés d’une base CouchDB. Voir aussi cet article à ce propos.
  • RabbitMQ qui permet de récupérer des documents dans une queue de traitement asynchrone (genre JMS)
  • Twitter qui permet d’indexer votre flux de messages twitter par exemple
  • Wikipedia qui permet d’indexer toutes les nouveautés de l’encyclopédie au fur et à mesure de leurs publications

Premiers pas

J’ai commencé par bidouiller un peu la rivière CouchDB pour y apporter quelques fonctionnalités dont mes collègues avaient besoin :

Finalement, le principe se révèle assez simple. Il faut une classe qui implémente River et qui hérite de AbstractRiverComponent.

Là, il ne reste plus qu’à implémenter :

  • Le constructeur
  • La méthode start qui se lance quand la rivière démarre
  • La méthode close qui se lance lorsque la rivière stoppe

Et mon flux RSS alors ?

Oui… J’y viens…

Au fait, tout le monde sait ce qu’est un flux RSS ? La spécification officielle est ici.

Je reprends donc le plugin CouchDB River, je le mavenise (ouais, je ne suis pas encore super fan de Gradle), et je l’adapte à mes besoins.

Pour faire simple, je vais suivre la mécanique suivante :

  • Toutes les x minutes, je télécharge le flux RSS demandé que je transforme en POJO en me basant sur le travail fait par Lars Vogel
  • Je compare la date du flux (balise pubDate) avec la dernière date de flux (que j’avais stockée dans ElasticSearch)
  • Si le flux est plus récent, je parcours tous les éléments du flux (item)
    • Je fabrique un identifiant de l’item basé sur un encodage du champ description. Pour cela, je me sers de ce qui est déjà présent dans ES.
    • Si cet identifiant a déjà été envoyé à ES, alors on ignore cet item.
    • Sinon, on le pousse vers ElasticSearch dans un document de type « page »

Les champs récupérés pour le moment dans le flux RSS sont :

  • title
  • description
  • author
  • link

Ca marche ?

Mes profs en école d’ingé me disaient : « non ! ça fonctionne… »

Bon, une fois le plugin publié sous github, il est simple de l’utiliser.

Tout d’abord, on l’installe :

$ bin\plugin -install dadoonet/rssriver/0.0.1

Puis, on démarre ES et on créé notre index pour stocker le flux RSS :

$ curl -XPUT 'http://localhost:9200/lemonde/' -d '{}'

Puis on ajoute la rivière :

$ curl -XPUT 'http://localhost:9200/_river/lemonde/_meta' -d '{
  "type": "rss",
  "rss": {
    "url": "http://www.lemonde.fr/rss/une.xml"
  }
}'

Et voilà…

A partir de ce moment, on peut faire des recherches dans le flux… Par exemple :

$ curl –XGET 'http://localhost:9200/lemonde/_search?q=taxe'

On peut jouer sur les paramètres de la rivière en modifiant les paramètres url pour l’adresse du flux et update_rate pour la fréquence de mise à jour du flux (en millisecondes).

Egalement, il peut être souhaitable (conseillé) de modifier le mapping par défaut du type « page » :

$ curl -XPUT 'http://localhost:9200/lefigaro/' -d '{}'

$ curl -XPUT 'http://localhost:9200/lefigaro/page/_mapping' -d '{
  "page" : {
    "properties" : {
      "title" : {"type" : "string", "analyzer" : "french"},
      "description" : {"type" : "string", "analyzer" : "french"},
      "author" : {"type" : "string"},
      "link" : {"type" : "string"}
    }
  }
}'

$ curl -XPUT 'localhost:9200/_river/lefigaro/_meta' -d '{
  "type": "rss",
  "rss": {
    "url": "http://rss.lefigaro.fr/lefigaro/laune",
    "update_rate": 900000
  }
}'

Et maintenant ?

Que vais-je faire de tout ce temps ? Que sera ma vie ?

J’envisage de faire une nouvelle évolution du plugin CouchDB car pour le moment, il ne traite pas la récupération des pièces jointes (format binaire).

Et bien évidemment, poursuivre sur le plugin RSS River qui doit traiter d’autres balises et être testé avec d’autres flux…

D’ailleurs, si vous l’utilisez et que vous rencontrez des problèmes, n’hésitez pas à contribuer en créant des bugs ou en forkant et améliorant le projet.

Les sources sont ici : https://github.com/dadoonet/rssriver

 

 

Leave a Comment :, , , , , , more...

ElasticSearch et les « facets »

by on juin.20, 2011, under Elastic Search, Java

Les aventures avec ElasticSearch se poursuivent.

Combien de fois ai-je dit récemment que ce projet est absolument génial et qu’il va constituer à mon sens un des projets majeurs des prochaines années…

Qui n’a pas besoin de moteur de recherche ? Qui s’est déjà « emmerdé » à fabriquer ça lui-même ou à utiliser des briques pouvant aider au prix d’une complexité plus ou moins grande de mise en oeuvre ?

Je crois que nous sommes tous passés par là !!!

Et là, ce projet permet en quelques heures (minutes) de faire tourner un moteur de recherche complet…

Les facettes (facets)

Bref, là n’est pas mon propos d’aujourd’hui. Le thème du jour est la notion de facets. Je l’ai testé en quelques minutes sur une base de 1,5 millions de documents indexés à mon boulot. Résultat bluffant !

Une facette permet d’ajouter des informations à un résultat de recherche. Imaginez un site marchand. Vous cherchez un ou plusieurs mots, par exemple : rasoir.

Le site vous fournit une liste des éléments correspondants et en général ajoute des informations pour vous aider à affiner votre recherche.

Par exemple, le nom des fabricants de ces produits avec le nombre d’objets trouvés pour les 10 principaux fabricants. Dans notre cas, on pourrait avoir par exemple :

  • Tous (134)
  • Philips (35)
  • Braun (21)
  • Calor (12)

Ce résultat qui décore notre résultat de recherche se nomme une facette (facet in english).

Il existe différents types de facettes. Celle dont nous venons de parler est une facette de type TERMS, c’est à dire qu’Elastic Search va renvoyer la distribution des 10 principaux termes trouvés pour une propriété donnée des documents par rapport à une requête.


{
"query" : {
"match_all" : {  }
},
"facets" : {
"tag" : {
"terms" : {
"field" : "tag",
"size" : 10
}
}
}
}

En passant une requête de ce type, on obtiendra la consolidation et le comptage associé de tous les principaux termes du champ tag de toute notre base de documents.

Il existe d’autres types de facettes très intéressantes :

  • les facettes RANGE : pour donner une distribution sur un intervale de valeurs. Par exemple, pour reprendre notre exemple de site marchand, vous pouvez utiliser la facette RANGE pour donner la distribution des prix pour les intervales de 0 à 10 €, de 10 à 20 €, de 20 à 50 € et au delà de 50 €.
  • les facettes DATE HISTOGRAM : pour donner un comptage avec un axe X des temps (période à décider : jour, mois, année, …). Par exemple, le nombre de vente par mois pour un produit donné.

La liste complète est disponible sur le site d’Elastic Search.

Et les résultats ?

Là où cela devient très fort, c’est que cette recherche s’exécute en temps réel, même sur des données « neuves » qui arrivent en permanence et avec un temps de réponse assez incroyable.

A titre d’exemple, sur la base de 1,5 millions de documents que je citais plus haut en début de document, j’ai pu ainsi faire un outil d’analyse rapidement (à peine 4 heures de boulot – et encore, c’est juste parce que je ne suis pas assez bon en Javascript !) sur des déclarations en douane. Ce qui est surprenant, c’est que sans avoir fait le moindre effort d’optimisation, nous avons pu regarder l’effet des saisons sur l’importation de tomates au fur et à mesure des années et sur les TOP 10 des pays d’importation !

Pour réaliser cela, je n’ai fait que suivre l’excellent article sur le blog d’elastic search. Je ne peux pas malheureusement pas vous montrer le résultat :-( Mais sachez que cela réagit en quelques secondes sur un poste bureautique avec peu de mémoire. Alors, imaginez si vous mettez cela en production avec 16 ou 32 Go de RAM distribué sur plusieurs noeuds !!!

Vous pouvez également utiliser le résultat des facettes comme point d’entrée ergonomique pour filtrer ensuite le résultat de vos recherches : un clic sur le nom du fabriquant du produit fera par exemple la même recherche dans Elastic Search avec en plus un filtre posé sur le nom du fabriquant.

Quelle(s) conclusion(s) en tirer ?

Bon, j’ai un peu bluffé dans mon premier exemple… La possibilité d’avoir la somme totale de tous les résultats ( Tous (134)  ) n’existe pas encore. Shay Banon, l’auteur du projet, a accepté ma demande d’évolution #1029 à ce sujet. Pour le moment, il faut faire un calcul à la main (enfin, en javascript je veux dire) !

Dans la même requête, vous pouvez associer plusieurs facettes d’un seul coup. Dans mon cas de démo au boulot, j’ai mis 5 facettes. Un appel = les 10 premiers résultats de ma recherche plus 5 facettes d’analyse des données…

Sinon, oubliez les requêtes SQL que vous faites tourner pendant quelques minutes pour vous fabriquer vos statistiques. Oubliez les moteurs de recherche en SQL (si ! si ! ça existe encore !). Je me demande du coup quel sera le devenir de projets comme Hibernate Search ? Même si avec la sortie d’Hibernate OGM, on sent une tentative astucieuse de garder la communauté des développeurs Hibernate. Pour ma part, j’avais commencé à écrire un plugin Hibernate pour Elastic Search mais finalement je l’ai supprimé de mon projet car il n’apporte quasiment que des contraintes pour le peu d’intérêt qu’il apporte. Une vraie novation pourrait être d’ajouter à Hibernate Search un stockage des données dans Elastic Search, mais Shay Banon a un point de vue divergent sur les annotations utilisées. Du coup, un projet (OSEM) soutenu par Shay a vu le jour grâce à l’excellent travail d’Aloïs Cochard. Une fois stabilisé, ce projet rejoindra le projet Elastic Search afin de proposer des annotations standards pour vos objets Java à rendre cherchables (Searchable).

De mon côté, je réfléchis au développement d’un simple plugin maven pour générer automatiquement les fichiers de mapping pour Elastic Search basés sur les entités annotées Searchable. A suivre donc !

Installez chez vous Elastic Search et testez juste en ligne de commande (avec des curl) ces fonctionnalités et dites vous que le petit résultat que vous observez sur quelques documents tient autant la route sur une forte volumétrie… C’est la puissance de Lucene associée à l’ingéniosité de l’auteur d’Elastic Search qui met ainsi à notre disposition un outil simple, basé sur des technos simples mais au combien efficace !!!

Je vous ai dit que j’adore ce projet ???? ;-)

9 Comments more...

CouchDB

by on mai.13, 2011, under CouchDB, Elastic Search

Après avoir testé ElasticSearch, me voici parti pour regarder ce monde étrange qu’on appelle le NoSQL

A dire vrai, j’ai entendu ce mot il y a quelques années, sans jamais vraiment m’y interesser… Après tout, une base de données non SQL, ça n’est tout simplement pas possible !!!

Puis, à force de cotoyer le monde d’ElasticSearch et les technos JSon et REST, je me lance.

Pour des raisons très pratiques, je choisis CouchDB de Apache. D’une part, il est directement intégrable avec ElasticSearch, et à la lecture rapide de sa documentation, il semble répondre à un des besoins auquel une équipe de mon pôle de développement est confrontée.

Notre besoin (résumé) :

  • Archiver des données de notre SI afin notamment de décharger les bases live (Front Office).
  • Historiser ces données
  • Y associer des pièces jointes (vues PDF et XML)
  • Etre en mesure d’y accéder facilement
  • Prévenir des consommateurs de ces documents qu’il y a des nouveautés à récupérer et à traiter (Décisionnel)
  • Etre en mesure de rechercher ces documents

Au début, les équipes ont pensé mettre en place des copies via des fichiers XML dans des répertoires partagés depuis les applications Front Office (live), puis des scripts shell pour recopie dans des espaces propres à chaque consommateur de données qui traitera ensuite les flux à son rythme. Sans entrer dans les détails, c’est un peu genre « je fais tout moi-même à la main, comme je l’aurais fait en 1995″…

Depuis le monde a un peu changé, non ?

Alors, que peut faire CouchDB pour nous :

  • Stocker des documents (format JSON)
  • Y associer des pièces jointes (PDF et XML)
  • Le tout avec un mode de transport simple : HTTP / REST
  • Gestion d’un flux type RSS pour informer n’importe qui de toutes les modifications apportées à la base
  • Gestion des révisions de chaque document
  • Non adhérence à un format particulier (contrairement aux SGBD-R)
  • Capacité de stockage et de montée en charge
  • Réplication ultra simple
  • Partitionnement

Bon, ça c’est sur le papier… Rien ne vaut un bon test…

On se lance donc avec un ami pour mettre en place une plate-forme de test.

Nous partons d’une base de données disposant de plusieurs millions d’enregistrements divers (sous Oracle). Notre objectif :

  • Les lire avec un DAO classique dans Oracle
  • JSONiser chaque entité
  • La transformer aussi en une vue XML (module déjà existant)
  • La transformer aussi en une vue PDF (nous avons déjà développé tout cela avant)
  • Envoyer le tout à CouchDB.

Il faut 5 minutes pour installer CouchDB (grand max !), 20 minutes pour comprendre que le firewall de Microsoft n’est pas notre ami et que nous avons intérêt à ouvrir le port CouchDB si nous voulons pouvoir communiquer avec CouchDB depuis une autre machine !

On lance le batch sur une machine et on envoie vers un CouchDB… Là, tranquille, au rythme de 15-20 documents par seconde, notre base se remplit petit à petit !

On consulte un document JSON ainsi : http://couchdb/index/ref000000001/

Si on veut prendre la version PDF, c’est beaucoup plus compliqué : http://couchdb/index/ref000000001/ref000000001.pdf

Je passe la version XML… C’est aussi compliqué !

 

Au bout de 50 000 documents, nous nous lançons un nouveau défi : répliquer sur une autre instance CouchDB.

Installation de CouchDB sur une autre machine. Cette fois, on ne perd pas de temps pour le firewall : on sait directement où enlever le blocage…

Puis on se connecte sur l‘interface de gestion de CouchDB et on demande une réplication de la première machine vers la deuxième… Il faut 10 secondes pour configurer cela. C’est vraiment trop simple pour fonctionner directement ! Mais, si ! Ca fonctionne !

La réplication commence… 20 à 50 documents répliqués par seconde… Le tout sur un PC assez lent. On est loin des conditions de PROD !

En même temps, notre BATCH continue à alimenter la première instance.

 

Arrivés à 100 000 documents, nous n’en n’avons pas assez !!!

Nous décidons de nous lancer un nouveau défi. Il nous reste 10 minutes avant une réunion de présentation de ces concepts à notre management. Nous avons largement le temps !

Alors, nous décidons de lancer un noeud ElasticSearch sur une machine et d’y ajouter le plugin river CouchDB. Puis nous activons ce plugin pour ouvrir une rivière (river) vers la première instance de CouchDB… Et là, encore un miracle… Nos documents se déversent sans aucun effort dans ElasticSearch.

Nous avons donc au final, au bout d’une demi journée d’efforts surhumains (fallait quand même développer le batch initial), atteint nos objectifs.

 

Reste à regarder cette histoire de flux RSS (sorte d’inscription aux nouveautés de la base). Cela est nativement porté par la fonction _changes de CouchDB. C’est absolument génial. Comme si vous aviez un trigger permanent et automatique sur chaque modification apportée dans la base. Avec la possibilité de faire un appel à _changes en précisant là où nous en étions la dernière fois que nous y avons fait appel (gestion différentielle), ou encore mieux, de façon continue, de laisser en permanence un flux HTTP ouvert dans lequel se déverse au fil de l’eau chaque changement apporté…

C’est vraiment bluffant et simplissime à l’usage.

 

C’en est tellement facile que cela paraît suspect…

Les prochains tests sont maintenant de faire monter la volumétrie à quelques millions de données pour voir comment cela se passe…

 

La suite au prochain numéro !

 

1 Comment :, , more...

La recherche élastique…

by on mar.09, 2011, under Elastic Search, Hibernate, Java

En cherchant un bout de code pour rendre la couche Hibernate Search facilement distribuable sur un cluster de machines JBoss, je suis tombé sur le projet ElasticSearch.

Au début, un peu interloqué… Puis, je me lance…

Je télécharge le projet. Je dézippe.

Je lance…

Miracle. En quelques secondes, je dispose d’un outil dans un Cloud, simple, me permettant d’indexer n’importe quel type de document, de le récupérer et de faire une recherche (au sens google du terme) sur n’importe quel champ… Et cela, quelque soit la technologie employée (Java, C#, .Net, Php, à la main, …).

La simplicité repose sur l’intégration de quelques technologies simples et éprouvées : JSon, REST, Lucene.

Là, où cela devient très fort, c’est lorsque vous démarrez sur une seconde machine dans le même réseau, une autre instance d’Elastic Search… Et là : réplication automatique. Votre nouvelle instance fait parti du Cloud…

Sans rien faire… Presque magique.

Lorsque vous montez encore 2 autres instances (ça peut être sur la même machine – les ports d’écoute s’adaptent automatiquement), alors Elastic Search réparti l’indexation sur plusieurs machines…

La Team est très active. Il suffit de regarder la fréquence des commits sur github. Elle fournit un composant Java simple à utiliser.

En deux lignes, on se connecte au cloud (sans trop savoir à quelle machine exactement, le principal étant de trouver un service), et on envoie nos demandes d’indexation ou de recherche…

Je vous recommande fortement de regarder de très près ce projet qui va rapidement s’imposer comme une référence.

Pour ma part, je travaille en ce moment à développer une méthode très simple pour interfacer automatiquement et de façon transparente l’indexation des entités gérées par Hibernate. L’idée est de pousser les entités Hibernate à chaque fois qu’elles sont insérées, mises à jour ou effacées vers Elastic Search plutôt que vers Hibernate Search. Le tout avec très peu d’annotations.

Plus d’informations dans quelques jours je pense…

4 Comments :, , more...

Installation FusionForge 5.0 sur Redhat 5

by on mai.11, 2010, under Divers

Voici la suite de l’article sur l’installation d’une forge.

Finalement, le temps d’obtenir une machine sous Redhat 5 a laissé le temps à la team FusionForge de sortir une release finale de la version 5.0.

Nous voilà donc lancés dans cette installation que je me propose de décrire ici.

A noter que pour le moment la forge n’est pas totalement opérationnelle. Des évolutions dans la configuration devront être menées et j’espère pouvoir tenir à jour cet article pour les décrire.

Processus d’installation

Préinstallation

Création du sous-domaine

Il faut choisir un nom « agréable » pour la machine et le déclarer dans le DNS. Dans le reste du document, on considère qu’on installe la forme sous le nom maforge.mondomaine.

Espace disque

Il est recommandé également de prévoir un espace disque suffisant pour la forge en montant par exemple un disque sur une baie SAN. Dans le reste du document, on considère que le répertoire disponible est /maforge.

Configuration YUM pour internet

Les scripts d’installation nécessitent d’avoir un accès à internet pour télécharger à l’aide de yum les modules nécessaires pouvant manquer dans l’installation par défaut de la machine. Pour cela, si il est nécessaire de passer par un proxy, le déclarer dans yum.conf sous la forme d’une ligne :

proxy=http://adresseipproxy:port/

Téléchargement de la distribution fusionforge

Les packages à télécharger pour installer la forge sont disponibles à l’adresse :

http://fusionforge.org/frs/?group_id=6

A noter que le document présent est basé sur la version 5.0 de la forge. Il est conseillé de prendre la version notée « allinone ».

Dans la suite, on considère qu’on a téléchargé le fichier : fusionforge-5.0-allinone.tar.bz2

Processus d’installation

Une fois le fichier d’installation téléchargé, le déposer dans un répertoire temporaire de la machine, par exemple : /tmp

Puis en tant qu’utilisateur root :

cd /tmp
bunzip2 fusionforge-5.0-allinone.tar.bz2
tar xf fusionforge-5.0-allinone.tar

On doit se retrouver avec un répertoire /tmp/fusionforge-5.0

cd /tmp/fusionforge-5.0
install.sh maforge.modomaine

Ce script exécute l’installation de la forge :

  • Téléchargement des dépendances (via le script fusionforge-install-1-deps.php)
  • Installation des scripts de la forge, des répertoires, … (via le script fusionforge-install-2.php)
  • Création de la base de données (fusionforge-install-3-db.php)

Lors de l’installation, le script demande d’entrer le nom de l’utilisateur administrateur de la forge et son mot de passe.

Note :

Lors de l’installation, le script semble ne pas avoir complètement fonctionné correctement. Des analyses sont en cours.

De ce fait, un démarrage manuel de la base postgres a dû être effectué à l’aide la commande suivante.

/etc/rc.d/init.d/postgresql start

Une fois ces opérations menées, il doit être possible d’ouvrir un navigateur web à l’adresse :

http://maforge.modomaine/

Page d'accueil de la forge

Processus post-installation

Déplacement des fichiers sur la baie SAN

La forge s’installe dans ses répertoires par défaut. En attendant que la communauté de développeur de la forge rende paramétrable les répertoires, un certain nombre d’action sont nécessaires pour déplacer les répertoires d’installation vers un disque adéquat (sur la baie SAN par exemple).

Pour faire ces déplacements, il est nécessaire de stopper la base de données :

/etc/rc.d/init.d/postgresql stop

Le tableau ci-dessous donne les répertoires par défaut d’installation de la forge et les répertoires cibles vers lesquels on souhaite se déplacer.

Répertoire origine Répertoire destination Commentaire
/opt/gforge /maforge/fforge50 Contient les sources, les scripts php, bref, toute le « programme » forge
/var/lib/gforge /maforge/files Contient les répertoires de travail (svn, uploads, …)
/var/lib/pgsql /maforge/pgsql Contient la base de données
/etc/gforge /maforge/conf Contient la configuration (forge, apache, plugins)
/opt/groups /maforge/groups ???

Pour déplacer les fichiers, faire :

mkdir /maforge/conf
mv /etc/gforge/* /maforge/conf/
rmdir /etc/gforge
ln -s /maforge/conf/ /etc/gforge

mkdir /maforge/pgsql
mv /var/lib/pgsql/* /maforge/pgsql/
mv /var/lib/pgsql/.bash_profile /maforge/pgsql/
rmdir /var/lib/pgsql
ln -s /maforge/pgsql/ /var/lib/pgsql

mkdir /maforge/files
mv /var/lib/gforge/* /maforge/files/
rmdir /var/lib/gforge
ln -s /maforge/files/ /var/lib/gforge

mkdir /maforge/fforge50
mv /opt/gforge/* /maforge/fforge50/
rmdir /opt/gforge
ln -s /maforge/fforge50/ /opt/gforge

mkdir /maforge/groups
mv /opt/groups/* /maforge/groups/
rmdir /opt/groups
ln -s /maforge/groups/ /opt/groups

Puis redémarrer postgres :

/etc/rc.d/init.d/postgresql start

Patch sur les répertoires SVN et CVS

L’installation de la forge semble poser des problèmes sur Redhat 5 et CentOS 5 car des répertoires attendus par la forge ne sont pas créés. Il faut donc, créer des liens symboliques pour corriger ce problème :

ln -s /maforge/files/svnroot /maforge/files/svn
ln -s /maforge/files/cvsroot /maforge/files/cvs
ln -s /maforge/files /scmrepos
ln -s /maforge/files/svnroot /svnroot
ln -s /maforge/files/cvsroot /cvsroot

Installation BIND et configuration DNS (PROVISOIRE/EN COURS)

La forge doit gérer elle-même ses DNS afin de pouvoir déclarer chaque nouveau projet dans son espace propre (par exemple nomprojet.maforge.mondomaine).

Pour cela, une délégation de DNS doit être réalisée par le DNS principal du domaine mondomaine pour laisser le service BIND de la forge gérer le sous-domaine maforge.mondomaine.

Il faut donc également installer le service BIND sur la forge et le configurer.

Note : A compléter

Voir aussi : https://fusionforge.org/docman/view.php/6/1/gforge_manual.plain.html#id2623367

1 Comment :, more...

Utiliser Jetty 7 avec Maven

by on fév.26, 2010, under Java, Maven

Jetty peut être très utile aux projets Maven, notamment dans la phase de tests d’intégration.

Il faut souvent déployer l’application sur un serveur type JBoss puis lancer les tests. Avec Jetty, on dispose alors d’un conteneur léger qui permet de disposer des fonctionnalités essentielles d’un conteneur (webapp, datasource, …).

Problème : avec la version 7 de Jetty, il faut gérer l’authentification. Sinon, on obtient une erreur du type :

java.lang.IllegalStateException: No LoginService for org.eclipse.jetty.security.authentication.BasicAuthenticator@4095c5ec in ConstraintSecurityHandler@28f52a14@

J’ai trouvé la solution à ce problème sur le blog de Max Berger.

A SUIVRE

Leave a Comment :, , more...

Problème Jetty / Maven sous Windows

by on fév.24, 2010, under Maven

Lorsqu’on souhaite lancer une WebApp avec le plugin Jetty sous Maven 2 depuis un PC sous windows on obtient une erreur référencée sous JIRA #JETTY-1063 :

java.net.URISyntaxException: Illegal character in path at index 18: file:/C:/Documents and Settings/USER/.m2/repository/org/mortbay/jetty/jetty-maven-plugin/7.0.0.1beta2/jetty-maven-plugin-7.0.0.1beta2.jar

Ce problème n’est résolu que sous Maven 3. Pour ceux qui souhaitent rester sous Maven 2 (Maven 3 est encore en version alpha), il faut modifier l’emplacement de la repository pour éviter le souci du caractère ESPACE présent dans le chemin C:\Documents and settings\USER\.m2\repository (chemin par défaut).

Il est fortement recommandé de déplacer le répertoire repository dans c:\maven2\repository par exemple et modifier ensuite le fichier settings.xml qui se trouve normalement dans C:\Documents and settings\USER\.m2 ou (moins bien) dans votre répertoire d’installation de maven sous /conf.

<localRepository>/c:/maven2/repository</localRepository>

Ainsi, Maven ira chercher les libs dans un répertoire sans espaces…

2 Comments :, , more...

Utilisation du mode Lazy d’Hibernate avec Struts et Spring

by on fév.24, 2010, under Java

Lorsqu’on utilise Hibernate pour déléguer la gestion de la persistence, se pose alors le classique problème de l’exception LazyInitialisationException.

En effet, dans une modélisation assez classique, imaginons le cas suivant :

Couche Modèle (ou DAO)

Classe POJO contenant un attribut x et une collection cols

@Entity
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
public class Dossier {
	@Id
	@GeneratedValue
	private Long id;
	private String x;

	@OneToMany(cascade=CascadeType.ALL)
	private Collections<String> cols;
	// Getter et setters
}

Classe DAO

Voir le blog pour l’utilisation des generics de Java5 afin d’éviter d’avoir à coder toujours les mêmes méthodes CRUD.

@Repository
@Transactional
public class DossierDAO {
	@Autowired
	protected SessionFactory factory;

	public Dossier getOne (Long id) {
		Session session = factory.getCurrentSession();
		return (Dossier)(session.get(Dossier.class,id));
	}
}

Couche Métier (ou Service)

Classe Service contenant l’injection du DAO

@Transactional
public class DossierServiceImpl implements DossierService {
	@Autowired
	@Qualifier("dossierDao")
	private DossierDAO dossierDao;

	public Dossier read(Long id) {
		return dossierDao.getOne(Dossier.class.getName(), id);
	}
}

On voit ici que la transaction peut démarrer au niveau du service et que par défaut, en mode Lazy, seul l’attribut x de Dossier sera chargé.

Pour que l’application Web appelante puisse faire une itération sur la collection, il faudrait que celle-ci soit chargée.
Il est possible de changer le mode LAZY pour dire à Hibernate de tout récupérer mais pour un arbre de données assez profond, cela peut devenir désastreux.
Il est également de modifier la méthode read du service DossierService ainsi :

public Dossier read(Long id) {
	Dossier d = dossierDao.getOne(Dossier.class.getName(), id);
	d.getCols();
	return d;
}

Dans ce cas, on a déclenché manuellement la recherche du contenu de la collection…

Autre possibilité, garder la connexion avec Hibernate pendant tout le temps du traitement de la requête Web de l’utilisateur.
Pour se faire, on doit ouvrir la transaction au début du traitement de la requête pour ne la restituer qu’à la fin de la génération de la vue.

On modifie le web.xml :

	<filter>
		<filter-name>OpenSessionInViewFilter</filter-name>
		<filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>
	</filter>
	<filter-mapping>
		<filter-name>OpenSessionInViewFilter</filter-name>
		<url-pattern>*.do</url-pattern>
	</filter-mapping>

Dans cette configuration, le filtre OpenSessionInViewFilter mis sur tous les appels *.do va déclencher une ouverture de session hibernate jusqu’à la restitution de la vue.
Ainsi, si dans la JSP, on trouve une itération de l’attribut cols du bean Dossier, un appel à la base de données via Hibernate sera déclenché à ce moment là (et seulement à ce moment là).
Autrement dit, si pour une autre JSP vous n’avez pas besoin d’afficher la collection, l’appel à la base ne sera pas réalisé.

8 Comments :, , more...

Publication de documentation fonctionnelle avec Maven

by on fév.23, 2010, under Maven

Lorsqu’on utilise Maven, se pose souvent la question de génération de documents à intégrer dans le site web généré par Maven.

Au début, j’ai regardé le format APT qui a l’avantage certain de générer du contenu directement consultable sous forme de page Web. Il existe de plus un plugin qui permet de fabriquer un PDF en regroupant les fichiers APT souhaités.

Mais, cela reste un nouveau langage à apprendre pour des équipes fonctionnelles et le format APT est trop limité pour permettre un travail efficace par les équipes de conception ou d’analyse.
Après avoir tourné et viré, testé quelques solutions, j’en suis arrivé à la conclusion que le plus pratique est de laisser les concepteurs utiliser leurs outils office (Microsoft ou oOo) et de transformer ces documents en PDF lors de la fabrication du site.

Pour cela, un petit plugin miracle (jodconverter-maven-plugin) couplé à oOo permet de faire le travail.

Tout d’abord, il faut lancer oOo en mode serveur. Sous Linux, ça se fait comme ça :

/opt/openoffice.org3/program/soffice -headless -accept="socket,host=localhost,port=8100;urp;" -nofirststartwizard

Sous Windows :

"C:\Program Files\OpenOffice.org 3\program\soffice.exe" -accept="socket,host=localhost,port=8100;urp;"

Puis ajouter dans le pom.xml :

<build>
<plugins>
<plugin>
<groupId>com.artofsolving</groupId>
<artifactId>jodconverter-maven-plugin</artifactId>
<version>2.2.3</version>
<inherited>false</inherited>
<configuration>
<sourceDirectory>${basedir}/src/site/docs</sourceDirectory>
<outputDirectory>${project.reporting.outputDirectory}/docs</outputDirectory>
<include>**/*.odt,**/*.odp</include>
<outputFormat>pdf</outputFormat>
<port>8100</port>
</configuration>
<executions>
<execution>
<id>convert</id>
<phase>pre-site</phase>
<goals>
<goal>convert</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>

Ainsi, lors de la génération du site, tous les documents odt ou odp présents dans le répertoire /src/site/docs et sous-répertoires seront transformés en documents PDF dans le répertoire de sortie du site sous /docs. Les sous-répertoires sont également recréés.

Il ne reste plus qu’à faire des liens vers ces documents générés que ce soit dans site.xml ou dans un fichier APT.

Dans l’exemple suivant, le fichier source MonDoc.odt se trouve dans /src/site/docs/1.

<!-- Extrait du site.xml -->
<body>
<menu name="Fonctionnel">
<item name="Mon document" href="./docs/1/MonDoc.pdf" />
</menu>
</body>

Dans le cadre des projets que je gère, j’ai mis en place Hudson qui me reconstruit toutes les nuits une vision documentaire de mes projets. Ainsi, lorsqu’un concepteur valide dans CVS ou SVN pendant la journée un document, il est automatiquement publié la nuit sur le site Maven correspondant.

Autre intérêt : à chaque livraison (release), une photographie complète de l’état de la documentation au moment de la fabrication des livrables est générée. Il est ainsi possible de retrouver facilement le contexte fonctionnel d’une version particulière…

Leave a Comment : more...

La mise en place d’une Forge

by on jan.26, 2010, under Développement

Pour les besoins internes de la douane, j’ai proposé la mise en place d’une forge afin de consolider nos moyens de développement et de gestion de projets.

Histoire d’être cohérent avec d’autres choix faits par l’administration, projet Adullact, j’ai retenu la forge GFORGE.

Je vais décrire ici le processus d’installation que je vais suivre afin de partager cette information avec d’autres personnes qui pourraient être intéressés par cette démarche.

Installation de la Forge sur Ubuntu 9.10

Tout d’abord, il faut télécharger les sources de la forge. Je me suis basé sur la dernière version connue à ce moment : 5.7b2 Community Edition.

Correction du problème avec Postgresql

La version de postgres téléchargée par Ubuntu ne correspond pas à la version attendue dans le script d’installation install-gforge-2-db.php.

Pour corriger ce problème, j’ai remplacé partout (sauf à la fin) la version 8.3 par 8.4.

Par exemple la ligne

'/etc/init.d/postgresql-8.3',

est devenue

'/etc/init.d/postgresql-8.4',

Correction du problème avec la distribution Apache pour Ubuntu (Rewrite)

La gestion de la configuration Apache n’est pas « standard » sur Ubuntu. J’ai donc suivi les recommandations du blog de Josh Street pour corriger le problème.

cd /etc/apache2/mods-enabled
sudo ln -s ../mods-available/rewrite.load rewrite.load
sudo service apache2 start

Finalement, Adullact a annoncé vouloir passer sous FusionForge qui est un fork de GForge afin de conserver la forge dans le monde open-source. La team FusionForge travaille en ce moment sur la version 5.0 mais elle n’est pas encore stabilisée. Nous allons donc installer la version 4.8.3.

La mise en place de FusionForge est abordée dans cet article.

David ;-)

Leave a Comment :, , more...

Statistiques


144
Visiteurs
Uniques
Powered By Google Analytics

Google Adsense