Archive
Conception d’un client Eclipse RCP et serveur OSGI avec Spring DM [step9]
Dans les billets précédants [step7] et [step8] nous avons utilisé Spring Dynamic Module pour déclarer la consommation/l’enregistrement du service OSGi UserService dans le registre de services OSGi.
A partir de ce billet nous allons nous concentrer sur la mise en place d’une architecture Client/Serveur, autrement dit :
- Serveur : les services seront hébergés dans une application WEB (classique, bundle OSGi…) qui exposera le service UserService.
- Client : le client (main classique, bundle OSGi, Eclipse RCP) appelera le UserService pour récupérer la liste des User qui seront transmis du serveur au client. Le service UserService sera accéssible via l’URL http://localhost:8080/dynaresume-server/remoting/UserService.
Dans ce billet nous allons nous occuper de la partie Serveur en mettant en place une application WEB classique qui expose le service UserService à l’aide de Spring Remoting. Dans le prochain billet nous décrirons comment mettre en place un client (sans OSGi et avec OSGi) qui fera appel au serveur en appelant le service UserService exposé par l’application WEB. Dans les billets futurs nous verrons comment transformer notre application WEB en bundle OSGi pour bénéficier de la technologie OSGi coté serveur.
Voici un schéma de ce que nous allons effectuer dans ce billet :

Ce schéma montre que :
- nous allons créer une application WEB classique de contexte dynaresume-server. Pour cela nous utiliserons un Dynamic Web Project .
- le service UserService est accéssible via HTTP en utilisant HttpInvoker de Spring Remoting. Pour gérer cela, :
- un Listener Spring ContextLoaderListener doit ête défini pour charger le fichier XML Spring de configuration WEB-INF/applicationContext.xml qui joue le rôle de factory de services.
- une Servlet Spring DispatcherServlet doit être défini pour charger le fichier XML Spring de configuration WEB-INF/remoting-servlet.xml qui permet d’exposer via HTTP le service UserService.
- l’interface UserService et la classe User doivent être communes au client et au serveur.
Nous utiliserons un serveur Tomcat pour hébérger notre application WEB.
Conception d’un client Eclipse RCP et serveur OSGI avec Spring DM [step8]
Dans le billet précédant [step7] nous avons montré l’interêt d’utiliser Spring Dynamic Modules pour déclarer l’enregistrement des services via <osgi:service. Nous avons vu aussi que le bundle Spring Extender s’occupait de créer les org.springframework.context.ApplicationContext des bundles avec des fichiers de configuration XML de Spring.
Dans ce billet nous allons utiliser Spring Dynamic Modules pour déclarer la consommation du service UserService, effectuée dans le bundle client org.dynaresume.simpleosgiclient via <osgi:reference.
Pour rappel la consommation du service UserService s’effectue dans le bundle org.dynaresume.simpleosgiclient dans le thread FindAllUsersThread.
Voici un schéma de ce que nous allons effectuer dans ce billet :

Ce schéma montre que la consommation du service UserService s’effectue déclarativement avec <osgi:reference. Cette déclaration se trouve dans le fichier XML Spring META-INF/spring/module-osgi-context.xml du bundle client org.dynaresume.simpleosgiclient.
Nous verrons dans ce billet trois techniques pour récupérer l’instance UserService déclarée :
- ServiceTracker – ApplicationContext : cette solution consiste à récupérer via ServiceTracker l’instance ApplicationContext du fichier XML Spring spring/module-osgi-context.xml. La Thread FindAllUsersThread utilise ensuite cette instance pour récupérer le service.
- ApplicationContextAware : cette solution consiste à déclarer la Thread FindAllUsersThread dans un fichier XML Spring. La classe FindAllUsersThread implémente ApplicationContextAwarepour récupérer l’instance ApplicationContext du bundle. La Thread FindAllUsersThread utilise ensuite cette instance pour récupérer le service.
- UserService – Injection de dépendances : cette solution consiste à laisser Spring injecter le service dans le Thread FindAllUsersThread. Cette solution est la plus simple et est indépendante de l’API Spring.
Conception d’un client Eclipse RCP et serveur OSGI avec Spring DM [step7]
Dans le billet précédant [step6] nous avons introduit Spring pour instancier le service UserServiceImpl déclarativement via un fichier XML Spring de configuration. Nous avons vu que dans un contexte OSGi, la mise en oeuvre de Spring n’est pas tâche facile. Dans ce billet nous allons utiliser Spring Dynamic Module et montrer que ce dernier simplifie grandement l’enregistrement/consommation des services OSGi qui s’effectue déclarativement et plus programmatiquement comme ce que nous avons fait jusqu’à maintenant.
Voici un schéma de ce que nous allons effectuer dans ce billet :

