Accueil > DynaResume, OSGi, Spring, Spring DM > Conception d’un client Eclipse RCP et serveur OSGI avec Spring DM [step7]

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.

Introduction Spring Dynamic Module

A quoi ca sert?

Avec Spring Dynamic Module il est possible de :

Comment ca marche?

Comme nous allons voir dans ce billet, les bundles qui souhaitent déclarer leur services à enregistrer et consommer dans le registre de services OSGi n’ont aucune dépendances sur Spring. Il héberge uniquement les fichiers XML Spring nécéssaires pour Spring et Spring DM.

Bundle Spring Extender org.springframework.osgi.extender

Pour rendre actif l’utilisation de ces fichiers XML Spring, il faut ajouter dans la Target Platform les bundles (JArs) nécéessaire à Spring Dynamic Module notemment le bundle Spring Extender org.springframework.osgi.extender. Ce bundle s’occupe de scruter tous les autres bundles définis dans la Target Platform et détecte pour chacun si ils contiennent des fichiers XML Spring. C’est ce bundle qui s’occupe de charger les fichiers XML Spring (instancie des org.springframework.context.ApplicationContext) et d’enregistrer les services déclarés dans le registre OSGi. Ce bundle s’occupe de charger les fichier XML Spring dans des ApplicationContext. Pour plus d’information sur le bundle extender, veuillez vous reporter au chapitre 5.1. The Spring Dynamic Modules Extender bundle.

Prérequis

Avant de démarrer ce billet nous devons préparer le workspace avec les projets suivants :

Vous pouvez télécharger org.dynaresume_step7-start.zip qui contient les projets expliqués dans ce pré-requis. Voici les projets que vous devez avoir pour démarrer ce billet :

<osgi:service = enregistrement services OSGi

Dans cette section nous allons déclarer l’enregistrement du service UserService dans le registre de services OSGi à l’aide de du XML <osgi:service.

Spring DM & XML Bean

Dans cette section nous allons déclarer via des fichiers XML Spring :

  • l’instantiation du service UserServiceImpl en XML (comme ce que nous avons pu faire dans le [step6]) (Spring Framework)
  • l’enregistrement de ce service dans le registre de services OSGi (Spring DM) à l’aide de l’élement XML <osgi:service.

Vous pouvez télécharger :

Bundle org.dynaresume.services.impl

Ici nous allons nous concentrer sur le bundle org.dynaresume.services.impl qui va héberger les fichiers XML Spring.

Suppression ServicesFactory

Après avoir créé le workspace Prérequis ou nos bundles n’ont aucunes dépendances à Spring, nous allons utiliser Spring DM pour ne plus devoir enregistrer programmatiquement notre service UserService, autrement dit :

  • Supprimez la classe ServicesFactory.
  • Commentez ou supprimez le code dans l’Activator qui enregistre le UserService basé sur la classe ServicesFactory :
    package org.dynaresume.services.internal;
    
    import org.osgi.framework.BundleActivator;
    import org.osgi.framework.BundleContext;
    
    public class Activator implements BundleActivator {
    
    	// private ServiceRegistration reg = null;
    
    	public void start(BundleContext context) throws Exception {
    		System.out.println("Start Bundle ["
    				+ context.getBundle().getSymbolicName() + "]");
    
    		// Register UserService instance into OSGi Services Registry
    		// reg = context.registerService(UserService.class.getName(),
    		// ServicesFactory.getInstance().getUserService(), null);
    	}
    
    
    	public void stop(BundleContext context) throws Exception {
    		System.out.println("Stop Bundle ["
    				+ context.getBundle().getSymbolicName() + "]");
    
    		// Unregister UserService instance from OSGi Services Registry
    		// if (reg != null) {
    		// reg.unregister();
    		// reg = null;
    		//
    		// }
    	}
    
    }
Déclaration services OSGi

