Tutorial OSGi

Service Binder

Le Service Binder est un mécanisme qui facilite la creation de bundles et qui gére les dépendances de services de façon automatique. Les dépendances sont décrites avec une cardinalité et une politique (statique ou dynamique).

Le Service Binder est déployé comme un bundle classique. Si les exemples de ce TP on été suivis dans l'ordre, le ServiceBinder doit déjà être présent dans le framework (verifier avec ps). Sinon, il est possible de l'installer à partir de l'URL suivante:


-> install http://gravity.sf.net/servicebinder/jar/servicebinder1.0.jar

Pour cet example, qui a la même fonctionnalité que celle de l'example antérieur, il n'est pas nécessaire d'écrire un activateur, le Service Binder exporte une classe appelée GenericActivator qu'il suffit d'étendre. L'activateur se réduit donc au code suivant:

/*
* OSGi and Gravity Service Binder tutorial.
* Copyright (c) 2003 Richard S. Hall
* http://oscar-osgi.sourceforge.net
**/

package tutorial.example7;

import org.ungoverned.gravity.servicebinder.GenericActivator;

public class Activator extends GenericActivator
{
}

Le Service Binder utilise un fichier en format xml dans lequel les dépendances de service sont décrites. La dépendance que nous avons entre le SpellCheckService et les services DictionaryService est de type dynamique multiple et obligatoire. Ceci veut dire que le SpellCheckService nécessite d'au moins un dictionnaire pour fonctionner, et il est capable d'en gérer plusieurs et de les incoporer lors de l'éxecution. Le fichier xml doit être sauvé sous le nom metadata.xml et mis dans le même répertoire que l'activateur.

<?xml version="1.0" encoding="UTF-8"?>
<bundle>

<instance class="tutorial.example7.SpellCheckServiceImpl">
<service interface="tutorial.example5.service.SpellCheckService"/>
<property name="version" value="1.0" type="string"/>
<requires
service="tutorial.example2.service.DictionaryService"
filter="(Language=*)"
cardinality="1..n"
policy="dynamic"
bind-method="addDictionary"
unbind-method="removeDictionary"
/>
</instance>
</bundle>

Le Service Binder va créer une instance de composant à partir de la classe SpellCheckServiceImpl. Ce composant sera crée au moment ou au moins un dictionnaire deviendra disponible et sera détruite lorsqu'il n'y aura plus de dictionnaires. Le composant fournit un service SpellCheckService qui est enregistré avec une propriété version de type string. Les methodes addDictionary() et removeDictionary() seront appelées sur le composant par le ServiceBinder pour lui passer les références des services qui deviennent disponibles.

Le code de SpellCheckImpl ne contient plus de références à OSGi et ne contient plus de code déstiné à gérer les dépendances, ceci simplifie beaucoups le développement.

/*
* OSGi and Gravity Service Binder tutorial.
* Copyright (c) 2003 Richard S. Hall
* http://oscar-osgi.sourceforge.net
**/


package tutorial.example7;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.StringTokenizer;

import tutorial.example2.service.DictionaryService;
import tutorial.example5.service.SpellCheckService;

/**
* This class re-implements the spell check service of Example 5.
* This service implementation behaves exactly like the one in
* Example 5, specifically, it aggregates all available dictionary
* services, monitors their dynamic availability, and only offers
* the spell check service if there are dictionary services
* available. The service implementation is greatly simplified,
* though, by using the Service Binder. Notice that there is no OSGi
* references in the application code; intead, the metadata.xml
* file describes the service dependencies to the Service Binder, which
* automatically manages them and it also automatically registers the
* spell check services as appropriate.
**/