Ce schéma montre que :
- le bundle org.dynaresume.services.impl contient dans son répertoire MANIFEST-MF/spring 2 fichiers XML Spring :
- module-context.xml qui est le fichier XML Spring de configuration des beans services (identique à celui du fichier applicationContext.xml du billet précédant).
- module-osgi-context.xml qui est le fichier XML qui indique les services à enregistrer dans le registres de service OSGi. Dans notre cas, il indique que le bean userService déclaré dans le fichier module-context.xml doit être enregistré dans le registre de services OSGi.
- la classe ServicesFactory n’existe plus. L’enregistrement du service ne s’effectue plus programmatiquement dans l’Actvator du bundle org.dynaresume.services.impl mais déclarativement via le fichier module-osgi-context.xml
- le bundle org.dynaresume.services.impl ne fait plus référence aux bundles de Spring.
- la Target Platform est enrichie avec les bundles de Spring DM, notemment par celui du bundle Spring extender org.springframework.osgi.extender (spring-osgi-extender-1.2.0.jar) qui s’occupe de scruter tous les bundles de la Target Platform pour détecter pour chacun d’eux si ils contiennent des fichiers XML de configuration Spring (dans notre cas module-context.xml et module-osgi-context.xml). Pour chaque fichier XML Spring, le bundle Spring extender s’occupe de les charger et d’enregistrer les services déclarés dans le registre de services OSGi.
Dans ce billet nous montrerons comment enregistrer un service OSGi déclarativement via <osgi:service avec :
- XML bean : la déclaration s’effectue tout en XML.
- @Service annotation : la déclaration s’effectue via l’annotation Spring @Service.
Dans le prochain billet nous montrerons comment consommer déclarativement un service via <osgi:reference.
Conception d’un client Eclipse RCP et serveur OSGI avec Spring DM [step6]
Dans le billet précédant [step5] nous avons mis en place les 3 couches Client/Services/Domain découpées en plusieurs Bundles :
- Couche Domain gérée par le bundle org.dynaresume.domain.
- Couche Services gérée par les 2 bundles :
- API Services org.dynaresume.services qui contient l’interface UserService.
- Implémentation Services org.dynaresume.services.impl qui exporte UserServiceImpl, l’implémentation de l’interface UserService dans le registre de services OSGi.
- Couche Client qui consomme via le registre de services OSGi, le service UserServiceImpl, géré par le bundle org.dynaresume.simpleosgiclient.
Dans ce billet et le prochain nous allons montrer pas à pas l’interêt d’utiliser Spring Dynamic Module en nous concentrant sur le bundle org.dynaresume.services.impl qui a pour rôle d’enregistrer une instance UserServiceImpl dans le registre de services OSGi. Dans ce billet nous allons utiliser basiquement Spring . Voici un schéma de ce que nous allons effectuer dans ce billet :