La déclaration des services OSGi s’effectue via des fichiers XML Spring que le bundle Spring Extender doit retrouver. Il existe 2 manières pour indique au bundle Spring Extender de charger ces fichiers XML dans des instances org.springframework.context.ApplicationContext :

  • les fichiers XML Spring de configuration sont stockés dans le repertoire META-INF/spring et doivent se terminer par l’extension *.xml. C’est cette solution que nous allons utiliser dans la suite de ce billet.
  • le fichier META-INF/MANIFEST.MF contient la méta donnée Spring-Context qui renseigne les chemins des fichiers XML Spring.

Pour plus d’information sur ce sujet je vous conseille de lire le chapitre 6.1. Bundle Format And Manifest Headers.

L’enregistrement programmatique d’un service OSGi s’effectue en 2 étapes :

  1. instancier le service. Dans notre cas nous avions utilisé la classe ServicesFactory qui faisait :
    UserService userService = new UserServiceImpl();
  2. enregistrer l’instance service dans le registre de services OSGi. Dans notre cas, c’était l’Activator du bundle qui s’occupait de cet enregistrement :
    UserService userService = ...;
    context.registerService(UserService.class.getName(),	userService, null);
    

Avec Spring Dynamic Module, l’enregistrement d’un service OSGi s’effectue déclarativement via les 2 déclarations :

  1. déclaration qui permet d’instancier un service. C’est ce que nous avons effectuer dans le billet précédant :
    <bean id="userService" class="org.dynaresume.services.impl.UserServiceImpl"></bean>
  2. déclaration qui permet d’enregistrer le service dans le registre de services OSGi :
    <osgi:service ref="userService" interface="org.dynaresume.services.UserService" />

On peut remarquer que la 2ème déclaration à le namespace osgi qui est associé au schéma XML http://www.springframework.org/schema/osgi/spring-osgi-1.0.xsd. Ces 2 déclarations pourrait s’effectuer dans le même fichier XML, mais une bonne pratique est de :

  1. séparer ces 2 déclarations dans 2 fichiers XML distincts.
  2. nommez les fichiers XML modulename-context.xml qui contient la première déclaration et modulename-osgi-context.xml pour la 2eme déclaration où modulenameest le nom du module.

Mais que signifie nom du module? A cette étape de notre billet nous avons le bundle org.dynaresume.services.impl qui contient tous les services de notre application. Nous avons jusqu’à maintenant découpé nos bundles en couche technique (Client/Domain/Services). Mais dans une application réelle le découpage des bundles doit aussi s’effectuer selon le métier. Ce métier détermine le nom du module. Par exemple dans notre cas, notre bundle s’occupe des User autrement dit des « Ressources Humaines ». Nous pourrions appeler ce module « rh » et donc :

  • nommez le bundle en org.dynaresume.rh.services.impl
  • nommez les fichiers XML Spring rh-context.xml et rh-osgi-context.xml.

Dans notre cas, nous allons utiliser le nom générique « module ». Pour cela :

  1. Créez un répertoire spring dans le répertoire META-INF du bundle org.dynaresume.services.impl.
  2. Créez le fichier module-context.xml dans le le répertoire META-INF/spring comme suit :
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
    	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    	xsi:schemaLocation="http://www.springframework.org/schema/beans
      http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
    	<bean id="userService" class="org.dynaresume.services.impl.UserServiceImpl"></bean>
    </beans>
  3. Créez le fichier module-osgi-context.xml dans le le répertoire META-INF/spring comme suit :
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
    	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:osgi="http://www.springframework.org/schema/osgi"
    	xsi:schemaLocation="http://www.springframework.org/schema/osgi  
           http://www.springframework.org/schema/osgi/spring-osgi-1.0.xsd
           http://www.springframework.org/schema/beans   
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
    
    	<osgi:service ref="userService" interface="org.dynaresume.services.UserService" />
    
    </beans>

A ce stade notre bundle est terminé. Nous n’avons pas ajouté de dépendances à Spring ou Spring Dynamic Module car le chargement de ces 2 fichiers XML Spring vont être effectué via le bundle Spring Extender. Pour rendre opérationnel notre bundle nous devons donc ajouter les bundles Spring Dynamic Module (dont Spring Extender) à notre Target Platform.

Target Platform

Dans cette section nous allons enrichir la Target Platform DynaResume Target Platform [step 6] pour ajouter les bundles Spring Dynamic Module. Vous pouvez télécharger org.dynaresume_step7_spring-target-platform.zip du projet Simple Eclipse spring-target-platform qui contient :

  • les JARs Spring et Spring Dynamic Module nécéssaire pour notre Target Platform.
  • le fichier target DynaResume Target Platform.target qui est la Target Platform que nous allons créé ci-dessous. Si jamais vous utilisez ce projet, les étapes suivantes ne sont pas nécéssaires. En effet Eclipse détecte l’existence de tous les fichiers *.target ouverts dans Eclipse et les affichent dans la page de Preferences des Target Platform. Il faut juste bien penser à activer cette target.

Ici nous allons enrichir la Target Platform du step6 pour ajouter les bundles Spring DM. Pour cela copiez collé dans le répertoire lib les libraires Jars Spring suivantes de la distribution Spring :

JArs Description
dist/spring-osgi-core-1.2.0.jar
dist/spring-osgi-extender-1.2.0.jar
dist/spring-osgi-io-1.2.0.jar
lib/com.springsource.org.aopalliance-1.0.0.jar
lib/org.springframework.aop-2.5.6.A.jar

Rafraîchir la Target Platform avec les nouvelles librairies ajoutées :

Lancement

Voici notre workspace :

Assurez vous que tous les bundles sont cochés dans la configuration OSGi DynaResume. Relancez (via OSGi DynaResume) Equinox et la console OSGi affiche la trace suivante :

