OSGi : Mais qui c’est ce Hausse Guy?

16 Fév

Ce billet a pour but d’expliquer brièvement le fonctionnement de la plateforme logicielle OSGi et de montrer un cas d’utilisation.

OSGi (Open Services Gateway initiative) est une spécification « qui définit un modèle de gestion de cycle de vie d’une application, un répertoire (registry) de services, un environnement d’exécution et des modules ». L’implémentation d’un tel système est donc un socle logiciel qui permet de gérer des composants logiciels (appelés des bundles) entre eux:

  • dépendance,
  • version nécessaire,
  • déploiement (à chaud),
  • cycle de vie,
  • fonctionnalités exposées.

Architecture

Une notion à bien comprendre est que OSGi se base sur des composants, des bundles, qui vont dialoguer entre eux pour effectuer des fonctionnalités et appeler les fonctionnalités fournies par les autres bundles. Un bon exemple est le bundle Tomcat qui permet de fournir un moteur de servlets que pourront exploiter les autres bundles.

Pour mieux comprendre, voici une comparaison avec l’architecture en couches que l’on retrouve souvent dans les projets JEE:

Architecture en couches

Ici, pour gérer le projet global, les différentes couches accèdent entre elles de façon descendante (front n’accède qu’à service et service au DAO), hormis le domaine qui est commun. Pour réaliser cela, les trois couches sont souvent hébergées dans trois projets distincts, qui dépendent les unes des autres par le classpath.

OSGi va faire pour moi un peu la même chose, si ce n’est qu’il va gérer par lui même:

  • la dépendance entre les couches/composants, qui seront des bundles,
  • les librairies (jar) (ce qui pose problème quand deux couches utilisent la même mais dans des versions différentes),
  • le déploiement.

La différence avec OSGi serait l’architecture suivante:

La même architecture en OSGi

Plus-value

Pour moi, les vraies plus-values:

  • le déploiement à chaud, sans redémarrer le serveur ou autres, c’est bien chouette (si l’on veut corriger un bug ou ajouter une fonctionnalité, on peut simplement redémarrer le bundle en question),
  • l’architecture modulaire/par composant, par essence.

Qui utilise OSGi?

Les plus connus sont:

  • Eclipse (par Equinox, leur implémentation),
  • Apache Sling,
  • Jonas, Glassfish, Spring DM Server pour les serveurs.

Cas d’utilisation

Ce cas d’utilisation va permettre d’afficher une simple file de tâches mais permettra de comprendre comment interagissent les différentes couches entre elles. Le principe va être de créer un bundle (projet de plugin dans Eclipse) pour chaque couche. Cependant, pour simplifier, je ne vais pas faire la persistance dans ce billet. Ce sera donc la couche service qui se chargera de retourner simplement la liste des tâches.

Pour écrire des bundles, il préférable d’utiliser la mouture d’Eclipse étudiée pour faire des bundles: Eclipse PDE (Eclipse for RCP/Plug-in Developers).

La partie DAO

Cette partie, pour l’exercice, ne contiendra que le domaine, en fait, c’est à dire, les POJO.

Faire File/New/Other puis Plug-in Development/Plug-in Project.

Création du projet de plugin

Bien choisir un framework standard pour le plugin et nommer le comme un package, c’est la convention de nommage pour les bundles. Faire « next ».

Paramétrage du bundle

Dans la fenêtre de paramétrage du bundle, tous les champs ont de l’importance:

  • l’id permettra de d’identifier notre bundle dans OSGi,
  • la version, la jvm, seront des paramètres qui pourront bloquer l’utilisation s’ils ne sont pas corrects dans l’environnement d’utilisation, et la version est explicitement déclarée dans la dépendance entre les bundles,
  • la classe d’activation du bundle(qui va être générée).

Sélectionner la génération de la classe « Activator », qui générera une classe permettant de gérer les opérations à effectuer au démarrage du bundle. Faire « Finish ».

Le fichier intéressant à regarder est le fichier META-INF/MANIFEST.MF qui contient le paramétrage du bundle. Ce qui est intéressant de comprendre:

  • Bundle-Activator: classe qui gère l’activation(ici, Activator.java)
  • Require-Bundle: les bundles nécessaires
  • Import-Package: les packages en particulier : Import-Package: org.osgi.framework;version= »1.3.0″ la version permet de gérer la dépendance(version minimale)
  • Export-Package: permet de dire quels packages seront accessibles par les autres bundles(dans notre cas, il faut exporter le package du domain qui va être utilisé dans les autres bundles: fr.adioss.osgitask.domain)
  • les jars et librairies utilisées(dans le classpath)

La view graphique d’Eclipse permet de gérer facilement ces paramètres(double clic sur le fichier).

Dans la classe Activator.java, modifier le code:

public void start(BundleContext context) throws Exception {
 System.out.println("démarrage du bundle fr.adioss.osgitask.domain");
 }

Pour le lancer, dans l’onglet « overview » du fichier MANIFEST.MF, faire « Launch the framework ».

Dans la vue console, le output est bien présent ce qui prouve que notre bundle a bien démarré et qu’il fonctionne correctement. La console va permettre d’exécuter des commandes sur notre conteneur OSGi. « ss », par exemple, permet de voir les bundles qui sont chargés et leur état:

La vue console d'Eclipse permet de jouer des commandes sur notre container

Il faut maintenant créer la partie DAO à proprement dit. Pour cela, seule une classe va être créée.

package fr.adioss.osgitask.domain;
 
public class Task {
 private String Name;
 private String Description;
 
public String getName() {
 return Name;
 }
 
public void setName(String name) {
 Name = name;
 }
 
public String getDescription() {
 return Description;
 }
 
public void setDescription(String description) {
 Description = description;
 }
 
}