Ce schéma montre que :
- La classe ServicesFactory est basée sur un fichier XML Spring applicationContext.xml qui permet de déclarer la classe UserServiceImpl. C’est le conteneur Spring qui s’occupera d’instancier cette classe. Spring joue le rôle dans notre cas de factory de services.
- la Target Platform doit être enrichie pour ajouter tous les bundles Spring.
- le bundle org.dynaresume.services.impl fera référence aux bundle Spring de la Target Platform via les dépendances Import Package.
Le but de ce billet est d’introduire Spring en montrant comment déclarer l’instanciation du service UserServiceImpl via Spring :
- dans un contexte non OSGi. Nous repartirons des projets du billet [step1] et notre factory de services ServicesFactory se basera sur Spring. Nous montrerons qu’il existe 2 manières de déclarer le service UserServiceImpl avec Spring:
- XML bean : la déclaration s’effectue tout en XML.
- @Service annotation : la déclaration s’effectue via l’annotation Spring @Service.
Nous verrons comment configurer Log4j dans un contexte non OSGi.
- dans un contexte OSGi. Nous partirons des projets du billet [step5] et notre factory de services ServicesFactory se basera sur Spring. Nous tenterons d’utiliser les 2 modes de déclarations en mettant en évidence toutes les problématiques de mise en oeuvre de Spring dans un contexte OSGi (problème lié au classloader). Attention, ici nous n’utiliserons pas encore Spring DM, mais uniquement Spring Framework et dans le prochain billet nous verrons comment Spring DM simplifie le code expliqué dans cette section.
Nous verrons comment configurer Log4j dans un contexte OSGi via un Fragment OSGi.
Conception d’un client Eclipse RCP et serveur OSGI avec Spring DM [step5]
Dans le billet précédant [step4] nous avons utilisé le registre de services OSGi pour consommer/fournir le service UserService. Nous avons montré que l’utilisation du registre de services OSGI, permettait de rendre opérationnel le lancement/arrêt du bundle org.dynaresume.services qui fournit le service UserService :
- lorsque le bundle service org.dynaresume.services est arrêté, le bundle client org.dynaresume.simpleosgiclient qui souhaite consommer le service UserService, récupère une instance null.
- lorsque le bundle service org.dynaresume.services est lancé, le bundle client org.dynaresume.simpleosgiclient qui souhaite consommer le service UserService, récupère l’instance UserService fournit par le bundle services.
Dans ce billet je vais expliquer 2 "bonnes pratiques" à suivre dans les Bundle OSGi :
- scinder les bundles services en 2 bundles services API et Implémentation. Dans notre cas nous scinderons le bundle org.dynaresume.services en 2 bundles services API et Implémentation.
- favoriser la gestion des dépendances entre bundles avec Import Package au lieu de Require Bundle, qui sera expliqué plus en détail dans la section Import Package.
Voici un schéma de ce que nous allons effectuer dans ce billet :

Ce schéma montre que :
- le bundle service org.dynaresume.services est scindé en 2 bundles service API et Implémentation.
- les dépendances entres bundles sont gérées via Import Package (et plus par Require Bundle).
Conception d’un client Eclipse RCP et serveur OSGI avec Spring DM [step4]
Dans le billet précédant [step3] nous avons mis en place les 3 bundles OSGi Client org.dynaresume.simpleosgiclient, Services org.dynaresume.services et Domain org.dynaresume.domain. Le service UserService est récupéré via la factory de services ServicesFactory qui est un singleton. OSGi met en avant le fait que l’on puisse lancer/stopper des bundles à chaud sans devoir arrêter le conteneur OSGi. Nous verrons dans ce billet que le lancement/arrêt de nos bundles est à ce stade obsolète et par la suite comment y remédier en utilisant le registre de services OSGi. Autrement dit ce billet aborde le registre de services OSGi en expliquant comment fournir/consommer le service UserService via ce registre. Je vous conseille de lire La plate-forme dynamique de services OSGi pour plus d’informations sur la notion de services OSGi.
Voici un schéma de ce que nous allons effectuer dans ce billet :

Ce schéma montre que :
- le bundle client org.dynaresume.simpleosgiclient consomme toutes les 5 sec le services UserService via la Thread FindAllUsersThread.
- la factory de services ServicesFactory a disparu. L’instance service UserServive est enregistré et récupéré via le registre de services OSGi (en utilisant ServiceTracker).
Dans ce billet nous montrerons pas à pas comment nous arrivons au choix de conception décrit ci-dessus :
- Dans la section start/stop bundle, le bundle client appele via une Thread toutes les 5 sec le service UserService via la factory ServicesFactory. Nous montrerons qu’avec le singleton ServicesFactory, l’arrêt du bundle services est obsolète. Vous pouvez télécharger l’ensemble des projets expliqués dans cette section sur org.dynaresume_step4-thread.zip.
- Dans la section OSGi Services Registry, le bundle service et client utilisent le registre de services OSGi pour fournir/consommer le service UserService. Nous montrerons qu’avec l’utilisation du registre de services OSGi, l’arrêt du bundle service a une influence. Vous pouvez télécharger l’ensemble des projets expliqués dans cette section sur org.dynaresume_step4-osgiservicesregistry.zip.
- Dans la section ServiceTracker, le ServiceTracker OSGi est utilisé dans le bundle client pour consommer le service UserService enregistré (par le bundle service) dans le registre de services OSGi. Ce tracker évite de solliciter tout le temps le registre de services OSGi pour récupérer le service UserService. Vous pouvez télécharger l’ensemble des projets expliqués dans cette section sur org.dynaresume_step4-servicetracker.zip.
Conception d’un client Eclipse RCP et serveur OSGI avec Spring DM [step3]
Dans le billet précédant [step2] nous avons créé le Bundle OSGi org.dynaresume.domain et préparé l’environnement OSGi (Target Platform). Dans ce billet nous allons créer les 2 Bundles OSGi Services org.dynaresume.services, et Client org.dynaresume.simpleosgiclient et gérer leur dépendances via leur fichier MANIFEST.MF.
Voici un schéma de ce que nous allons effectuer dans ce billet :