osgi> Start Bundle [org.dynaresume.domain]
Start Bundle [org.dynaresume.services]
Start Bundle [org.dynaresume.services.impl]
Start Bundle [org.dynaresume.simpleosgiclient]
--- Get UserService from OSGi services registry with ServiceTracker ---
Cannot get UserService=> UserService is null!
0 [Start Level Event Dispatcher] INFO org.springframework.osgi.extender.internal.activator.ContextLoaderListener - Starting [org.springframework.osgi.extender] bundle v.[1.2.0]
406 [Start Level Event Dispatcher] INFO org.springframework.osgi.extender.internal.support.ExtenderConfiguration - No custom extender configuration detected; using defaults...
406 [Start Level Event Dispatcher] INFO org.springframework.scheduling.timer.TimerTaskExecutor - Initializing Timer
468 [Start Level Event Dispatcher] INFO org.springframework.osgi.extender.support.DefaultOsgiApplicationContextCreator - Discovered configurations {osgibundle:/META-INF/spring/*.xml} in bundle [DynaResume Services Implementation (org.dynaresume.services.impl)]
515 [SpringOsgiExtenderThread-1] INFO org.springframework.osgi.context.support.OsgiBundleXmlApplicationContext - Refreshing org.springframework.osgi.context.support.OsgiBundleXmlApplicationContext@132ae7: display name [OsgiBundleXmlApplicationContext(bundle=org.dynaresume.services.impl, config=osgibundle:/META-INF/spring/*.xml)]; startup date [Wed Nov 25 08:01:40 CET 2009]; root of context hierarchy
515 [SpringOsgiExtenderThread-1] INFO org.springframework.osgi.context.support.OsgiBundleXmlApplicationContext - Unpublishing application context OSGi service for bundle DynaResume Services Implementation (org.dynaresume.services.impl)
578 [SpringOsgiExtenderThread-1] INFO org.springframework.beans.factory.xml.XmlBeanDefinitionReader - Loading XML bean definitions from URL [bundleentry://10.fwk24585668/META-INF/spring/module-context.xml]
687 [SpringOsgiExtenderThread-1] INFO org.springframework.beans.factory.xml.XmlBeanDefinitionReader - Loading XML bean definitions from URL [bundleentry://10.fwk24585668/META-INF/spring/module-osgi-context.xml]
797 [SpringOsgiExtenderThread-1] INFO org.springframework.osgi.context.support.OsgiBundleXmlApplicationContext - Bean factory for application context [org.springframework.osgi.context.support.OsgiBundleXmlApplicationContext@132ae7]: org.springframework.beans.factory.support.DefaultListableBeanFactory@181497d
828 [SpringOsgiExtenderThread-1] INFO org.springframework.osgi.extender.internal.dependencies.startup.DependencyWaiterApplicationContextExecutor - No outstanding OSGi service dependencies, completing initialization for OsgiBundleXmlApplicationContext(bundle=org.dynaresume.services.impl, config=osgibundle:/META-INF/spring/*.xml)
828 [SpringOsgiExtenderThread-2] INFO org.springframework.beans.factory.support.DefaultListableBeanFactory - Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@181497d: defining beans [userService,org.springframework.osgi.service.exporter.support.OsgiServiceFactoryBean#0]; root of factory hierarchy
875 [SpringOsgiExtenderThread-2] INFO org.springframework.osgi.service.exporter.support.OsgiServiceFactoryBean - Publishing service under classes [{org.dynaresume.services.UserService}]
875 [SpringOsgiExtenderThread-2] INFO org.springframework.osgi.context.support.OsgiBundleXmlApplicationContext - Publishing application context as OSGi service with properties {org.springframework.context.service.name=org.dynaresume.services.impl, Bundle-SymbolicName=org.dynaresume.services.impl, Bundle-Version=1.0.0.qualifier}
890 [SpringOsgiExtenderThread-2] INFO org.springframework.osgi.extender.internal.activator.ContextLoaderListener - Application context successfully refreshed (OsgiBundleXmlApplicationContext(bundle=org.dynaresume.services.impl, config=osgibundle:/META-INF/spring/*.xml))
--- Get UserService from OSGi services registry with ServiceTracker ---
User [login=angelo, password=]
User [login=djo, password=]
User [login=keulkeul, password=]
User [login=pascal, password=]

Cette trace montre que :

  1. nos bundles sont lancés :
    osgi> Start Bundle [org.dynaresume.domain] Start Bundle [org.dynaresume.services] Start Bundle [org.dynaresume.services.impl] Start Bundle [org.dynaresume.simpleosgiclient]
  2. le service UserService n’est pas encore publié :
    --- Get UserService from OSGi services registry with ServiceTracker --- Cannot get UserService=> UserService is null!
  3. le bundle Spring Extender se lance et charge les fichiers XML Spring de notre bundle org.dynaresume.services.impl :
    0 [Start Level Event Dispatcher] INFO org.springframework.osgi.extender.internal.activator.ContextLoaderListener - Starting [org.springframework.osgi.extender] bundle v.[1.2.0]... 687 [SpringOsgiExtenderThread-1] INFO org.springframework.beans.factory.xml.XmlBeanDefinitionReader - Loading XML bean definitions from URL [bundleentry://10.fwk24585668/META-INF/spring/module-osgi-context.xml]...
  4. le service UserService est consommé par le bundle client org.dynaresume.simpleosgiclient :
    --- Get UserService from OSGi services registry with ServiceTracker --- User [login=angelo, password=] User [login=djo, password=] User [login=keulkeul, password=] User [login=pascal, password=]

Spring DM & @Service

Dans cette section nous allons déclarer via des fichiers XML Spring et l’annotation @Service:

  • l’instantiation du service UserServiceImpl à l’aide de l’annotation Spring @Service (comme ce que nous avons pu faire dans le [step6]) (Spring Framework)
  • l’enregistrement de ce service dans le registre de services OSGi (Spring DM) à l’aide de l’élement XML <osgi:service.

Nous repartons des projets précédemment expliqués ci-dessus. Vous pouvez télécharger :

Bundle org.dynaresume.services.impl

Ici nous allons utiliser l’annotation Spring @Service pour déclarer notre service UserService dans le bundle org.dynaresume.services.impl . Pour cela :

  1. Importez le package org.springframework.stereotype
  2. Modifiez la classe UserServiceImpl pour l’annoter en tant que service Spring avec l’ID userService :
    package org.dynaresume.services.impl;
    
    import java.util.ArrayList;
    import java.util.Collection;
    import java.util.List;
    
    import org.dynaresume.domain.User;
    import org.dynaresume.services.UserService;
    import org.springframework.stereotype.Service;
    
    @Service("userService")
    public class UserServiceImpl implements UserService {
    ...
    }
  3. Modifiez le fichier de configuration Spring module-context.xml pour indiquer le package de base à scruter pour retrouver la classe UserServiceImpl, avec le contenu suivant :
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
    	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    	xmlns:context="http://www.springframework.org/schema/context"
    	xsi:schemaLocation="
    			http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
    			http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd">
    	
    	<context:component-scan base-package="org.dynaresume.services.impl" />
    
    </beans>
  4. Ajoutez le JAR dist/extensions/spring-osgi-annotation-1.2.0.jar à la Target Platform puis rechargez la Target Platform et assurez vous que le bundle org.springframework.osgi.extensions.annotations est coché dans le configuration OSGi DynaResume.

Relancez (via OSGi DynaResume) Equinox et la console OSGi affiche l’erreur suivante :

875 [SpringOsgiExtenderThread-2] ERROR org.springframework.osgi.extender.internal.activator.ContextLoaderListener - Application context refresh failed (OsgiBundleXmlApplicationContext(bundle=org.dynaresume.services.impl, config=osgibundle:/META-INF/spring/*.xml))
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.osgi.service.exporter.support.OsgiServiceFactoryBean#0': Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: Cannot locate bean named 'userService' inside the running bean factory.
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1338)
...
Caused by: java.lang.IllegalArgumentException: Cannot locate bean named 'userService' inside the running bean factory.
...
Exception in thread "SpringOsgiExtenderThread-2" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.osgi.service.exporter.support.OsgiServiceFactoryBean#0': Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: Cannot locate bean named 'userService' inside the running bean factory.
...

Cette erreur s’explique par le fait que Spring est incapable de trouver la classe UserServiceImpl. Pour y remedier, il faut ajouter la métadonnée Bundle-ClassPath dans le fichier MANIFEST.MF du bundle en lui indiquant ou sont stocké les *.class, plus exactement dans le repertoire bin du projet Eclipse.

Add Classpath

Ici nous allons ajouter au classpath du bundle org.dynamesume.services.impl les classes java *.class. Le plugin PDE lorsqu’il compile les classes du bundle, les stocke dans le répertoire bin du projet Eclipse. Nous allons référencer dans le MANIFEST.MF cette informations via Bundle-ClassPath. Pour cela accédez à l’onglet runtime du MANIFEST.MF du bundle org.dynamesume.services.impl :

Cliquez sur le bouton Add à coté de la liste Classpath. Ceci ouvre la fenêtre de dialogue qui propose tous les répertoires du projet Eclipse :

Sélectionnez le repertoire bin puis OK :

Après avoir enregistré, le fichier MANIFEST.MF est mis à jour avec cette métadonnée :

...
Bundle-ClassPath: bin/,
 .

Lancement

Relancez (via OSGi DynaResume) Equinox et la console OSGi affiche la trace suivante :

osgi> Start Bundle [org.dynaresume.domain]
Start Bundle [org.dynaresume.services]
Start Bundle [org.dynaresume.simpleosgiclient]
Start Bundle [org.dynaresume.services.impl]
--- Get UserService from OSGi services registry with ServiceTracker ---
Cannot get UserService=> UserService is null!
0 [Start Level Event Dispatcher] INFO org.springframework.osgi.extender.internal.activator.ContextLoaderListener - Starting [org.springframework.osgi.extender] bundle v.[1.2.0]
171 [Start Level Event Dispatcher] INFO org.springframework.osgi.extender.internal.support.ExtenderConfiguration - No custom extender configuration detected; using defaults...
171 [Start Level Event Dispatcher] INFO org.springframework.scheduling.timer.TimerTaskExecutor - Initializing Timer
281 [Start Level Event Dispatcher] INFO org.springframework.osgi.extender.support.DefaultOsgiApplicationContextCreator - Discovered configurations {osgibundle:/META-INF/spring/*.xml} in bundle [DynaResume Services Implementation (org.dynaresume.services.impl)]
312 [SpringOsgiExtenderThread-1] INFO org.springframework.osgi.context.support.OsgiBundleXmlApplicationContext - Refreshing org.springframework.osgi.context.support.OsgiBundleXmlApplicationContext@49cf9f: display name [OsgiBundleXmlApplicationContext(bundle=org.dynaresume.services.impl, config=osgibundle:/META-INF/spring/*.xml)]; startup date [Thu Nov 26 14:42:47 CET 2009]; root of context hierarchy
312 [SpringOsgiExtenderThread-1] INFO org.springframework.osgi.context.support.OsgiBundleXmlApplicationContext - Unpublishing application context OSGi service for bundle DynaResume Services Implementation (org.dynaresume.services.impl)
375 [SpringOsgiExtenderThread-1] INFO org.springframework.beans.factory.xml.XmlBeanDefinitionReader - Loading XML bean definitions from URL [bundleentry://57.fwk24585668/META-INF/spring/module-context.xml]
656 [SpringOsgiExtenderThread-1] INFO org.springframework.beans.factory.xml.XmlBeanDefinitionReader - Loading XML bean definitions from URL [bundleentry://57.fwk24585668/META-INF/spring/module-osgi-context.xml]
703 [SpringOsgiExtenderThread-1] INFO org.springframework.osgi.context.support.OsgiBundleXmlApplicationContext - Bean factory for application context [org.springframework.osgi.context.support.OsgiBundleXmlApplicationContext@49cf9f]: org.springframework.beans.factory.support.DefaultListableBeanFactory@1107c05
734 [SpringOsgiExtenderThread-1] INFO org.springframework.osgi.extender.internal.dependencies.startup.DependencyWaiterApplicationContextExecutor - No outstanding OSGi service dependencies, completing initialization for OsgiBundleXmlApplicationContext(bundle=org.dynaresume.services.impl, config=osgibundle:/META-INF/spring/*.xml)
828 [SpringOsgiExtenderThread-2] INFO org.springframework.beans.factory.support.DefaultListableBeanFactory - Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@1107c05: defining beans [userService,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.osgi.service.exporter.support.OsgiServiceFactoryBean#0]; root of factory hierarchy
859 [SpringOsgiExtenderThread-2] INFO org.springframework.osgi.service.exporter.support.OsgiServiceFactoryBean - Publishing service under classes [{org.dynaresume.services.UserService}]
859 [SpringOsgiExtenderThread-2] INFO org.springframework.osgi.context.support.OsgiBundleXmlApplicationContext - Publishing application context as OSGi service with properties {org.springframework.context.service.name=org.dynaresume.services.impl, Bundle-SymbolicName=org.dynaresume.services.impl, Bundle-Version=1.0.0.qualifier}
859 [SpringOsgiExtenderThread-2] INFO org.springframework.osgi.extender.internal.activator.ContextLoaderListener - Application context successfully refreshed (OsgiBundleXmlApplicationContext(bundle=org.dynaresume.services.impl, config=osgibundle:/META-INF/spring/*.xml))
--- Get UserService from OSGi services registry with ServiceTracker ---
User [login=angelo, password=]
User [login=djo, password=]
User [login=keulkeul, password=]
User [login=pascal, password=]

Cette trace montre que le service a été publié correctement.

Conclusion

Dans ce billet nous avons introduit Spring Dynamic Module pour déclarer l’enregistrement du services OSGi UserService dans le bundle org.dynaresume.services.impl via <osgi:service. L’enregistrement de services OSGi est grandement simplifié avec Spring Dynamic Module car tout est en XML (aucun code Java n’est requis et aucune dépendance à Spring n’est nécéssaire (excepté pour l’annotation @Service)). Dans le prochain billet nous verrons comment déclarer la consommation de service OSGi via <osgi:reference même si cela n’est pas nécéssaire dans notre cas.

Vous pouvez lire le billet suivant [step8].

Catégories :DynaResume, OSGi, Spring, Spring DM Étiquettes : ,
  1. jawher
    novembre 29, 2009 à 11:57

    Salut,
    :awe: Angelo pour le travail que tu fais sur cette série !

    Sinon, juste pour clarifier un point : l’ajout de « bin/ » au classpath du bundle pour que les @ de Spring fonctionnent est un hack spécifique à eclipse et n’est requis que si on veut que ça fonctionne depuis un run-config de type OSGi (toujours depuis Eclipse) : ça vient de la façon dont Eclipse déploit les projets explosés. Ce n’est pas requis une fois les projets exportés comme bundles OSGi.

    Bravo encore !

  2. novembre 30, 2009 à 8:48

    Salut djo,

    Merci beaucoup de suivre mes billets et de tes encouragements.

    Merci pour cette précision pour l’ajout du « bin » au classpath, je ne le savais pas. Cela signifie que l’on est obligé de « polluer » le MANIFEST.MF avec ce repertoire? N’y a il pas une autre solution plus propre?

    Merci.

    Angelo

  3. Jérôme
    septembre 22, 2010 à 10:27

    Salut,

    Tout d’abord merci pour cette excellente série de billets ! Ensuite je me trompe peut-être mais je pense que le fichier xml à modifier pour utiliser les annotations @Service est bien le fichier module-context.xml et pas module-osgi-context.xml comme indiqué. Si j’ai bien compris du moins🙂

    • septembre 22, 2010 à 12:24

      Salut Jérôme,

      Merci de ta remarque. Je viens de corriger l’article. Le zip org.dynaresume_step7-spring-osgi-annotations.zip est fait comme tu dis.

  4. Pierre
    mars 7, 2011 à 2:16

    Bonjour,

    Je poursuis pas à pas vos notes, toujous aussi excellentes.
    Ici j’ai buté sur le extender. J’utilise une installation avec org.spring.framework en version 3.0.5.RELEASE et org.spring.framework.osgi en version 2.0.0.M2 sous Eclipse Helios.
    Je n’ai réussi à faire fonctionner l’exemple qu’après avoir ajouté « org.springframework.osgi.extender » à la liste des « Import-Package » du MANIFEST.MF.
    Or cela n’est pas mentionné ci-dessus. Suis je passé à côté de quelque chose ?

    Pierre

  5. mars 7, 2011 à 2:24

    Bonjour Pierre,

    Je n’ai jamais refait ma serie de billet avec Spring 3. Je ne comprends pas pourquoi vous avez eu besoin d’ajouter org.springframework.osgi.extender dans les import packages (de quel bundle?) Vous avez une erreur de compilation?

    Angelo

  6. Pierre
    mars 30, 2011 à 7:23

    Angelo,

    Désolé pour cette réponse tardive.
    Encore une fois merci pour votre série d’articles. Ils ont été d’une grande aide pour s’en sortir avec les OSGi, Spring, Hibernate…
    A cette étape 7, j’avais ajouté « org.springframework.osgi.extender » à la liste « Import-Packages » du projet « org.dynaresume.services.impl ». Et comme vous le suggérez, sans raison valable : cela doit rester géré par la configuration de lancement.

    Pierre

  7. Amine B.
    janvier 2, 2012 à 8:50

    Bonjour Angelo, encore une petite remarque en passant sur ce billet🙂

    En utilisant la version 1.2.1 de spring-osgi plutôt que la 1.2.0 utilisée dans ce blog, le service n’est jamais retrouvé, ni à la première recherche ni aux suivantes.
    Même en faisant bien attention aux start level pour que l’extender puisse démarrer en priorité ça ne fonctionne pas.

    Par contre, en effet, avec la 1.2.0 fournie dans le zip, le service n’est pas trouvé la première fois mais c’est ok pour toutes les itérations d’après.

    Comment fais-tu d’habitude dans ces cas là pour savoir si c’est l’enregistrement ou la consommation qui s’est mal passé?
    Et comment s’assurer à 100% que l’enregistrement des services se déroulera toujours avant toute consommation du osgi registry pour éviter ce côté « aléatoire » ?
    Modifier les « start level » dans le run configurations de eclipse n’est sûrement pas assez fiable pour de gros projets, surtout que, comme tu l’as souligné dans ce billet, les découpages doivent se faire en plein de modules fonctionnels (découpage vertical) pour que l’utilisation d’osgi soit pleinement intéressant dans la pratique donc ça doit être dur à gérer.

    • janvier 2, 2012 à 11:17

      Salut Amine,

      >En utilisant la version 1.2.1 de spring-osgi plutôt que la 1.2.0 utilisée dans ce blog, le service n’est >jamais retrouvé, ni à la première recherche ni aux suivantes.

      Je n’ai pas testé. Ceci étant dit je te conseille d’utiliser Eclipse Gemini (http://eclipse.org/gemini/) au lieu de Spring DM qui est Spring DM qui a été donné à Eclipse (c’est ce que nous utilsons dans notre application RCP/RAP).

      > Comment fais-tu d’habitude dans ces cas là pour savoir si c’est l’enregistrement ou la >consommation qui s’est mal passé?

      Je lance mon launch, puis J’utilise la console OSGi en demarrant (via la commande start) le bundle qui consomme ou le bundle qui enregistre le service pour voir ce qui se passe.

      > Et comment s’assurer à 100% que l’enregistrement des services se déroulera toujours avant toute > consommation du osgi registry pour éviter ce côté “aléatoire” ?
      C’est comme tu dis modifier les « start level » qu’il faut faire. Mais le plus important c’est de mettre les bundles qui enregistre les services en auto-start. C’est peut etre ton problème?

      Tu peux quand même en Java forcer les start/stop de bundles via le BundleContext mais j’ai jamais vu faire ca. En Eclipse RCP tu as une notion de product qui est comme un launch (ou tu configure les start level, etc et qui est aussi utilisé pour générer ton exe).

      Angelo

  1. décembre 2, 2009 à 11:08
  2. décembre 11, 2009 à 10:47
  3. décembre 22, 2009 à 2:25

Laisser un commentaire

Entrez vos coordonnées ci-dessous ou cliquez sur une icône pour vous connecter:

Logo WordPress.com

Vous commentez à l'aide de votre compte WordPress.com. Déconnexion / Changer )

Image Twitter

Vous commentez à l'aide de votre compte Twitter. Déconnexion / Changer )

Photo Facebook

Vous commentez à l'aide de votre compte Facebook. Déconnexion / Changer )

Photo Google+

Vous commentez à l'aide de votre compte Google+. Déconnexion / Changer )

Connexion à %s

%d blogueurs aiment cette page :