- Titre : Système d'événements sous Eclipse

- Auteur : AIT YAHIA Idir

- Parution : 24 juillet 2013

- Licence : Copyright © 2013 AIT YAHIA Idir. CDATA[Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 € de dommages et intérêts. Droits de diffusion permanents accordés à Developpez LLC. Cette page est déposée à la SACD.

Sommaire

- I. Vue d'ensemble

- II. Système d'événements dans Eclipse.

- II-A. Le design pattern Observer.

- II-B. Le Service OSGi EventAdmin

- III. Système d'éventements EventAdmin sous Eclipse

- III-A. Mise en œuvre sous Eclipse 4

- III-A-1. Configuration

- III-A-2. IEventBroker

- III-A-3. Envoi d'événement

- III-A-4. Réception des événements

- III-A-5. Substitution dans la clé d'événement (Topic)

- III-A-6. Les événements du Framework (UIEvents)

- III-A-7. Tutoriel :Cas pratique

I - Vue d'ensemble

Dans n'importe quelle application la gestion des éventements se révèle être un aspect extrêmement important, gérer les événements c'est le fait de réagir au changement qui peuvent se produire dans l'application, ces changements peuvent être déclenchés par l'utilisateur ou par des routines internes a l'application, c'est ce qui rend votre application interactive, sa mise en œuvre peut s'avérer simple dans une application Eclipse, mais celle-ci peut très vite devenir compliquée et risque d'être une source de bug pour votre application.

II - Système d'événements dans Eclipse.

II-A - Le design pattern Observer.

Usuellement, dans une application Java ou basée sur Eclipse, la gestion des événements adopte une approche basée sur l'écoute des événements autrement dit le design pattern Observer, c'est un concept simple et se révèle très pratique pour les applications de petite envergure.

Nous pouvons représenter un gestionnaire d'événements qui gère des interactions homme machine avec le schéma suivant :

Dans notre exemple, les Listeners A et B peuvent écouter les événements du clavier ou de la souries, tout dépend de l'objet auxquels ils sont associés.

Notez que les événements émis par l'expéditeur ne sont pas forcément déclenchés par l'utilisateur et qu'ils peuvent se produire automatiquement lorsque la valeur d'un attribut objet change ou une action est exécutée par exemple.

Comme nous l'avons mentionné plus haut ce design pattern est une très bonne approche, néanmoins il présente certaines contraintes et inconvénients comme la dépendance du listener à l'expéditeur et l'implémentation multiple.

Le listner est étroitement lié au fournisseur d'événement autrement dit l'expéditeur, d'ailleurs l'instanciation du listener dépend de celle de l'expéditeur, en d'autre terme le listener ne peut pas écouter les événements si l'expéditeur n'est pas instancié d'un autre côté le listener doit être désinscrit si l'expéditeur est libéré, ce qui se traduit par du code supplémentaire qui pourrait devenir une source de bug.

l'implémentation multiple est un autre inconvénient qui prend de l'ampleur avec l'accroissement de la taille de l'application, les fournisseurs d'événement ne peuvent pas se partager une même instance d'un listener, c'est-à-dire que chaque fournisseur doit instancier ses propres listeners, même si le pattern fournit des classes comme (ListenerList, Job, SafeRunnable) cela se traduit encore une fois par du code supplémentaire pour faire les jonctions. En conséquence votre application devient plus gourmande en ressources.

Hormis ce design pattern, il existe une autre solution qui obéit au pattern PubSub qui est tout aussi simple et qui nous permet d'éviter ces inconvénients, il s'agit du service OSGi EventAdmin.

II-B - Le Service OSGi EventAdmin

Avec le service EventAdmin, il y a un nouvel élément qui vient s'intercaler entre l'expéditeur et le receveur de l'événement, cet élément est appelé Event Broker, il a pour rôle de recevoir tous types d'événements et de dispatcher chaque type aux receveurs qui sont abonnés a ce type d'événements.

Dans ce concept les receveurs ou listeners s'abonnent et se désinscrivent aux événements à n'importe quel moment sans contrainte et sans se soucier si le fournisseur d'événements est instancié, d'ailleurs il n'a même pas besoin de le connaître tout comme le fournisseur d'événement n'a pas besoin de connaître le listener qui recevra l'événement.

Avec cette approche nous avons perdu la dépendance entre le fournisseur d'événements et le receveur, ce qui est déjà une bonne chose, l'Event Broker se sert d'une clé sous forme de chaîne de caractère appelé TOPIC pour faire l'adressage. c'est-à-dire que le fournisseur d'événements émet les événements associés a des clés avec lesquelles les listeners s'abonnent, nous verrons cela plus en détail dans les chapitres qui viennent.

Nous pouvons représenter cette approche comme suit :

III - Système d'éventements EventAdmin sous Eclipse

Nous aborderons dans ce tutoriel l'implémentation d'un système de gestion des événements basé sur le service OSGi EventAdmin sous les plateformes Eclipse 4 et 3.x

III-A - Mise en œuvre sous Eclipse 4

Eclipse 4 utilise le service IEventBroker pour gérer le système d'événements, qui est basé sur le service OSGi EventAdmin mais avec une API simplifiée, vous allez constater cela par vous-même lorsque nous verrons l'implémentation sur les deux plateformes Eclipse.

III-A-1 - Configuration

IEventBroker est inclus dans le plugin org.eclipse.e4.core.services donc pour pouvoir utiliser le service vous devez déclarer la dépendance a celui-ci dans votre fichier plugin.xml

dans le nouveau modèle de programmation, Eclipse 4 préconise une dépendance au package donc il est recommandé de déclarer une dépendance au package org.eclipse.e4.core.services.events pour ne pas embarquer le plugin en entier.

Optionnellement si vous avez l'intention d'utiliser directement l'inscription aux événements avec IEventBroker sans passer par l'injection de dépendance, vous avez besoin de déclarer la dépendance au package org.osgi.service.event afin de pouvoir déclarer vos handlers (voir la section Envoi d'événement)

III-A-2 - IEventBroker

IEventBroker fournit un ensemble de méthodes pour envoyer, s'abonner et se désabonner à des éventements, il est non seulement un système de gestion d'événements mais il s'avère aussi être un excellent moyen de communication entre les différents composants de l'application, vu qu'il nous permet d'envoyer avec l'événement des données qui peuvent être récupérées par les Listeners.

Communément une instance d'IEventBroker est disponible dans le contexte Eclipse par défaut EclipseContext

Vous pouvez récupérer l'instance d'IEventBroker par injection de dépendance :

@Inject
IEventBroker eventBroker;

Ou la récupérer dans le contexte Eclipse

@Inject
IEclipseContext eclipseContext;

IEventBroker eventBroker = eclipseContext.get(IEventBroker.class);

III-A-3 - Envoi d'événement

L'envoie d'événements peu se faire de deux manières différentes, synchrone et asynchrone respectivement avec les méthodes send et post

@Inject
IEventBroker eventBroker;

…

String myData = "Nouvelle valeur" ;
//Envoie synchrone
enventBroker.send("TOPIC_NEW_DATA", myData);

//Envoie asynchrone
enventBroker.post("TOPIC_NEW_DATA", myData);

A vous de choisir la méthode qui convient a votre cas de figure, utilisez la méthode synchrone lorsque vous avez besoin de bloquer l'expéditeur jusqu'à ce que l'événement soit livré.

III-A-4 - Réception des événements

Maintenant que nous avons vu comment envoyer des événements nous allons voir comment s'abonner a ces derniers et récupérer les données embarquées.

Nous pouvons nous abonner aux événements avec deux méthodes, soit a l'aide l'injection de dépendance ou directement avec la méthode subscribe.

Il est recommandé et plus simple d'utiliser l'injection de dépendance.

@Inject @Optional
void eventHandler(@UIEventTopic("TOPIC_NEW_DATA") String myData) {

// votre code ici soit myData la chaîne de caractères
// que nous avons expédiée avec l'événement
System.out.println(s) ;

}

MyData n'est pas forcément un String mais peut être une instance d'objet que vous avez déclaré.

@Inject @Optional
void eventHandler(@UIEventTopic("TOPIC_NEW_DATA") MyDataObject myData) {

// votre code ici
System.out.println(myData.toString) ;

}

Si vous avez souscrit a un événement avec l'injection de dépendance, il vous sera pas possible de vous désinscrire, par contre celle-ci sera effective si votre souscripteur est libéré.

Si les circonstances ne vous permettent pas d'utiliser l'injection de dépendance ou que vous avez besoin de vous désinscrire a certains événements dynamiquement, vous pouvez utiliser directement la méthode suscribe d'IEventBroker.

EventHandler fait partie du package org.osgi.service.event auquel vous avez besoin de déclarer la dépendance dans votre fichier plugin.xml (voir la note dans la partie configuration)

EventHandler myHandler = new EventHandler() {

@Override
public void handleEvent(Event event) {
String s ;
// Nous allons caster DATA  vers le type de donnée attendu
s =  (String) event.getProperty(IEventBroker.DATA);

System.out.println(s) ;

}

};

eventBroker.subscribe("TOPIC_NEW_DATA", myHandler);

Pour vous désinscrire d'un événement nous n'avez qu'à appeler la méthode unsubscribe

//désinscription a l'événement myHandler
eventBroker.unsubscribe(myHandler);

III-A-5 - Substitution dans la clé d'événement (Topic)

Comme nous l'avons mentionné plus haut IEventBroker utilise une clé sous forme de chaine de caractère pour identifier et s'inscrire à des événements.

Communément chaque événement envoyer est censé être traité indépendamment par un handler, mais dans un contexte particulier il est possible que vous ayez besoin de traiter un ensemble événements avec un seul handler.

A cette fin, il est possible de substituer une partie du topic a l'aide du caractère * comme nous pouvons le voir dans l'exemple qui suit :

@Inject
IEventBroker eventBroker;

…

//Ajout de donnée
String myData = "Nouvelle valeur" ;
enventBroker.send("TOPIC_DATA/NEW", myData);

//modification de la donnée
myData = "une autre valeure" ;
enventBroker.post("TOPIC_DATA/EDIT", myData);

Vous pouvez vous inscrire aux deux événements ci-dessus avec un seul handler comme suit :

@Inject @Optional
void eventHandler(@UIEventTopic("TOPIC_DATA/*") MyDataObject myData) {

// votre code ici
System.out.println(myData.toString) ;

}

Remarquez que cette implémentation peut être très utile, d'où l'importance de bien définir les topics sinon il nous sera impossible de les substituer.

III-A-6 - Les événements du Framework (UIEvents)

La Plateforme Eclipse 4 utilise elle-même le service IEventBroker pour communiquer, elle envoie des événements auxquels vous pouvez vous inscrire, les constantes utiliser pour l'abonnement aux événements sont définies dans la classe org.eclipse.e4.ui.workbench.UIEvents

par exemple UIEvents.UILifeCycle.ACTIVATE est déclenché lorsque une MPart (View) est activée, si son libellé change l'événement UIEvents.UILabel.TOPIC_LABEL est déclanché.

@Inject @Optional
private void closeHandler(@UIEventTopic(UIEvents.UILifeCycle.ACTIVATE) org.osgi.service.event.Event event) {
// récupérer l'instance de la Part qui vient d'être activée
MPart activePart = (MPart) event.
getProperty(UIEvents.EventTags.ELEMENT);
// Votre code ici

}

III-A-7 - Tutoriel :Cas pratique

Pour comprendre ce que nous avons vu jusqu'à présent, nous allons réaliser une petite application qui résume l'ensemble des aspects du système d'événements sous Eclipse 4,

Nous n'allons pour nous nous pencher sur la création d'application Eclipse 4 dans cet article, nous supposons que vous avez les notions de bases pour le faire, vous pouvez consulter l'article ci-dessous pour plus de détails.

Tutoriel sur la construction d'applications Eclipse RCP basées sur Eclipse 4

Système d'événements sous Eclipse

Auteur

AIT YAHIA Idir