Ce schéma met en évidence plusieurs notions :
- les dépendances entre les Bundle OSGi s’effectuent via le fichier META-INF/MANIFEST.MF et plus par le Java Build Path classique.
- l’appel des services par le client ne se fait plus par un main Java mais par la méthode start du BundleActivator.
En fin du billet nous reprendrons les 2 problèmes souléves avec le Java build Path classique et qui seront résolus avec OSGi:
- Classes non protégées qui sera résolu via les export package du MANIFEST.MF.
- ClassLoader qui sera résolu par la fait qu’un Bundle OSGi a son propre ClassLoader.
Vous pouvez télécharger les projets org.dynaresume_step3.zip et org.dynaresume_step3-commons-lang.zip (zip qui contient les Bundle OSGi qui utilisent 2 versions de la librairie Apache commans-lang*.jar et qui montre en évidence le problème de ClassLoader résolu) présentés dans ce billet.
Conception d’un client Eclipse RCP et serveur OSGI avec Spring DM [step2]
Dans le billet précédant [step1] nous avons mis en place les 3 couches Client/Services/Domaine dans 3 projets Java qui font références entre eux avec le classique Java Build Path. Nous avons vu que ce type de dépendance engendrait les 2 problèmes de classes non protégées et de ClassLoader. Dans ce billet nous allons créer et lancer notre premier Bundle OSGi, autrement dit nous allons transformer le projet Java org.dynaresume.domain en Bundle OSGi et préparer l’environnement OSGI (Target Platform). Dans le prochain billet nous transformerons les 2 autres projets Java en Bundle OSGi et verrons comment OSGi règle les 2 problèmes cités en introduction.
Voici un schéma de ce que nous allons effectuer dans ce billet :

Ce schéma met en évidence plusieurs notions :
- Bundle OSGi : le projet Java org.dynaresume.domain devient un Bundle OSGi qui est un projet Eclipse Plug-in.
- Target Platform : ensemble de Bundles OSGi (JARs) nécéssaires au Bundle OSGi que nous créons dans le workspace Eclipse. Dans notre cas nous allons dépendre du Bundle OSGi org.eclipse.osgi qui contient l’API OSGi.
- Conteneur OSGi (Equinox) : hébérge et orchestre les Bundles OSGi (gère leur cycle de vie) provenant de notre workspace Eclipse et de la Target Platform. Nous utiliserons Equinox qui est celui par défaut utilisé par Eclipse.
- Dependances : les dépendances entre les Bundle OSGi s’effectuent via le fichier META-INF/MANIFEST.MF et plus par le Java Build Path classique.
- BundleActivator (classe Activator) : permet d’éxecuter du code lors du lancement/arrêt du Bundle.
Nous nous appuierons sur l’ensemble de plugins PDE (Plug-in Development Environment) qui permet de créer des Plug-ins Eclipse mais aussi des Bundles OSGI (un Plug-in Eclipse est en fait un Bundle OSGI).
Vous pouvez télécharger les projets org.dynaresume_step2.zip présentés dans ce billet.
Conception d’un client Eclipse RCP et serveur OSGI avec Spring DM [step1]
Dans le billet précédant [step0], j’ai présenté ce que je souhaitais effectuer dans les billets intitulés Conception d’un client Eclipse RCP et serveur OSGI avec Spring DM. Pour rappel, mon idée est d’expliquer pas à pas comment créer une application cliente eclipse RCP qui communiquera avec des services hébérgés sur un serveur OSGI. L’application RCP affichera une liste d’utilisateurs User récupérée via un service UserService qui sera hébérgé sur le serveur OSGI. Dans ce billet nous n’allons pas encore faire d’OSGI, mais nous allons créer un client (Java main) qui va communiquer avec un service UserService qui retournera une liste de User. Ce service qui est une interface sera récupéré via une factory de services ServicesFactory. Nous découperons chacune de ces couches (Client/Service/Domain (POJO User)) dans un projet Java distinct.
Voici un schéma de ce que nous allons effectuer dans ce billet :