public class SpellCheckServiceImpl implements SpellCheckService
{

// List of service objects.

private ArrayList m_svcObjList = new ArrayList();

/**
* This method is used by the Service Binder to add
* new dictionaries to the spell check service.
* @param dictionary the dictionary to add to the spell
* check service.
**/

public void addDictionary(DictionaryService dictionary)
{

// Lock list and add service object.

synchronized (m_svcObjList)
{
m_svcObjList.add(dictionary);
}
}

/**
* This method is used by the Service Binder to remove
* dictionaries from the spell check service.
* @param dictionary the dictionary to remove from the spell
* check service.
**/

public void removeDictionary(DictionaryService dictionary)
{

// Lock list and remove service object.

synchronized (m_svcObjList)
{
m_svcObjList.remove(dictionary);
}
}

/**
* Checks a given passage for spelling errors. A passage is any
* number of words separated by a space and any of the following
* punctuation marks: comma (,), period (.), exclamation mark (!),
* question mark (?), semi-colon (;), and colon(:).
* @param passage the passage to spell check.
* @return An array of misspelled words or null if no
* words are misspelled.
**/

public String[] check(String passage)
{

// No misspelled words for an empty string.

if ((passage == null) || (passage.length() == 0))
{
return null;
}

ArrayList errorList = new ArrayList();

// Tokenize the passage using spaces and punctionation.

StringTokenizer st = new StringTokenizer(passage, " ,.!?;:");

// Lock the service list.

synchronized (m_svcObjList)
{

// Loop through each word in the passage.

while (st.hasMoreTokens())
{
String word = st.nextToken();

boolean correct = false;

// Check each available dictionary for the current word.

for (int i = 0; (!correct) && (i < m_svcObjList.size()); i++)
{
DictionaryService dictionary =
(DictionaryService) m_svcObjList.get(i);

if (dictionary.checkWord(word))
{
correct = true;
}
}

// If the word is not correct, then add it
// to the incorrect word list.

if (!correct)
{
errorList.add(word);
}
}
}

// Return null if no words are incorrect.

if (errorList.size() == 0)
{
return null;
}

// Return the array of incorrect words.

return (String[]) errorList.toArray(new String[errorList.size()]);
}
}

Finalement le manifest contient une ligne en plus qui permettra au ServiceBinder de connaitre l'emplacement du fichier metadata.xml. On doit aussi importer le package contenant le GenericActivator.

Bundle-Activator: tutorial.example7.Activator
Import-Package: tutorial.example2.service, tutorial.example5.service,
org.ungoverned.gravity.servicebinder
Import-Service: tutorial.example2.service.DictionaryService
Bundle-Name: Service Binder Spell check service
Bundle-Description: A bundle that implements a simple spell check service
Bundle-Vendor: Richard Hall
Bundle-Version: 1.0.0
Metadata-Location: tutorial/example7/metadata.xml

Voici le fichier build_example7.xml permettant de créer le bundle.

Attention: il faut copier le servicebinder.jar dans les librairies (repertoire lib) avant de compiler!

Avant de tester, il faut arreter le service de verification crée auparavant.

-> install file:/projet/bundle/example7.jar
-> ps

[  0] [Active     ] System Bundle
[  1] [Active     ] Oscar Shell Service
[  2] [Active     ] Shell TUI
[  3] [Active     ] Oscar Bundle Repository
[  5] [Active     ] Service listener example
[  6] [Active     ] English dictionary
[  7] [Active     ] French dictionary
[  8] [Installed  ] Dictionary client
[  9] [Resolved   ] servicebinder.jar
[ 10] [Resolved   ] Table Layout
[ 11] [Installed  ] Gravity
[ 12] [Active     ] Shell Components
[ 13] [Active     ] Shell GUI
[ 14] [Installed  ] Dictionary client
[ 15] [Resolved   ] Spell check service
[ 16] [Installed  ] Spell check client
[ 17] [Active     ] Service Binder Spell check service

-> start 16
Enter a blank line to exit.
Enter passage: welcome to osgi
Passage is correct.
Enter passage:

->


Cet exemple permet d'apprecier les simplifications qu'apporte le ServiceBinder. L'avantage du fichier descripteur est qu'il est possible de réaliser des changements de manière très simple, on peut par exemple changer le filter pour que notre service soit restreint a une seule langue.

Retour au sommaire


Last update: 22 February 2003
contact: Humberto.Cervantes@imag.fr
Homepage