La partie Service

Comme précédemment, faire un nouveau projet de plugin:

Création du bundle service

Rajouter une interface:

package fr.adioss.osgitask.service;
 
import java.util.Collection;
 
import fr.adioss.osgitask.domain.Task;
 
public interface TaskService {
 Collection<Task> findAllUsers();
}

Un point à remarquer est que, du fait que le package précédent est exporté, l’accès à l’activateur du bundle Domain est accessible dans ce bundle:

Accès à l'activateur depuis un autre bundle???

Ce qui est bien, mais pas top. Pour éviter cela, il faut enlever l’activateur de ce package et le déplacer dans un autre (ex: en utilisant « Refactor » et « Move », l’ensemble du bundle, dont le MANIFEST.MF, sera modifié).

Et l’implémentation, qui retourne manuellement une liste de Task (pour l’exercice…):

package fr.adioss.osgitask.service.impl;
 
import java.util.ArrayList;
import java.util.Collection;
 
import java.util.List;
 
import fr.adioss.osgitask.domain.Task;
 
import fr.adioss.osgitask.service.TaskService;
 
public class TaskServiceImpl implements TaskService {
 private Collection<Task> tasks = null;
 
@Override
 public Collection<Task> findAllTasks() {
 // simulation ici de la récupération des taches d'un dao
 List<Task> tasks = new ArrayList<Task>();
 Task t1 = new Task();
 t1.setDescription("la description 1");
 t1.setName("le nom 1");
 tasks.add(t1);
 Task t2 = new Task();
 t2.setDescription("la description 2");
 t2.setName("le nom 2");
 tasks.add(t2);
 return tasks;
 }
 }

Pour utiliser ce service, une factory va être créée:

package fr.adioss.osgitask.service;
 
import fr.adioss.osgitask.service.impl.TaskServiceImpl;
 
public class ServiceFactory {
 private static ServiceFactory INSTANCE = new ServiceFactory();
 private TaskService taskService = null;
 
private ServiceFactory() {
 
}
 
public static ServiceFactory getInstance() {
 return INSTANCE;
 }
 
public TaskService getTaskService() {
 if (taskService == null) {
 taskService = createTaskService();
 }
 return taskService;
 }
 
private TaskService createTaskService() {
 TaskService taskService = new TaskServiceImpl();
 return taskService;
 }
 
}

Le package exporté est la factory, et non l’implémentation du service! Pour cela, c’est le package fr.adioss.osgitask.service qui sera exporté du bundle. C’est la factory qui nous retournera l’objet implémenté.

La partie Front/Cliente

Comme précédemment, faire un nouveau projet de plugin:

Création du bundle client

Ajouter le bundle service dans les « Required Plug-in » du MANIFEST.MF.

L’activateur sera simplement utilisé pour exploiter le service:

package fr.adioss.osgitask.front;
 
import java.util.Collection;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import fr.adioss.osgitask.domain.Task;
import fr.adioss.osgitask.service.ServiceFactory;
import fr.adioss.osgitask.service.TaskService;
 
public class Activator implements BundleActivator {
 
 public void start(BundleContext context) throws Exception {
 System.out.println("Start Bundle [" + context.getBundle().getSymbolicName() + "]");
 TaskService taskService = ServiceFactory.getInstance().getTaskService();
 Collection<Task> tasks = taskService.findAllTasks();
 for (Task task : tasks) {
 System.out.println("task [nom=" + task.getName() + ", description=" + task.getDescription() + "]");
 }
 }
 
 public void stop(BundleContext context) throws Exception {
 System.out.println("Stop Bundle [" + context.getBundle().getSymbolicName() + "]");
 }
}

Et le résultat, dans la console:

Utilisation du bundle service, dans le bundle front

Conclusion

Je ne suis pas vraiment rentrer dans le détail, mais cet exemple a permis de voir comment:

  • fonctionne brièvement OSGI,
  • faire une architecture en couche avec OSGI,
  • utiliser des fonctionnalités des différents bundles entre eux,
  • passer de couche en couche le domain en utilisant l’export de package.

Ce qui me séduit dans cet outil:

  • indéniablement, le chargement à chaud des bundles, ce qui est assez révolutionnaire puisque si un bundle bug, il est possible de le couper, de le recharger, sans pour autant priver tous les utilisateurs de l’ensemble des fonctionnalités,
  • la programmation orientée composant.

Dans un prochain billet, il sera bien de présenter le couplage avec Spring(intégré avec Spring DM), l’utilisation d’un ORM, tel Hibernate, et le découplage complet entre Domain et DAO, l’intégration au server SpringSource Dm… A ce moment là, cela commencera à être vraiment intéressant…

Source:

http://angelozerr.wordpress.com/

http://www.javaworld.com/javaworld/jw-04-2008/jw-04-osgi2.html?page=1

4 thoughts on “OSGi : Mais qui c’est ce Hausse Guy?

  1. Salut Mr adrien.
    Alors sympa cette petite introduction mais ca serait cool de faire un cas un peu plus pratique 😉 Lache toi un peu ! 🙂
    Alors j’essaye de donner une idée :
    OSGI avec :
    – Module Servlet
    – Module Application Web (3 couches standard)
    – Module performance avec AOP
    – Module Supervision pour monitorer ton application
    – Module décisionnel
    C’est tout 😉 Voila l’idée c’est plus une séparation fonctionnelle. Bon courage 😉

    • Très, très bonnes idées. Je vais essayer de combattre mes problèmes de sommeil et je m’y attaque 😉
      Effectivement, ça serait terrible de faire tout ce travail. Je vais y aller en douceur pour le moment. Le prochaine bien parlera persistance et ça sera déjà un peu plus intéressant.

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *