• Aucun résultat trouvé

OSL est un mécanisme élaboré de mapping et de recherche de services au dessus du mécanisme de localisation de services standard d'OSGi. Pour illustrer le principe de fonctionnement d'OSL, nous prenons un exemple d'application. Cette application est constituée de deux composants : MorseED et MorseClient. Le premier est un encodeur/décodeur de codes Morse. Il fournit un service appelé MorseService. Ce service définit deux opérations : getCode() et getMessage(). L'opération getCode() permet de calculer le code Morse correspondant à un message donné et getMessage() détermine le message correspondant à un code Morse. Le second composant (MorseClient) est le client qui permet de tester le fonctionnement de MorseED.

Supposons que ces deux composants ont été développés séparément, selon les deux spécifications suivantes :

Dans la recherche standard, le client MorseClient ne peut pas obtenir la référence du service MorseService car celui-ci n'est pas compatible avec le service demandé. Le rôle d'OSL est d'intervenir dans de telles situations pour proposer des alternatives aux services indisponibles. Concrètement, OSL propose de faire dynamiquement le mapping entre le service requis et le ou les services disponibles. Le mapping est sémantique, et ne peut pas être complètement automatisé. Un acteur humain doit participer à sa réalisation.

MorseClient MED Service {

public String encode(String message); public String decode(String code); }

MorseED MorseService {

public char[] getCode(char[] message); public char[] getMessage(char[] code); }

Le processus du mapping passe par plusieurs étapes. Ces étapes sont illustrées à travers notre exemple d'application.

4.2.1 Sélection du service de substitution

Lorsque OSL reçoit la requête d'un client, il tente d'abord d'obtenir le service demandé. Si le service est disponible, il crée un proxy représentant ce service et retourne sa référence au client. Ceci correspond à ce que nous avons expliqué dans la section précédente. Dans le cas contraire, OSL indique à l'utilisateur l'absence du service requis et lui propose de sélectionner un ou plusieurs services parmi ceux disponibles pour simuler le service manquant. Ceci est illustré par la Figure 45.

Figure 45. Sélection des services de substitution 4.2.2 Mapping des opérations

Après la sélection du ou des services de substitution, l'utilisateur doit spécifier le mapping entre les opérations. Pour chaque opération du service originalement requis, il est possible d'associer une ou plusieurs opérations de substitution. Il est possible de valider le mapping à ce stade, si à chaque opération correspond exactement une seule opération avec la même signature (même si les noms des opérations sont différents). Ceci n'est pas possible dans notre exemple d'application car les types de paramètres et les types de retour ne sont pas similaires. Cette étape est illustrée par la Figure 46.

Figure 46. Mapping des opérations

4.2.3 Mapping des paramètres et des types de retour

Si les paramètres de l'opération originale et de celle qui est destinée à la remplacer ne sont pas identiques, il est nécessaire de définir la relation exacte entre ces informations. La Figure 47 présente l'interface qui permet de définir une telle relation. Dans le haut de l'interface, l'opération originale est décrite. L'utilisateur doit spécifier pour chaque paramètre de l'opération de substitution, une expression qui permet de le calculer. Par exemple, la première ligne de l'interface signifie que le premier paramètre de l'opération getCode() est équivalent à l'expression "oldParam_0.toCharArray()", où oldParam_0 est le premier paramètre de la méthode originale.

Figure 47. Mapping des paramètres et des types de retour

La dernière ligne de l'interface du mapping concerne les types de retour. Si le type de retour de l'opération attendue est différent de celui de l'opération de substitution, il est nécessaire de préciser comment calculer la valeur de retour attendue à partir de la valeur retournée par l'opération de substitution.

4.2.4 Utilisation des informations de mapping

Ce paragraphe explique comment les informations de mapping sont utilisées lorsque l'opération originale est appelée par le client.

Mapping

Appeler encode() Appeler getCode()

Retourner tableau 4 3 1 2 MorseED MorseClient Retourner String Proxy

Figure 48. Utilisation des informations de mapping dans un appel

La Figure 48 montre les différentes étapes de l'appel :

1. A l'interception de l'appel d'une opération, le proxy détermine l'instance et l'opération de substitution et calcule les nouveaux arguments, éventuellement à partir de ceux passés par le client.

2. Le proxy appelle l'opération déterminée avec les arguments calculés.

3. Le proxy reçoit éventuellement le résultat de l'appel. Il calcule ensuite le résultat que le client attend en utilisant les informations du mapping.

4.2.5 Composition de services

L'exemple de mapping que nous avons discuté est relativement simple. La situation devient plus complexe si le service requis par le client ne peut pas être entièrement couvert par un seul autre service. Par rapport à notre exemple d'application, supposons qu'il n'existe pas un autre service capable de fournir les mêmes fonctionnalités que MED_Service. Supposons d'un autre coté la présence de quatre services capables tous ensemble de simuler ces fonctionnalités. Ces services sont :

• Service d'encodage de messages (MES) : fourni par l'instance MessageEncoder, capable de remplacer la fonction d'encodage des messages (opération encode()). • Service de découpage de codes (CSS) : fourni par l'instance CodeSplitter. Il découpe

un code Morse en plusieurs items où chaque item correspond à une lettre.

• Service de décodage d'items (IDS) : fourni par l'instance LetterDecoder. Il détermine la lettre qui correspond à un item Morse.

• Service d'inversion de messages (MIS) : fourni par l'instance MessageInverter. Il permet d'inverser un message. Ce service est nécessaire si les codes Morse traités sont inversés.

Comme illustré par la Figure 49, l'opération originale decode() est simulée par trois autres opérations de substitution.

Figure 49. Mapping multiple d'opérations

L'utilisateur doit ensuite définir un script pour exprimer comment agir lorsque l'opération originale decode() est appelée, et comment calculer la valeur de retour le cas échéant. Le squelette du script est automatiquement généré par OSL. L'utilisateur doit compléter ce squelette avec la partie sémantique du mapping (le code Java). La Figure 50 montre un script potentiel pour notre exemple.

L'architecture de l'application après le mapping est illustrée par la Figure 51. MES CodeSplitter MED Service MessageEncoder LetterDecoder Proxy MIS IDS CSS MessageInverter MorseClient

Figure 51. Architecture après le mapping