OSGi et les Components
Les bases d'OSGi
Architecture

L'architecture d'OSGi est présenté comme un modèle en plusieurs couches :
- Les Bundles composent les applications
- Le Module gère le class loader et les dépendances de chaques bundles
- La couche Cycle de vie est l'API qui permet de gérer les bundles (installation, exécution, ...)
- Le Registre de service est l'API qui permet de gérer les services fournis par des bundles (enregistrement des services, maintient des références, ...)
- Les Services permettent de lier les bundles entre eux de manière dynamique (des bundles vont fournir des services et d'autre vont en consommer)
Bundles
Les bundles sont les composants qui compose les application OSGi. Un bundle est une archive Jar contenant des classes Java, des ressources (comme des librairie) et un fichier MANIFEST.MF (présenté ci-dessous)

Ce fichier MANIFEST.MF va décrire le bundle et va dire au framework comment l'utiliser. Dans ce fichier manifest, seul "Bundle-SymboliqueName" est obligatoire, car il permet au framework de différencier les bundles.
"Bundle-Activator" permet de spécifier une classe exécutable dans le bundle (de la même façon qu'une classe "main"). Cette classe doit implémenter l'interface BundleActivator et ses méthodes start(BundleContext) et stop(BundleContext) qui seront appelées lors du démarrage (méthode start) et de l'arrêt (méthode stop) du bundle. Sur l'image suivante, vous pouvez voir à quoi ressemble ce bundle lors de sa création dans Eclipse :

Une application en OSGi est généralement composé de plusieurs bundle, qui peuvent également être utilisé par plusieurs application simultanément. Ces bundles peuvent interagir ensemble (avec des dépendances) et avec le système :

Module
Le module est la partie qui permet la mise en oeuvre des bundles dans le framework. Il est responssable de la gestion :
-
Des dépendances entre les bundles. Ces dépendances sont rensignées dans le MANIFEST.MF de chaques bundles, avec les header "Import-Package" et "Export-Package".
-
Du classloader. Dans le framework, chaque bundle possède sont propre classloader. Les classes loader possèdent ensuite une références vers celui de chaque bundle auquel il dépend : il a donc accès à toutes les classes et instances géré par le second classe loader.
ATTENTION : Ce méchanisme est à connaitre parfaitement si vos bundles échangent des instances entre eux, car il peut y avoir des problèmes de "ClassCastException" entre deux objets de même classe simplement parce que leur class loader est différent !
Cycle de vie d'un bundle
Chaque bundle a son propre cycle de vie. Après avoir démarré le framework, il n'y a aucun bundle. Il faut commencer par en installer un. Si toutes ses dépendances (les "Import-Package") sont remplis, il passera en "Resolved".
On peut ensuite lancer le bundle (start), ce qui appelera la méthode start du BundeActivator. Pendant que la méthode "start" s'exécute, le bundle est dans l'état "Starting", et à la fin de l'exécution il passera dans l'état "Active".
Le bundle peut être arrêté (stop), ce qui appellera la méthode "stop" du BundleActivator. Comme pour le démarrage, le bundle passera du statut "Active" à "Stopping" puis retournera à l'état "Resolved".
Le bundle peut également être supprimé du framework en le désinstallant.

