Tutorial OSGi

Creation d'un client pour le service dictionnaire

Nous allons créer un client interactif pour tester le service dictionnaire. Ce client ne se servira du service dictionnaire que si il le trouve lors de son démarrage.

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


package tutorial.example3;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;

import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;

import tutorial.example2.service.DictionaryService;

/**
* This class implements a bundle that uses a dictionary
* service to check for the proper spelling of a word by
* check for its existence in the dictionary. This bundle
* uses the first service that it finds and does not monitor
* the dynamic availability of the service (i.e., it does not
* listen for the arrival or departure of dictionary services).
* When starting this bundle, the thread calling the start()
* method is used to read words from standard input. You can
* stop checking words by entering an empty line, but to start
* checking words again you must stop and then restart the bundle.
**/

public class Activator implements BundleActivator
{

/**
* Implements BundleActivator.start(). Queries for
* all available dictionary services. If none are found it
* simply prints a message and returns, otherwise it reads
* words from standard input and checks for their existence
* from the first dictionary that it finds.
* (NOTE: It is very bad practice to use the calling thread
* to perform a lengthy process like this; this is only done
* for the purpose of the tutorial.)
* @param context the framework context for the bundle.
**/

public void start(BundleContext context) throws Exception
{

// Query for all service references matching any language.

ServiceReference[] refs = context.getServiceReferences(
DictionaryService.class.getName(), "(Language=*)");

if (refs != null)
{
try
{
System.out.println("Enter a blank line to exit.");
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
String word = "";

// Loop endlessly.

while (true)
{

// Ask the user to enter a word.

System.out.print("Enter word: ");
word = in.readLine();

// If the user entered a blank line, then
// exit the loop.

if (word.length() == 0)
{
break;
}

// First, get a dictionary service and then check
// if the word is correct.

DictionaryService dictionary =
(DictionaryService) context.getService(refs[0]);
if (dictionary.checkWord(word))
{
System.out.println("Correct.");
}
else
{
System.out.println("Incorrect.");
}

// Unget the dictionary service.

context.ungetService(refs[0]);
}
} catch (IOException ex) { }
}
else
{
System.out.println("Couldn't find any dictionary service...");
}
}

/**
* Implements BundleActivator.stop(). Does nothing since
* the framework will automatically unget any used services.
* @param context the framework context for the bundle.
**/

public void stop(BundleContext context)
{

// NOTE: The service is automatically released.

}
}

Noter que le code fait référence au package du service dictionnaire défini dans l'exemple antérieur. Voici le manifeste pour le client:

Bundle-Activator: tutorial.example3.Activator
Import-Package: tutorial.example2.service
Import-Service: tutorial.example2.service.DictionaryService
Bundle-Name: Dictionary client
Bundle-Description: A bundle that uses the dictionary service if it finds it at startup
Bundle-Vendor: Richard Hall
Bundle-Version: 1.0.0

Voici aussi le fichier build_example3.xml pour ant. Lancer la cible example3.bundle, si tout se passe bien, nous devons retrouver le fichier example3.jar sous le répertoire bundle que nous pouvons installer dans le framework.

-> install file:/chemin_du_projet/bundle/example3.jar
-> ps

[  0] [Active     ] System Bundle
[  1] [Active     ] Oscar Shell Service
[  2] [Active     ] Shell TUI
[  3] [Active     ] Oscar Bundle Repository
[  4] [Active     ] Service listener example
[  5] [Active     ] English Dictionary
[  6] [Installed  ] French Dictionary
[  7] [Installed  ] Dictionary Client
-> start 7
Enter a blank line to exit.
Enter word: wellcome
Incorrect.
Enter word: welcome
Correct.
Enter word:
->

Question: Que se passe-t'il si le dictionnaire n'est pas actif lorsqu'on active le client ?

A Faire: Modifier le client pour qu'il soit à l'écoute des évènements du framework. Pour cela il faut implementer l'interface ServiceListener et s'enregistrer auprès du framework lors du démarrage. La propriété objectClass est ajoutée par défault par le framework chaque fois qu'un service est enregistré:

// Listen for events pertaining to dictionary services.
m_context.addServiceListener(this,"(&(objectClass="
+ DictionaryService.class.getName() + ")" + "(Language=*))");

Il faut ensuite implementer l'interface ServiceListener qui n'a qu'une méthode: serviceChanged()

/**
* Implements ServiceListener.serviceChanged(). Checks
* to see if the service we are using is leaving or tries to get
* a service if we need one.
* @param event the fired service event.
**/

public void serviceChanged(ServiceEvent event)
{
// If a dictionary service was registered, see if we
// need one. If so, get a reference to it.

if (event.getType() == ServiceEvent.REGISTERED)
{
// COMPLETER
}
// If a dictionary service was unregistered, see if it
// was the one we were using. If so, unget the service
// and try to query to get another one.

else if (event.getType() == ServiceEvent.UNREGISTERING)
{
if (event.getServiceReference() == m_ref)
{

// COMPLETER

}
}
}

Pour tester si notre client marche, il faut prévoir le cas ou le service disparait au milieu de l'exécution du client. Pour faire que le service disparaisse, il faut arreter le bundle qui fournit le service le dictionnaire lors de l'execution, mais le client ne nous le permet pas car il monopolise l'entrée de texte. Pour résoudre ce problème nous allons utiliser une console graphique qui nous permettra de faire ceci en même temps. La console graphique fait partie d'une collection de bundles accessibles depuis oscar à travers la comande obr (taper obr -help pour plus de détail).

ATTENTION: si les bundles correspondant a Shell Component et a Shell GUI ne sont pas installés par OBR, il faut les installer à partir du répertoire /bundle de OSGi, les bundles correspondants sont appelés shellcomponent.jar et shellgui.jar.

-> obr Shell Component
Installing dependency Service Binder...
Installing dependency Table Layout...
Installing dependency Gravity...
Installing Shell Component...

-> obr Shell GUI
Installing Shell GUI...

-> start 12


-> start 7

Enter a blank line to exit.
Enter word: wellcome
Incorrect.
Enter word: welcome
Correct.
Enter word:

Lors du démarrage du Shell GUI, nous aurons une interface graphique qui nous permettra de faire l'équivalent de la console.


Le client doit être capable de gérer le départ des services dont il dépend à tout moment. Tester si ca marche...

Voici la solution (Activator.java), son manifest.mf et le fichier build_example4.xml, tester avec celle ci. Verifier qu'elle supporte les changements au niveau des services.

Retour au sommaire


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