Ce schéma met en évidence trois projets Java :
- org.dynaresume.domain (POJO) : projet Java qui contient les POJO (domaine de l’application) entre autres le POJO User.
- org.dynaresume.services (Services) : projet Java qui contient le service UserService qui permet de retourner une liste d’utilisateurs User.
- org.dynaresume.simplemainclient (Client) : projet Java qui consomme dans un main Java le service UserService.
Les dépendances entre les projets sont gérées classiquement via le Java Build Path du projet. Nous verrons en fin de ce billet les 2 problèmes courants que nous rencontrons avec ce type de dépendance classique :
- il est impossible de rendre inaccéssible l’utilisation de certaines classes d’un projet Java aux classes d’un autre projet Java. Ce problème sera résolu via OSGI dans le prochain billet en indiquant les packages que l’on souhaite exposer.
- tous les projets Java partagent le même ClassLoader, ce qui peut poser des problèmes lorsque l’on souhaite utiliser des versions différentes d’une librairie dans les projets Java. Ce problème sera résolu via OSGI dans le prochain billet car chaque Bundle OSGI a son propre ClassLoader.
Vous pouvez télécharger les projets org.dynaresume_step1.zip et org.dynaresume_step1-commons-lang.zip (zip qui contient les projets Java qui utilisent 2 versions de la librairie Apache commans-lang*.jar et qui montre en évidence le problème de ClassLoader) présentés dans ce billet.
Conception d’un client Eclipse RCP et serveur OSGI avec Spring DM [step0]
Il y a 3 ans j’ai créé le projet GestCV, une application WEB de gestion de CV basé sur Spring, Hibernate, Struts1.x et AJAX. A cette époque je souhaitais utiliser et mettre en évidence toutes les technologies que j’adorais dans un véritable projet.
Aujourd’hui j’ai décidé de me former au développement d’applications Eclipse RCP basé sur les API SWT et JFace que j’ai découvert à travers le développement du plugin Eclipse Akrogen, du projet TK-UI et JFace DOM Databinding. Eclipse RCP me séduit de plus en plus pour les raisons suivantes. Avec Pascal Leclercq nous avons créé ce mois-ci le projet DynaResume OSGI GestCV qui est une version RCP de GestCV (le projet est en phase d’étude). Plus exactement ce projet est basé sur une architecture client/serveur, autrement dit :
- la couche serveur fournira les services utiles pour la gestion de CV (édition d’un CV, création d’un CV).et sera basée sur OSGI via Spring DM. Les services feront appels à la base de données via Hibernate.
- la couche cliente sera une application Eclipse RCP qui consommera les services hébérgés sur le serveur.
Nous souhaitons utiliser OSGI dans la couche serveur pour démarrer/arrêter à chaud les services sans devoir redémarrer le serveur (très utile en développement comme en production). OSGI fournit d’autres avantages que je tenterais d’expliquer tout au long de ces billets. Je ne sais pas si nous aboutirons ce projet mais mon but premier est de me former aux technologies OSGI, Spring DM, RCP et de les expliquer par des exemples concrets et détaillés dans des billets.
Mon idée est de rédiger des billets qui expliqueront pas à pas comment réaliser une application Eclipse RCP qui communique avec un serveur OSGI avec Spring DM. Concrètement je vais tenter d’expliquer comment développer une petite application RCP qui affiche/met à jour une liste d’utilisateurs récupérée par des services (OSGI) hébérgés sur le serveur. Je tenterais en même temps d’expliquer l’interêt d’OSGI.
Nous avons aussi envisagé d’étudier plus tard (selon notre temps) ce que peut nous fournir le futur projet Eclipse E4 (moteur CSS (qui est à l’origine celui de projet TK-UI ), Modeled Workbench, SWT Flex…) et RAP (qui d’après ce que j’ai compris permet de déployer l’application RCP en mode WEB ).
Si le sujet vous intéresse, vous pouvez accéder à la série de billets intitulée Conception d’un client Eclipse RCP et serveur OSGI avec Spring DM .