OSGi en bref - Eric

publicité
ADELE/LIG
OSGi en bref
Version 1.0.2
Eric SIMON
OSGi en bref de Eric Simon est mis à disposition selon les termes de la licence Creative Commons
Paternité 3.0 non transcrit.
1 But du document
Ce document a pour but d’expliquer brièvement les mécanismes dans OSGi qui permettent le
chargement et le déchargement dynamiques de modules ainsi que de la mise en place d’applications
dites dynamiques.
2 OSGi : Histoire et Motivation
Le succès d’OSGi ne cesse de croître. Cependant les buts actuels d’OSGi ne correspondent plus
au but initial.
JSR 008
A l’origine, le projet de la plate-forme OSGi est issu de la JSR 008 (décembre 1998) (cf. [1.]) qui
spécifie une passerelle de service appelée OSG pour Open Service Gateway. Cette passerelle est
destinée à fournir une capacité de pontage entre un réseau interne et un réseau externe, par
exemple entre un réseau SOHO1 et internet ou encore entre un réseau domestique et internet (cf.
Figure 1).
Figure 1 Topologie ciblée par la JSR 008
Cette passerelle a deux buts :


Servir de point d’accès à des partis tiers pour fournir des services ;
Centraliser la gestion des différents équipements sur le réseau.
De plus les différents éléments sur cette passerelle doivent fournir des API pour pouvoir les lier
entre eux. Et d’autre part ils devraient suivre le principe de « zéro-administration ».
Un exemple de scénario parmi d’autres visés par la JSR 008
Pour bien comprendre l’intérêt, prenons un exemple concret :
EDF cherche à éviter la surcharge de la consommation nationale en fournissant un service de
facturation incitatif. C’est-à-dire que le prix du kW/h varie un jour sur l’autre dans une fourchette
préétablie. EDF s’engage à fournir la grille tarifaire 5 jours à l’avance au client. Par exemple un
dimanche au printemps ne nécessite pas de chauffage électrique ni de climatisation, pas
d’évènement particulier qui consomme de l’énergie au niveau national. Par conséquent le prix du
1
Small Office Home Office
2
kW/h sera faible ; les personnes devraient par conséquent faire leur lessive… Inversement imaginons
un lundi particulièrement froid en hiver, la consommation nationale en électricité est élevée :
chauffage, travail… Dans ce cas le prix du kW/h sera élevé, de cette manière les gens ne laisseront
pas le chauffage allumé alors qu’ils seront au travail, ils reporteront leur lessive et le sèche-linge à un
autre jour.
Pour définir un tel scénario il faut trois éléments :



Des sondes sur le panneau électrique qui remontent la consommation journalière ;
Une infrastructure de remontée de données des consommations ;
L’envoi de la grille tarifaire des 5 prochains jours au client en fonction de leur abonnement et
de leur géolocalisation.
Dans ce scénario une passerelle OSG est parfaite car la passerelle récupère les données sur les
sondes et envoie périodiquement les données à EDF avec le numéro d’abonnement. Chaque jour EDF
envoie les grilles tarifaires aux passerelles. Les clients accèdent aux tarifs en se connectant sur
l’interface de la passerelle.
Par conséquent, la passerelle embarque un module de communication pour les sondes, un
module de communication pour la remontée de données vers EDF, un module d’interface pour les
abonnés et finalement un ou plusieurs composants métier.
Dans l’exemple ci-dessus, la passerelle sert de pont entre le compteur électrique et la remontée
de données d’EDF. Elle fournit un point d’accès à EDF pour déployer des composants qui vont lui
permettre de remonter des données ou de lui en envoyer. Et finalement, la passerelle permet de
centraliser l’ensemble des composants nécessaires à l’abonné.
Et OSGi dans tout ça ?
OSGi est un projet issu de la JSR 008. Le consortium OSGi Alliance (cf. [2.]) a été fondé en mars
1999. Il est chargé de spécifier et de standardiser les fonctionnalités et les services des plates-formes
d’exécution OSGi.
Bien que déjà décrit dans la JSR, OSGi met l’accent sur la modularité des éléments qui
constituent l’application aussi bien au niveau classe qu’au niveau objet, pour pouvoir reconfigurer
l’architecture en exécution sans avoir à arrêter la passerelle. La modularité et la reconfigurabilité
sont des propriétés recherchées dans des domaines autres que celui des passerelles : par exemple
pour les serveurs d’applications.
Conclusion
Nous nous intéresserons dans ce document aux aspects de modularité et de reconfigurabilité fournis
par OSGi.
3
3 La plate-forme OSGi
OSGi spécifie une plate-forme d’exécution Java qui supporte le déploiement d’applications
extensibles et téléchargeables nommées : bundle.
Les équipements compatibles OSGi peuvent télécharger et installer ces bundles et les
désinstaller lorsqu’ils n’en ont plus besoin.
Cette plate-forme repose principalement sur trois couches en interaction (cf. Figure 2) :


Bundle
Bundle

La couche module définit un modèle de modularisation pour Java ;
La couche cycle de vie est basée sur la couche module. Elle définit l’API d’administration des
bundles ainsi que les différents états dans lesquels peut être un bundle;
La couche service est basée sur la couche cycle de vie. Cette couche définit un modèle de
programmation ainsi que les mécanismes pour la conception, le développement et
l’exécution d’applications « dynamiques » basées sur l’approche orientée service.
Enregistre,
Désenregistre,…
Service
Démarre,
Arrête
Cycle de vie
Installe,
Désinstalle
Charge les
classes
Module
Figure 2 Interactions entre les différentes couches
Nous résumerons dans cette section ces trois couches.
3.1 Couche Module : Bundle
La couche Module définit le concept de bundle à la fois comme unité de déploiement et comme
unité de composition dans la plate-forme d’exécution. Dans OSGi le concept de bundle et celui de
module sont similaires et sont donc interchangeables.
Un bundle est une archive Java (Jar) qui peut contenir, outre des classes Java, différentes
ressources. Ces ressources peuvent être diverses (cf. Figure 3) : GIF, PNG, fichier de propriétés ou
d’autres conteneurs comme des archives Java (Jar) ou des fichiers Zip. De plus un bundle peut
contenir aussi des librairies de code natif comme des dll ou des fichiers so… Il faut cependant
différencier les classes Java, les archives Java et les librairies de code natif des autres ressources car
celles-ci sont prises en charge par la plate-forme, alors que la gestion des autres ressources est à la
charge du développeur du bundle. Dernier point : un bundle contient un ensemble de métadonnées
utilisées par la plate-forme pour qu’elle puisse prendre en charge les différents aspects du bundle (cf.
section 3.1.1).
4
Rôle d’unité de déploiement
Un point important est que le bundle est une unité
de déploiement, c’est-à-dire que c’est un élément
« tangible » qui d’une part va pouvoir être copié et
transféré ; mais qui d’autre part va servir à empaqueter
les classes qui pourront ainsi être partagées, chargées
et utilisées.
.class
.class
Rôle d’unité de composition
.dll, .so
L’autre aspect d’un bundle est qu’il est utilisé
comme unité de composition. C’est-à-dire qu’il va être
utilisé avec d’autres pour définir une ou plusieurs
MANIFEST.MF
applications. Dans OSGi, cette composition peut se
faire à deux niveaux : niveau classe et niveau objet.
Dans cette section nous allons nous intéresser au
niveau classe, le niveau objet sera quant à lui traité
Figure 3 Module OSGi : Bundle
dans les autres couches. Au niveau classe le Bundle
permet de cloisonner les classes entre ce qui est propre (privé) à l’exécution du Bundle de ce qui sera
partagé dans la composition. Cet aspect est basé sur les métadonnées fournies par le Bundle.
Bundle
Nous allons, dans un premier temps, aborder les métadonnées définies par OSGi, puis la prise en
charge des classes et des librairies de code natif.
3.1.1 Métadonnées d’un bundle
OSGi spécifie une spécialisation de l’archive Java pour son contexte d’exécution. De ce fait il
réutilise le fichier de métadonnées (Manifest) défini par Java (cf. encadré ci-contre) pour y inscrire
ses propres métadonnées.
Les Manifests dans Java
Les archives Java supportent de
nombreuses fonctionnalités, comme les
signatures électroniques, le contrôle de
version et bien d’autres aspects. Ces
fonctionnalités nécessitent des informations
incluses dans l’archive Java : c’est le rôle du
Manifest.
Le Manifest (fichier MANIFEST.MF) est un
fichier de métadonnées dans le répertoire
META-INF de l’archive Java. Ce fichier contient
au moins l’information de version du Manifest.
Par défaut Java définit un ensemble de
métadonnées : comme par exemple le nom du
vendeur ou la version de l’archive. La plupart
des métadonnées dépendent du contexte
d’exécution et de la nature de l’archive.
Pour plus d’information, référez-vous à
http://java.sun.com/developer/Books/javapro
gramming/JAR/basics/manifest.html.
OSGi définit un certain nombre de
métadonnées
(cf.
section
3.2.1
de
http://www.osgi.org/download/r4v43/r4.core.pdf).
Dans cette section nous n’allons pas décrire
l’ensemble des propriétés, mais seulement celles
qui sont liées au cycle de vie et à la gestion des
classes/code.
Gestion des classes/code
 Bundle-ClassPath : cette propriété est
utilisée pour indiquer les chemins (path) vers les
archives Java contenues dans le bundle. De cette
manière, les classes et les ressources de ces
archives embarquées pourront être utilisées. Par
exemple : /lib/jms.jar. Nous aborderons à
nouveau cette propriété dans la section 3.1.2.
5


Bundle-NativeCode : comme vu précédemment, un bundle OSGi peut embarquer du code
natif. Cette propriété sert à la fois pour définir les chemins vers les librairies de code natif,
ainsi que dans quels contextes d’exécution (e.g. : système d’exploitation, processeur…).
Exemple : LibusbJava.dll;osname=WindowsXP;processor=x86. Nous aborderons à
nouveau cette propriété dans la section 3.1.3.
Bundle-RequiredExecutionEnvironnement : cette propriété indique le ou les
environnements d’exécution qui doivent être présents sur la machine. Exemple : Java SE
6.



Export-Package : cette propriété désigne les packages appartenant au bundle qui seront
exportés. Nous aborderons à nouveau cette propriété dans la section 3.1.2.
Import-Package : cette propriété désigne les packages requis par le bundle pour son
utilisation. Nous aborderons à nouveau cette propriété dans la section 3.1.2.
DynamicImport-Package : cette propriété désigne les packages qui seront chargés non pas à
l’installation du Bundle mais au moment de leur utilisation. Par conséquent il se peut qu’il ait
des dépendances de packages non résolues à l’exécution. Il faut donc utiliser cette propriété
en dernier recours.
Cycle de vie









Bundle-Activator : cette propriété spécifie le nom de la classe utilisée pour l’activation et la
désactivation du bundle. Nous aborderons à nouveau cette propriété dans la section 3.2.1.
Bundle-ActivationPolicy : cette propriété définit la politique d’activation que doit suivre la
plate-forme pour activer le bundle. Par défaut il existe deux politiques :
o Par défaut eager : démarre le bundle et charge les classes lors de l’activation.
o Lazy : diffère l’activation et le contexte d’exécution du bundle jusqu’à sa première
utilisation (déclenchée par le chargement d’une ou plusieurs classes spécifiées).
Bundle-UpdateLocation : cette propriété permet de spécifier une URL, à partir de laquelle on
devrait (SHOULD) pouvoir mettre à jour le bundle.
Export-Service : cette propriété est dépréciée (deprecated). Elle permettait d’indiquer les
services que fournissait un bundle.
Import-Service : cette propriété est dépréciée (deprecated). Elle permettait d’indiquer les
services que requérait un bundle.
Provided-Capability (R4.3) : Cette propriété signifie que le bundle fournit un ensemble de
« capacités ».
Require-Capability (R4.3) : Cette propriété signifie que le bundle requiert d’autres bundles
pour fourni une « capacité ». Cette dépendance vers d’autres bundles est définie via un filtre
LDAP.
Require-Bundle : cette propriété spécifie que tous les packages exportés par un bundle ciblé
doivent être importés.
Fragment-Host : cette propriété définit quels sont les bundles « hôtes » pour ce fragment.
6
3.1.2 Gestion des classes dans OSGi
L’un des principaux attraits d’OSGi est la
modularité qui permet l’installation et la
désinstallation de modules JAVA sans
interruption de la plate-forme. Cette
fonctionnalité est permise grâce à une gestion
avancée des classes. Dans cette section nous
allons nous intéresser à la gestion des class
loaders (rappel : voir encadré ci-contre).
OSGi base son mécanisme pour cacher et
partager les packages sur deux points : un
réseau de délégation de chargement de classes
(cf. Figure 4) et des règles de visibilité de
package.
Réseau de délégation de class loader
Chaque bundle a un unique class loader.
Ce class loader peut charger des classes à
partir de trois différentes sources de
ressources :



Boot class path : il contient les
packages
java.*
et
leurs
implémentations ;
Framework class path : la plate-forme
OSGi a généralement un class loader
séparé
pour
les
classes
d’implémentation de la plate-forme
ainsi que pour certaines interfaces de
service clé ;
Espace de Bundles : cet espace
consiste en l’ensemble des archives
Java liées au bundle par une relation
d’import ou de fragment.
Qu’est-ce qu’un class loader en Java ?
Rôle : La machine virtuelle Java (JVM) accède aux
classes via les chargeurs de classe (class loader). Le but
d’un class loader est de charger les classes à partir
d’une source. De ce fait la machine virtuelle Java
ignore la localisation des ressources : c’est aux class
loaders d’aller les chercher dans les différentes
ressources d’un système. Pour cela, Java se base sur
un arbre de délégation de class loader dont les règles
sont les suivantes :
 Tout class loader a un parent (sauf le chargeur
initial) ;
 Tout class loader va d’abord chercher les classes
à partir de son parent avant d’aller les chercher dans
le CLASSPATH.
Par défaut, la machine virtuelle Java possède trois
class loaders hiérarchiques :
1. Le class loader initial : charge les classes
standards de la machine virtuelle (rt.jar, core.jar…)
2. Le class loader d’extension : charge les classes du
répertoire d’extension : /jre/lib/ext ;
3. Le class loader applicatif : charge les classes à
partir des archives Java définies dans le CLASSPATH.
Il est possible d’ajouter d’autres class loader pour
prendre en charge des aspects particuliers dans le
système (e.g. : URLClassLoader)
Règles :
a. Une classe est liée à son class loader et ne peut
en changer ;
b. Une classe est identifiée par son nom et son
class loader ;
c. Il ne peut pas y avoir deux classes ou plus ayant
le même nom dans un class loader ;
d. Une même classe peut être chargée par
plusieurs class loaders ;
e. Une classe ne peut être déchargée que si son
class loader n’est plus référencé ; c’est-à-dire qu’il
n’existe plus d’instance de cette classe.
Bundle
Class Loader
Bundle
Class Loader
Framework
Class Loader
System
Class Loader
Bundle
Class Loader
Bundle
Class Loader
Import de
Figure 4 Modèle de délégation de class loader
7
Visibilité des packages
Le deuxième mécanisme mis en place dans OSGi est un mécanisme de visibilité de package. En
effet, comme vu dans la sous-section Gestion des classes de la section 3.1.1, OSGi définit des
métadonnées pour la gestion des packages qui
sont :



Ces métadonnées définissent deux types
de visibilité :


publics
Import Package ;
Export Package ;
Private Package ;
Bundle B
V1.0
privés
publics
Bundle A
Publique : les packages exportés ;
Privée : les packages déclarés comme
privés.
Les packages publics peuvent donc être
importés et utilisés par d’autres bundles. Par
conséquent un bundle a accès à la fois aux
classes de ses packages qu’ils soient publics ou
privés, mais aussi à toutes les classes des
packages publics qu’il importe.
privés
Espace de
Classe de A
publics
privés
Bundle C
privés
publics
Espace de
Classe de D
Bundle D
publics
privés
Bundle B
V2.0
Prenons l’exemple de la Figure 5, le
bundle A accède à la fois à ses classes mais
aussi aux classes des packages publics
Figure 5 Visibilité et espace de classe
importés par A. Cet ensemble de classes
auquel peut avoir accès le class loader du bundle A s’appelle espace de classe.
Versionnement
Le fait d’avoir un class loader par bundle permet d’avoir à l’exécution plusieurs versions d’un
même package dans l'environnement d'exécution. La seule contrainte est bien évidemment qu’un
bundle ne peut avoir accès qu’à une seule version (règle C des class loader dans Java, encadré
précédent).
OSGi suppose que les bundles ont une compatibilité ascendante et cherchera donc par défaut à
résoudre les dépendances de packages à l’aide des dernières versions. Cependant il est possible de
spécifier dans les métadonnées les versions que l’on souhaite utiliser pour résoudre la dépendance
de package :
Import-Package : org.apache.felix.ipojo;version= 1.4.0
Cela signifie que le bundle requiert le package org.apache.felix.ipojo ayant une version
au moins égale à 1.4.0. Pour définir une version explicite il faut définir la propriété de la manière
suivante :
8
Import-Package : org.apache.felix.ipojo;version= [1.4.0, 1.4.0]
Cela signifie que le package doit avoir une version supérieure ou égale à 1.4.0 et être inférieure
ou égale à 1.4.0 : donc être égale à 1.4.0. De manière plus générale OSGi définit la politique de
version de la manière suivante :
[Min,Max]
[Min,Max)
(Min,Max)
(Min,Max]
Version
Min <= x <= Max
Min <=x< Max
Min < x < Max
Min < x <= Max
Version <= x
En conclusion, comme le montre la Figure 5, il est possible d’avoir plusieurs versions d’un même
package dans OSGi : le bundle A utilise les packages du bundle B version 1 alors que le bundle D
utilise la version 2. Cependant, les bundles A et B ne doivent pas s’échanger des instances des classes
venant respectivement des bundles B.
Communication inter-bundle
Rappelons une règle des class loaders : une classe est identifiée par son nom et son class loader.
S’il existe une même classe dans plusieurs class loaders alors ces mêmes versions de classe seront
considérées comme étant distinctes. Par conséquent pour pouvoir communiquer, deux bundles
doivent se partager une même classe. C’est à ce moment que le mécanisme de réseau de délégation
de class loader entre en jeu : un class loader va chercher dans son parent les classes à charger avant
de les rechercher dans son classpath. Dans le cas d’OSGi, un bundle va d’abord chercher les classes à
partir du class loader parent c’est-à-dire le système Java et ses extensions, puis à partir des class
loaders des différents bundles appartenant à son espace de bundles (relation d’import/export de
packages à l’exécution). Grâce à ce mécanisme d’import/export de package, les bundles peuvent
s’échanger des classes provenant d’un unique class loader permettant ainsi la communication entre
les bundles.
Complétons l’exemple de la Figure
Class loader C
5 à l’aide de la Figure 6: une instance de
classe du bundle A envoie des messages
loadClass(fr.imag.Bob.getName())
à une instance de classe du bundle D.
Par conséquent A et D doivent avoir le
Class loader A
Class loader D
même type de message et venir du
même class loader. Dans le cas présent,
les instances respectives de A et D vont loadClass(fr.imag.Bob.getName())
loadClass(fr.imag.Bob.getName())
charger la classe du message
Figure 6 Exemple de délégation de chargement dans OSGi
fr.imag.Bob à partir de leur class
loader respectif qui délèguera au class loader du bundle C.
Dynamicité
Nous aurions pu avoir le cas, comme dans l’exemple de la Figure 7, où les classes servant à la
communication appartiennent à l’un des deux bundles. Ce cas de figure est à éviter car nuit à la
dynamicité de la plate-forme.
9
Explication : une instance de A
souhaite communiquer avec une
loadClass(fr.imag.Bob.getName())
instance de D, pour cela elle a chargé la
classe Bob à partir de D. Maintenant on
souhaite désinstaller D et installer un
Class loader A
Class loader D
autre bundle qui fournit les mêmes
fonctionnalités que D. il fournit aussi la
classe Bob. Cependant le bundle A a
loadClass(fr.imag.Bob.getName())
loadClass(fr.imag.Bob.getName())
déjà chargé la classe Bob et il n’est
Figure 7 Exemple de délégation à éviter
possible de le décharger que si on
relâche le class loader de A ce qui revient à redémarrer le bundle A. La communication avec les
instances du nouveau bundle n’est pas non plus possible car il utilisera sa classe Bob qui vient d’un
autre class loader et qui par conséquent est un autre objet.
Par conséquent dans OSGi, on sépare l’API pour la communication et son implémentation dans
des bundles différents.
3.1.3 Gestion du code natif
Java ne permet pas d’accéder à tous les aspects d’un système. Par conséquent OSGi spécifie la
possibilité d’embarquer du code natif dans un bundle. L’idée sous-jacente est qu’il est parfois
nécessaire d’utiliser des drivers natifs à un système. Cependant les programmes Java sont souvent
portables entre les systèmes, ce qui n’est pas le cas du code natif.
Sélection des librairies
OSGi spécifie un mécanisme de sélection de librairie de code natif en fonction du système. Cette
sélection se base sur cinq propriétés :





Le nom du système d’exploitation (osname) : par exemple WindowsXP, Linux, Solaris ;
La version du système d’exploitation (osversion) : par exemple 5.1 ;
Le processeur (processor) : par exemple x86, mips, sparc ;
Le langage (language) : par exemple en, fr ;
Un filtre de sélection.
Prenons l’exemple d’un bundle qui fait le pont d’USB2 vers OSGi. Le manifest de ce bundle
contient la métadonnée suivante :
Bundle-NativeCode :
lib/LibusbJava.dll;osname=WindowsXP;osname=windows vista;osname=Windows
7;processor=x86,
lib/libusbJava.so;osname=Linux;processor=x86
La métadonnée suivante dit que la librairie LibusbJava.dll présente dans le répertoire lib
du bundle sera chargée si le système d’exploitation est un Windows soit XP, soit vista soit 7 et si c’est
un processeur x86. Si le système d’exploitation est un Linux sur un processeur x86 alors la librairie
libusbJava.so sera chargée.
2
http://websvn.ow2.org/filedetails.php?repname=chameleon&path=%2Fsandboxes%2Fmehdi%2FUSB-BridgeBundle%2Fpom.xml
10
Utilisation du code natif
Grâce au mécanisme précédent il est
possible d’utiliser du code natif en fonction du
système sous-jacent. Cependant ces librairies ne
seront accessibles qu’à partir de la plate-forme
OSGi. En effet le but n’est pas de déployer ou de
mettre à jour des pilotes ou des fonctionnalités
du système sous-jacent, mais d’accéder et
d’exploiter des ressources du système qui
nécessitent des pilotes en code natif. L’exemple
précédent en est une parfaite illustration : l’accès
aux équipements USB n’est pas pris en charge par
Java et nécessite des pilotes dépendants du
système. Le but du bundle est de fournir un
service d’annuaire d’équipements USB basé sur
les pilotes USB pour Windows et Linux. Pour cela
les deux librairies sont interfacées à l’aide de JNI
(voir encadré Java Native Interface).
En fait, lorsque le code appelle le système
pour rechercher la librairie, OSGi retourne la
librairie comme si elle était installée dans le
système.
Il y a tout de même une limitation : seul un
unique class loader, donc un bundle, doit charger
la librairie native pour pouvoir préserver la
séparation des espaces de nom. En effet si
plusieurs class loaders chargent la librairie alors il
y aura un recouvrement des espaces de noms et
causera donc une erreur de liaison.
Java Native Interface (JNI)
(http://java.sun.com/docs/books/jni/download/jni.pdf)
Le but de JNI est de pouvoir incorporer du code
natif écrit en C ou en C++ dans du code JAVA.
JNI est fournie par défaut dans le JDK de Sun. La
machine virtuelle Java (JVM) fournit donc JNI pour
interfacer du code natif et du Java. Cette interface est
bidirectionnelle : elle permet à des applications Java
d’appeler du code natif et inversement.
L’interface bidirectionnelle JNI peut supporter
deux types de code natif : les libraires et les
applications.
JNI peut être utilisée pour écrire des méthodes
natives qui seront appelées par du code Java.
Inversement, JNI peut être utilisée pour
embarquer une application Java et la JVM dans une
application native.
Il faut toutefois remarquer que dans une
application Java dépendante de librairie native, seule
la partie purement Java est portable d’un système à un
autre. Il faudra donc interfacer pour chaque système
les librairies natives correspondantes.
Il faut donc bien circonscrire les librairies natives
dans l’architecture de l’application et en limiter
l’utilisation.
3.1.4 Conclusion
La couche module définit le concept de bundle. Ce concept est à la base de la modularité et de la
dynamicité de la plate-forme d’exécution OSGi. En effet chaque bundle a son class loader, ce qui fait
que chaque bundle peut être vu comme étant une plate-forme ayant son espace de classe et son
espace d’exécution. Cependant, c’est le mécanisme de délégation entre ces class loaders définis par
OSGi qui permet le partage de classe et la communication entre ces espaces d’exécutions.
En d’autres termes, OSGi se distingue des autres plates-formes d’exécution (serveur JavaEE…)
par son mécanisme de réseau de délégation de class loaders qui permet la modularité et une
dynamicité des applications.
11
3.2 Couche cycle de vie
La couche cycle de vie dans OSGi fournit les fonctionnalités de sécurité et les opérations
d’administration des bundles. Cette couche est basée sur celle de module.
Dans cette section nous allons nous intéresser au cycle de vie d’un bundle, c’est-à-dire décrire
les différents états par lesquels va passer un bundle de son installation à sa désinstallation, ainsi que
les différentes opérations d’administration qui permettent ces changements.
Nous allons dans un premier temps aborder les états et les opérations d’administration d’un
bundle avant de décrire un certain nombre de mécanismes qui interviennent durant le cycle de vie.
3.2.1 États et opérations d’administration d’un bundle
La Figure 8 définit le cycle de vie d’un bundle sous la forme d’un diagramme d’état.
En phase de
démarrage
installe
démarre
désinstalle
Désinstallé
Installé
désinstalle
/ rafraichit
/ met à jour
Résolu
résout
rafraichit / met à jour
Activé
arrête
En phase
d’arrêt
Figure 8 Cycle de vie du Bundle (Diagramme d'état)
Installé
Si un bundle est dans l’état installé c’est que l’installation a été effectuée avec succès. C’est-àdire que le bundle est valide (cf. section 3.12 de la spécification d’OSGi R4.3) et que la plate-forme lui
a assigné un identifiant unique. Cette opération d’installation est atomique et persistante. A la fin de
cette opération, un objet bundle est créé dans la plate-forme et servira à administrer le bundle
jusqu’à sa désinstallation.
Désinstallé
Un bundle est désinstallé si sa représentation physique (persistance) a bien été supprimée et
que ses différentes ressources logiques ont bien été déchargées de la plate-forme.
Résolu
Un bundle est résolu si toutes ses dépendances (package, capacité…) décrites dans le manifest
ont été pourvues.
12
En phase de démarrage
Durant la phase de démarrage d’un bundle, celui-ci est initialisé (appel de la méthode start de
l’objet bundle). Une fois initialisé, le bundle sera automatiquement activé si la politique d’activation
est eager. Dans le cas où la politique d’activation est lazy, alors l’activation ne se fera pas
immédiatement.
Une fois l’activation déclenchée, une notification est alors envoyée à la plate-forme OSGi.
Dans le cas où une classe d’activation est spécifiée par la propriété Bundle-Activator (cf. section
3.1.1), celle-ci est alors instanciée, déclenchant l’instanciation du class loader du bundle.
Une fois l’instance créée la plate-forme appelle la méthode start.
Activé
Un bundle est activé au moment de l’appel de la méthode start sur l’instance de la classe
d’activation (définie par la propriété Bundle-Activator) si celle-ci existe.
En phase d’arrêt
Un bundle actif peut être désactivé. Lorsque celui-ci est désactivé alors la méthode stop de la
classe d’activation est appelée et les contraintes suivantes doivent être respectées :



tous les services et autres ressources (sauf les packages), qui étaient utilisés, doivent être
relâchés par le bundle ;
tous les threads du bundle devraient être immédiatement stoppés ;
tous les services et listeners du bundle sont automatiquement désenregistrés de la plateforme OSGi.
3.2.2 Adaptation
Depuis la version 4.3 de la spécification, un bundle peut être « adapté » en différent types. Cette
fonctionnalité permet d’obtenir une vue spécifique du bundle, comme par exemple les liens entre les
capacités des bundles.
Le nombre de vues différentes n’est pas fixé par OSGi, cependant la spécification définit cinq
vues :



BundleRevision : cette vue permet d’accéder aussi bien aux déclarations de capacités
fournies et requises, ainsi qu’au BundleWiring associé : c’est-à-dire les liens entre les bundles
à l’exécution. Cette vue permet donc d’obtenir le graphe de dépendance à l’exécution en
terme de capacité. Notez que d’une part BundleRevision renvoie la révision courante et
d’autre part que cette vue n’a pas de sens pour un bundle désinstallé (pas de révision
courante).
BundleStartLevel : cette vue permet d’accéder et de modifier le niveau de démarrage du
bundle.
BundleWiring : cette vue permet d’accéder aux liens de capacité d’un bundle à l’exécution.
Notez qu’un lien de capacité ne peut exister qu’à partir de l’état résolu (incluant donc les
états : en phase de démarrage, en phase d’arrêt et activé).
13


FrameworkStartLevel : cette vue permet d’accéder et de modifier le niveau de démarrage du
système. Notez qu’il n’est possible d’adapter à cette vue que le bundle système.
FrameworkWiring : cette vue permet d’accéder aux dépendances des bundles. Elle permet
notamment d’obtenir la fermeture transitive des dépendances d’un bundle donné en
exécution.
3.2.3 Contexte du Bundle (Bundle Context)
Comme vu dans la couche bundle (cf. section 3.1), un bundle possède son propre class loader,
son espace de classe et d’une certaine manière son propre environnement d’exécution. Le
BundleContext représente cet environnement d’exécution et agit comme un proxy de la plate-forme
OSGi. Le BundleContext permet donc :





D’installer de nouveaux bundles ;
D’accéder aux informations des autres bundles ;
De rechercher un service (cf. section 3.3) ;
D’exposer un service (cf. section 3.3) ;
De souscrire aux différentes sources d’événements de la plate-forme OSGi.
Le BundleContext est créé à l’initialisation du bundle à la phase d’activation.
3.2.4 Événement
Le niveau cycle de vie de la plate-forme OSGi définit deux types de notifications :


Les événements relatifs aux bundles (BundleEvent) : la plate-forme OSGi émet des
notifications à chaque changement d’état d’un bundle.
Les événements relatifs à la plate-forme (FrameworkEvent) : la plate-forme OSGi émet des
notifications pour chaque changement d’état du bundle système (la plate-forme elle-même),
ainsi que pour chaque occurrence de logue (ERROR, INFO et WARNING) de la plate-forme.
Comme dit précédemment les éléments d’un bundle peuvent souscrire à ces deux sources
d’événements au travers du BundleContext.
3.2.5 Conclusion
La couche cycle de vie définit les différentes opérations d’administration que l’on peut effectuer
sur un bundle. Elle décrit les différents états par lesquels un bundle peut passer de son installation à
sa désinstallation et des notifications associées.
La version 4.3 de la spécification ajoute la notion de lien à l’exécution. Une partie de ces liens est
basée sur les capacités définies dans la couche module. Ce nouvel aspect est très intéressant car cela
permet de tracer le graphe de dépendance entre les éléments du système à l’exécution variant en
fonction du cycle de vie des bundles.
14
3.4 Couche service
Les deux couches précédentes : module et cycle de vie, permettent d’avoir une
gestion « dynamique » des bundles ; c’est-à-dire qui ne nécessite pas le redémarrage de la plateforme. Cependant cette dynamicité des modules ne concerne que les classes. Ces deux couches ne
sont pas suffisantes pour définir à elles seules des applications dynamiques ; en d’autres termes une
gestion dynamique des bundles n’implique pas nécessairement une gestion dynamique des
applications (niveau instance).
Dans OSGi la couche service va permettre la définition d’applications dites dynamiques. Pour
cela un bundle va exposer ses fonctionnalités (niveau instance) à d’autres bundles et inversement
pouvoir utiliser celles des autres. Pour conserver la dynamicité il est nécessaire d’avoir un couplage
lâche dans les dépendances de fonctionnalités.
L’un des aspects les plus importants dans l’approche orientée service (cf. encadré ci-dessous) est
le contrat (description du service). Le fournisseur utilise ce contrat pour définir ses fonctionnalités
Approche Orientée Service
L’approche orientée services [3.] est basée sur l’idée qu’une application peut être réalisée par composition
des services logiciels mis à disposition par des fournisseurs divers ([4.] [5.] appellent ce modèle « service-based
model of software »). Bien qu’il n’y ait pas de réel consensus sur la définition du concept de Service, les
différentes définitions s’accordent sur le patron d’interaction. Il faut cependant remarquer que ce patron
d’interaction n’est pas une réelle innovation en soi. En effet, il existait déjà, dans les applications distribuées, un
niveau d’indirection entre les clients et les serveurs, où les clients passent par le biais d’un intermédiaire qui
traduit le nom logique du serveur cible par l’adresse physique (cf. DNS, les courtiers ODP [6.]). Cependant
l’approche orientée service pousse le raisonnement plus loin : on ne recherche plus un serveur/élément logiciel
par rapport à son nom mais par rapport aux fonctionnalités qu’il fournit. En d’autres termes on recherche une
fonctionnalité (un service) et non un fournisseur.
Le patron d’interaction du SOC est basé sur trois acteurs :
 Les fournisseurs de services qui offrent des services
 Les consommateurs de services qui requièrent et utilisent des services offerts par des fournisseurs
 Un registre de services permettant aux fournisseurs de publier leurs services et aux consommateurs de
découvrir et de sélectionner les services qu’ils veulent utiliser.
Dans ce patron d’interaction, le fournisseur de service publie sa spécification auprès d’un courtier/registre
de services. Lorsqu’un Consommateur de service requiert un service, celui-ci recherche, auprès d’un ou
plusieurs registres de service, un service conforme à ses besoins ; une fois le service sélectionné, le
consommateur interagit avec le fournisseur de ce dernier (cf. figure ci-dessous). Notons que seule la
spécification du service est partagée entre les acteurs.
2. Découverte
et sélection
Client de
service
Registre de
services
1. Publication
Description de
Service
3. Liaison
Fournisseur
de service
15
ainsi que les propriétés non-fonctionnelles associées. Les clients se basent sur les contrats pour
sélectionner le ou les services qui conviennent à leurs besoins. Cet aspect de contrat de service
permet de définir une frontière claire et propre entre les différents éléments logiciels de
l’application. Par conséquent, puisque la recherche et l’utilisation d’un service se fait via le contrat, il
est possible de substituer l’implémentation par une autre tant que ce dernier fournit au moins le
contrat recherché. Par conséquent, OSGi utilise l’approche orientée service pour définir les
applications : car d’une part cette approche fournit un couplage lâche entre le consommateur et le
fournisseur de service, et d’autre part le registre permet la re-sélection et donc l’adaptation
(substitution) à l’exécution de l’application.
Dans cette section, nous aborderons le registre de services OSGi, puis les événements liés aux
services, avant de nous intéresser à la définition d’application dans OSGi. Finalement nous
aborderons brièvement les mécanismes spécifiés pour les services distants avant de conclure.
3.4.1 Registre de services
La couche module permet de partager les classes entre les différents bundles, alors que la
couche service va permettre de partager les instances des fonctionnalités (service) entre bundles. Ce
partage d’instances est basé sur un registre de services partagé entre tous les bundle contexts.
Un bundle peut être fournisseur et/ou consommateur de service. Nous allons dans la suite
aborder les aspects fournisseur avant de voir les aspects consommateur
Fournisseur de Service
Pour enregistrer un service, un bundle doit fournir au registre les éléments suivants :



La description des fonctionnalités : interface Java ;
Le(s) point(s) d’invocation des fonctionnalités : la référence de la classe d’implémentation ;
Les propriétés non-fonctionnelles : Tableau de propriétés Java (Properties.class).
Lorsqu’un élément d’un bundle enregistre un service, celui-ci récupère une référence de
l’enregistrement (ServiceRegistration). Cette référence sert à administrer le service : modifier les
propriétés non-fonctionnelles et désenregistrer un service.
Soit l’exemple de code suivant :
Properties properties = new Properties();
//...
ServiceRegistration serviceRegistration = bundleContext
.registerService(MonInterfaceDeService.class.getName(),
MonObjetDImplementationDuService, properties);
Le développeur du bundle doit désenregistrer son ou ses services lorsqu’il est désactivé. Noter
que certaines implémentations de plate-forme OSGi automatisent ce désenregistrement.
Consommateur de Service
Pour utiliser un service, un consommateur doit le rechercher. Il est possible de rechercher un
service selon deux modes : actif ou passif.
16
En mode actif, le consommateur fait un appel explicite au registre de services pour récupérer
une ou plusieurs références de services présents au moment de l’appel. Soit l’exemple de code
suivant :
ServiceReference[] refs =
context.getServiceReferences(MonInterfaceDeService.class.getName(), null);
En mode passif, le consommateur souscrit aux événements de la plate-forme concernant
l’apparition, la disparition et la modification des services. De cette façon, le consommateur peut
découvrir, sélectionner et utiliser un service au moment où il devient disponible ; ou sélectionner un
nouveau service si le premier vient à ne plus être disponible. Soit l’exemple de code suivant :
context.addServiceListener(this);
//...
public void serviceChanged(ServiceEvent event) {
//...
switch (event.getType()) {
case ServiceEvent.REGISTERED:
ServiceReference serviceRef = event.getServiceReference();
//...
break;
//...
Dans la pratique il est conseillé d’utiliser les deux modes : à l’activation du bundle, résoudre par
une recherche active les différents services requis, et souscrire aux notifications des services pour,
d’une part, compléter les dépendances non résolues et d’autre part, détecter le départ d’un service.
Lorsqu’un service est désenregistré, il est impératif que les consommateurs de ce service le
relâchent (cf. encadré stale reference). Par
conséquent ils doivent écouter les notifications de
Stale Reference
la plate-forme pour relâcher les services qui
Une stale reference ou référence obsolète
souhaitent partir.
en français désigne dans OSGi une référence
Java sur un objet qui soit appartient à un
bundle stoppé, soit provient d’un service
désenregistré ; dans les deux cas cet objet doit
être déréférencé. Cependant Java ne fournit
pas de mécanisme générique pour nettoyer les
références obsolètes. Le déréférencement de
ces objets est à la charge du développeur du
bundle. Les références obsolètes sont
potentiellement dangereuses car elles peuvent
bloquer le déchargement des class loaders.
Elles entrainent aussi une augmentation de la
mémoire ainsi que des problèmes de mise à
jour.
Pour éviter de tels problèmes, il est
fortement
recommandé
d’utiliser
des
intergiciels qui automatisent la dépendance
des instances (cf. section 4).
Référence de service
Dans les deux exemples précédents, la plateforme OSGi retourne une référence de service et
non le service lui-même. En effet rechercher un
service ne signifie pas nécessairement vouloir
l’utiliser, ce mécanisme permet donc d’éviter des
dépendances de service non nécessaires.
Pour utiliser un service, le consommateur
demande au registre, via le contexte du bundle, le
service ciblé par la référence. Soit l’exemple de code
suivant :
Objet service = bundlecontext
.getService(maReferenceDeService);
17
Une fois que le service n’est ou ne doit plus être utilisé, le consommateur de service doit
relâcher ce dernier. C’est-à-dire notifier au contexte du bundle que le service ne sera plus utilisé et
supprimer les références Java conservées. Soit l’exemple de code suivant :
bundlecontext.ungetService(maReferenceDeService);
this.service = null;
Au final que ce soit pour la recherche ou l’utilisation de service, il est recommandé, voir
nécessaire, de souscrire aux notifications de la plate-forme : en effet la plate-forme OSGi permet la
dynamicité des modules et des services.
3.4.2 Service Distant
Jusqu’à la version 4.3 de la spécification d’OSGi, les services étaient considérés comme étant
centralisés. Toutefois, certains mécanismes de distribution avaient été spécifiés dans le compendium
(compilation des services standardisés pour OSGi). Cependant, la spécification de la plate-forme OSGi
4.3 définit des propriétés et des mécanismes que devraient implémenter les « fournisseurs de
distribution » dans le cadre d’une distribution des services. Un fournisseur de distribution
implémente un ou plusieurs protocoles de communication (e.g. : RMI, CORBA, SOAP…). Ces
fournisseurs permettent à la fois d’exposer des services OSGi locaux sur le réseau, mais aussi de créer
des proxies /représentations des services distants exposés par d’autres plates-formes OSGi.
Après, le principe est relativement simple : un service OSGi expose dans ses propriétés les
protocoles par lesquels il souhaiterait être exporté. Par exemple le service Bob voudrait être exporté
en RMI et en SOAP, par conséquent il expose la propriété suivante :
service.exported.configs=net.rmi, net.soap
Ces propriétés sont utilisées par les « fournisseurs de distribution » pour les exposer. Ces
services exposés peuvent donc être finalement « importés » par les autres.
Il est à noter cependant certains points :



Il est possible d’accéder à un service distant par plusieurs protocoles à la fois mais pas deux
fois par le même. Par conséquent, soit les différents fournisseurs de distribution présents sur
la même plate-forme implantent des protocoles distincts, soit il existe un mécanisme de
gestion de conflits entre les fournisseurs de distribution.
Le cycle de vie des services importés doit être synchronisé ou cohérent avec le cycle de vie
du service correspondant.
OSGi ne définit pas dans la spécification de la plate-forme les mécanismes de découverte des
services distants, ni la liste des protocoles de communication autorisés et ni comment
implémenter un fournisseur de distribution. En d’autres termes, OSGi ne spécifie que les
grandes lignes / les principes de la distribution des services.
3.4.3 Application OSGi
Dans les sections précédentes nous avons vu que la modularisation était aussi bien en terme de
classes qu’en terme d’instances. Cette modularisation est à la base de la dynamicité fournie par la
plate-forme. Vient donc la question légitime : comment définir des applications et leur
dynamicité (niveau instance) dans une plate-forme OSGi?
18
Une caractéristique importante d’OSGi est qu’il
n’y a pas de modèle d’application. En effet,
Une question, voire une affirmation, qui
l’utilisation d’un modèle d’application comme, par
revient souvent est : OSGi est-il un modèle à
exemple, un ADL (architecture description
composant ? En effet bundle et composant
language) se prête mal à l’informatique pervasive et
partagent
certaines
similarités :
ils
modularisent le code, s’auto-décrivent,
au cas d’utilisation abordé à l’origine par OSGi (cf.
explicitent leurs dépendances…
section 2 : OSGi : Histoire et Motivation). En effet,
Cependant il faut bien voir qu’un bundle et
dans ces cas d’utilisation, on cherche à réifier des
un composant ont des natures et des buts bien
services/équipements disponibles sur le réseau
différents. Un bundle est au niveau classe :
domestique ou d’entreprise dans la plate-forme ; or
module, package, dépendance de classe…
alors qu’un composant est du niveau instance :
un ADL définit statiquement et par extension
dépendance de fonctionnalité…
l’architecture de l’application. Par conséquent si
De plus : dans OSGi les dépendances de
l’on souhaite prendre en charge la disponibilité de
services sont implicites (les propriétés
ces équipements, cela implique la modification de
exported-package et imported-package ne
sont pas en pratique utilisées) et d’autre part
l’ADL. Or si c’est le contexte d’exécution qui définit
le cycle de vie des services n’est pas équivalent
le modèle de l’application alors ce modèle ne définit
au cycle de vie de leur bundle.
pas l’application qui doit s’exécuter mais celle qui
En simplifiant, au niveau service/instance,
est en train de s’exécuter : dans ce cas l’ADL n’est
un bundle :
pas un ADL mais une modélisation de l’architecture
 n’explicite pas ses dépendances ;
 ne fournit pas les interfaces de
en exécution. De manière plus générale il est
contrôle du cycle de vie des services ;
difficile de définir un modèle par extension d’une
 n’a pas nécessairement un cycle de vie
application car cela va à l’encontre d’une passerelle
équivalent à celui de ses services.
à service ouverte (open service gateway). Par
En résume [7.], il faut penser qu’un bundle
conséquent, la façon de définir une application
traite de code statique et de dépendances à la
compilation, alors qu’un composant traite du
suivant la philosophie d’OSGi s’apparente à une
niveau instance et de dépendances à
composition par contrat où le dynamisme des
l’exécution.
dépendances est géré de façon programmatique
dans le bundle. Conséquemment, on peut définir la
notion d’application à deux niveaux : au niveau module et au niveau plate-forme.
OSGi : modèle à composant ?
Si on raisonne au niveau module, alors chaque bundle définit une micro-application qui peut
interagir avec d’autres ; cette interaction est contractualisée et donc ne dépend pas d’une autre
micro-application en particulier mais d’une fonctionnalité. De ce point de vue il y a autant
d’applications que de bundles.
Si on raisonne au niveau plate-forme, alors l’application peut être vue comme étant l’ensemble
des bundles et des équipements réifiés en cours d’exécution. Selon ce point de vue, il n’y a qu’une et
unique application sur la plate-forme.
Nous pensons que la notion d’application dans OSGi se situe entre ces deux extrêmes. Dans tous
les cas, dans OSGi la modification dynamique des dépendances se fait au niveau module et non au
niveau passerelle.
3.5 Conclusion
En conclusion, OSGi spécifie une plate-forme d’exécution pour des applications dynamiques.
Cette plate-forme est basée sur trois couches (cf. Figure 9):
19
Bundle
Bundle
1. La couche module définit le
concept de bundle ainsi que
les mécanismes nécessaires
au partage des classes et
des ressources. Cet aspect
de module est à la base
même du dynamisme dans
OSGi.
2. La couche cycle de vie
définit les différents états
3
par lesquels peux transiter
OSGi
1
un bundle ainsi que les
Figure 9 Les 3 mécanismes dans OSGi
différentes
opérations
d’administration sur ces derniers.
3. La couche service définit les mécanismes d’interaction des instances entre les bundles.
2
Ces trois couches permettent le partage aussi bien des classes que des instances tout en
maintenant un faible couplage entre les modules. Ces mécanismes permettent la modification de
l’architecture en cours d’exécution. Les aspects de modularité et de dynamicité influent sur la
définition d’une application dans OSGi. Par conséquent dans OSGi, une application est une
composition de modules dont les interactions sont définies contractuellement ; de cette façon il est
possible de substituer une interaction par une autre.
Par contre, autant le partage des classes par la couche module est géré par la plate-forme,
autant le partage des fonctionnalités en terme de services est à la charge des développeurs de
bundle. Or nous avons vu que la gestion des dépendances par le bundle est un aspect critique pour le
dynamisme de l’« application ». Cette gestion manuelle des dépendances est donc une source
d’erreur : une erreur de gestion de dépendances d’un bundle (e.g. : stale reference,…) peut nuire à la
dynamicité de toute la plate-forme. Il est donc recommandé d’utiliser des outils qui automatisent
cette gestion.
20
4 Intergiciels
Dans les sections précédentes nous avons abordé les mécanismes fournis par la plate-forme
OSGi pour exécuter des applications « dynamiques ». Nous avons observé trois choses :



La gestion du partage d’instance de service est manuelle et propre à chaque bundle. Cette
gestion est un aspect critique du dynamisme de la plate-forme.
Le cycle de vie des services n’est pas nécessairement équivalent au cycle de vie du bundle. En
d’autres termes, un service peut apparaitre ou disparaitre alors que son bundle est toujours
en état actif.
Une application dans OSGi est une composition de bundle en interaction.
Le problème soulevé par le premier point peut être résolu en automatisant la gestion des
dépendances. Les deuxième et troisième points sont problématiques pour l’adaptation de
l’environnement d’exécution, car d’une part il n’est pas possible d’agir sur un service en particulier
(création, destruction…) et d’autre part la composition en terme de bundle se prête mal à la
modélisation du but d’une application (e.g. : ADL). On aimerait pour cela avoir un modèle similaire au
composant qui fournirait les opérations d’administration et un accès au cycle de vie des
implémentations de services. L’approche à composant ne peut pas être réutilisée telle quelle car elle
possède une limitation non négligeable dans le cas d’OSGi qui est la staticité de l’architecture de
l’application. Dans [8.], Humberto Cervantes explique le fait qu’en général les implémentations de
l’approche à composant sont limitées vis à vis de la possibilité de supporter la disponibilité
dynamique car :




Les applications sont assemblées en phase de conception et non à l’exécution.
Dans les applications composées de façon déclaratives, le but de l’application est défini par
extension et n’autorise donc pas les changements à l’exécution.
Dans le cas d’une composition impérative, il est possible de reconfigurer l’application
(création et destruction d’instance, établissement de connexion) mais seulement avec des
classes de composants déjà disponibles durant la phase de conception.
La disparition d’une classe de composant à l’exécution n’est pas une hypothèse de
l’approche à composants.
Pour combler cela, H. Cervantes propose d’introduire l’approche orientée service pour la
communication entre les composants d’un modèle à composant. Il nomme cette approche :
composant orienté service (Service-Oriented Component) [8.][9.].
En résumé, nous avons vu que développer directement des applications dynamiques sur OSGi
peut être compliqué. Il est donc recommandé d’utiliser des intergiciels qui automatisent la gestion
des dépendances. D’autre part, mettre en place des mécanismes d’adaptation est compliqué car
l’administration des services est limitée et l’état courant de l’architecture en terme d’instances est
incomplet. L’utilisation de l’approche composant orienté service permet de résoudre ces problèmes
tout en préservant le dynamisme de la plate-forme.
Dans cette section, nous allons brièvement expliquer l’approche à composant orienté service.
Puis décrire brièvement trois intergiciels utilisant cette approche : Declarative Services, Blueprint et
iPOJO.
21
4.1 COMPOSANT ORIENTE SERVICE
L’approche composant orienté service est issue des travaux de H. Cervantes et de R. S. Hall qui le
définissent de la manière suivante :
“Service-Oriented Component model introduces concepts from service orientation into a
component model. The motivation for such a combination emerges from the need to
introduce explicit support for dynamic availability into a component model.” (cf. [8.].)
La principale caractéristique des modèles à composant orienté service réside dans l’interaction
entre les composants. En effet, dans cette approche les composants ne sont pas liés directement
entre eux. Ils exposent leurs fonctionnalités sous la forme d’un ou plusieurs services et utilisent les
fonctionnalités des autres composants au travers de ces services. En résumé, dans les modèles à
composant orienté service le « binding » est remplacé par l’approche à service (publication,
recherche, sélection, utilisation).
La Figure 10 résume les différentes caractéristiques d’un composant orienté service :






Interfaces de Service fournies : les fonctionnalités du composant sont exposées via une
description, dans le cas de [8.], cette description est une interface Java.
Dépendances de Service requises : les dépendances de fonctionnalité sont déclarées par le
composant et prises en charge par le conteneur. La résolution de la dépendance du
conteneur se fait suivant l’approche orientée service.
Interface et dépendance de contrôle : les interfaces de contrôle permettent aux instances de
composants de participer aux activités de reconfiguration dynamique.
Propriétés de configuration : propriétés fonctionnelles du service.
Propriétés de Service : propriétés exposées avec les interfaces de service
Exposition et dépendances de ressources : ce sont des références à des ressources exposées
qui peuvent être utilisées par d’autres composants. Dans le cas où elles sont requises, cellesci sont recherchées dans les ressources exposées par les autres composants.
Interfaces de
contrôle
Propriétés de
configuration
Propriétés de
services
Interfaces des
services requis
Composant
Interfaces des
services fournis
Ressources
exportées
Dépendances de
ressource
Figure 10 Composant Orienté Service défini par [8.]
22
La combinaison de l’approche à composant et celle des services permet aux développeurs de se
concentrer sur le code fonctionnel / métier et de déléguer la gestion de la disponibilité dynamique
ou du cycle de vie des services (composants) aux conteneurs.
Dans certaines technologies à service comme OSGi, le code qui gère la disponibilité dynamique
des services est assez complexe et est à la charge du développeur. L’utilisation de conteneurs
inspirée des composants pour gérer des aspects non fonctionnels, va permettre de gérer, entre
autres, la disponibilité dynamique, ce qui va simplifier la tâche des développeurs.
4.2 Intergiciels Composant Orienté Service
Il existe plusieurs intergiciels au-dessus d’OSGi. Nous allons cependant nous intéresser
brièvement à seulement trois d’entre eux qui utilisent l’approche composant orienté service :
Declarative Services
Un des intergiciels les plus simples. Declarative services a été standardisé dans le compendium
d’OSGi dans la version 4. Cette spécification définit une approche pour la gestion des dépendances
de service. Cette approche composant orienté service se concentre sur l’injection des dépendances
de service et sur le contrôle du cycle de vie des composants.
Blueprint
Blueprint est issue de la plate-forme à composant Spring Dynamic Module. Blueprint cible les
applications orientées entreprises hautement configurables. De fait, cet intergiciel fournit des
mécanismes plus avancés que Declarative Services que ce soit pour le cycle de vie du composant
(e.g. : politique d’instanciation) ou pour la gestion du dynamisme (e.g. : indirection des dépendances
au travers d’un proxy).
iPOJO
Le modèle composant orienté service iPOJO [10.] pour injected Plain Old Java Object – est
développé au-dessus de la plate-forme OSGi. Il est actuellement hébergé par le projet Apache Felix
(une implémentation de la plate-forme OSGi).
iPOJO est caractérisé principalement par deux aspects :


il utilise l’injection de byte code pour instrumenter le conteneur du composant à la
compilation ou à l’exécution ;
il propose une approche qui permet d’ajouter facilement des aspects non-fonctionnels aux
composants sans avoir à modifier le code métier.
Notez que le modèle iPOJO applique le principe de la séparation de préoccupations à tous les
aspects non-fonctionnels en se servant du concept de conteneur.
Comparaison des intergiciels
Le tableau ci-dessous (extrait de [7.]) résume les principales différences entre ces trois
intergiciels.
23
Fonctionnalité
Declarative Services
BluePrint
iPOJO
Oui
Non
Non
Oui
Non
Non
Non
Oui
Oui
Non
Oui
Oui
Oui
Non
Oui
Non
Oui
Oui
Oui
Oui
Oui
Oui
Oui
Oui
Oui
Non
Non
Oui
Oui
Oui
Non
Oui
Oui
Oui
Oui
Oui
Non
Non
Oui
Non
Oui
Oui
Oui
Oui
Non
Oui
Oui
Oui
Non
Oui
Oui
Oui
Non
Non
Oui
Non
Non
Oui
Oui
Oui
Injection de dépendance
Injection de « callback »
Injection du constructeur
Injection d’attribut
Injection de « setter »
Injection de proxy
Injection de liste
Injection d’objet nul
Cycle de vie
« callback »
(activation/désactivation)
Patron fabrique
3
Damping
Synchronisation des attributs
Contrôle du cycle de vie du
composant
Contrôle du cycle de vie du service
Configuration
Configuration des propriétés
Configuration des attributs
Administration de la configuration
(Config Admin)
Service
Type des attributs customisable
Approche des descriptions
XML
Annotations Java
API
5 Référence
[1.] JSR008 - http://jcp.org/en/jsr/detail?id=008
[2.] OSGi Alliance - http://www.osgi.org
[3.] M. P. Papazoglou. « Service-oriented computing: concepts, characteristics and directions ». WISE
2003. Proceedings of the Fourth International Conference on Web Information Systems
Engineering, 2003, 3-12
[4.] K. Bennett, P. Layzell, D. Budgen, P. Brereton, L. Macaulay et M. Munro. « Service-based
software: the future for flexible software ». APSEC 2000. Proceedings. Seventh Asia-Pacific,
Software Engineering Conference, 2000. 214-221
[5.] M. Turner, D. Budgen et P. Brereton. « Turning software into a service ». Computer, 2003, 36, 3844
[6.] J. Indulska, K. Raymond et M. Bearman. « A Type Management System for an ODP Trader »
Proceedings of the IFIP TC6/WG6.1 International Conference on Open Distributed Processing II,
North-Holland Publishing Co., 1994, 169-180
3
Signifie dans ce cas, faire une indirection de la dépendance au travers d’un proxy pour cacher et amortir le
dynamisme du service cible.
24
[7.] R. S. Hall, K. Pauls, S. McCulloch et D. Savage. « OSGi in Action : Creating Modular Applications in
Java ». Manning Publications. 2011
[8.] H. Cervantes. « Vers un modèle à composants orienté services pour supporter la disponibilité
dynamique ». Thèse de l’Université Joseph Fourier, Grenoble, 2004
[9.] H. Cervantes et R. S. Hall. « Autonomous Adaptation to Dynamic Availability Using a ServiceOriented Component Model ». Proceedings of International Conference of Software Engineering
(ICSE), IEEE Computer Society, 2004, 614-623
[10.] C. Escoffier. « iPOJO : Un modèle à composant à service flexible pour les systèmes
dynamiques ». Thèse de l’Université Joseph Fourier, Grenoble, 2008
25
Téléchargement