Pour savoir où on va, il faut savoir d'où l'on vient

Vous avez
une question ?
Un projet ?

Contactez nous !
 

Contactez-nous

Vous avez une question ? un projet ? 
Vous souhaitez plus d'informations sur un produit ? sur notre offre ? 
Contactez-nous, on vous répond sous 4H.

retour

Java Messaging System ou JMS

Java Messaging System ou JMS

Introduction

JMS est l'API de communication asynchrone via Message de Java. C’est l’API qui permet à une application d’invoquer les services d’un MOM.

JMS fait partie de JEE 5 et est ainsi disponible aux applications tournant sur des serveurs applicatifs Java.

La première version de JMS, JMS 1.0.2b est sortie le 25juinn 2001. La seconde version, JMS 1.1 est sortie le 18 mars 2007, sans présenter de différence importante. Les classes JMS 1.1 permettent de réaliser des clients JMS plus facilement. Nous allons étudier sommairement JMS 1.1. Mais nous commencerons par poser quelques définitions et concepts.

Comme toute spécification, JMS doit assurer que toutes les applications qui s’y conforment ont le même comportement quel que soit le fournisseur de l’implémentation. La JMS laisse aussi dans des cas bien définis, la liberté aux fournisseurs d'implémenter ou non certaines fonctionnalités. Nous reviendrons en détail sur ces fonctionnalités qui distinguent les différents MOMs.

Comme JDBC pour l’accès aux bases de données, ou JCR pour l’accès à un référentiel de contenus, JMS permet en théorie de développer une application interfacée à un MOM, sans dépendre d’un produit particulier. C'est-à-dire qu’il devrait être possible de remplacer un MOM JMS par un autre de manière transparente pour l’application. Comme pour les accès aux bases de données, cet aspect interchangeable n’est pas toujours vérifié en pratique. Il peut exister des petites différences d’implémentation de la spécification, et par ailleurs les différents outils MOMs s’efforcent d’offrir des petits « plus », des fonctionnalités différenciantes.

Modes de communication

La spécification JMS introduit deux modes de communication, les « domaines JMS »: les topics d'une part, les queues d'autre part. .

Le mode point à point ou « queue »

Ce mode de communication est aussi appelé communication via queue. Une application envoie des messages à une queue. Une seule des applications connectées reçoit le message. Il peut y avoir plusieurs applications en lecture sur la queue, mais une seule d’entre elles recevra le message.

queue_shema

Le mode « publish-subscribe » ou « topic »

Ce mode de communication est aussi appelé communication via topic. Une application envoie des messages à des topic.

Dans ce mode, on dit que les applications s'abonnent (subscribe) à un topic, afin de recevoir les messages.Plusieurs applications peuvent être abonnées à un même topic, et chacune d'elles reçoit une copie des messages.

À la manière de la diffusion d’un magazine par exemple, l’émetteur publie un message, et les différents destinataires s’abonnent pour recevoir une copie du message.

C’est donc un échange de 1 vers N, mais qui peut être aussi bien « de P vers N », car plusieurs applications peuvent écrire dans le topic.

topic_shema

Queues et topics

On voit bien les différences d’usage de ces deux modes. Dans le mode queue, on peut imaginer qu’un message représente une unité de traitement. L’application destinatrice reçoit le message et effectue un traitement à partir du message, et dans ce cas il faut que le traitement ne soit pas exécuté deux fois. Dans le mode topic, on peut voir le message plutôt comme une unité d’information, qui peut intéresser différents acteurs, différentes applications. Par exemple, un ordre de bourse sera une unité de traitement, tandis qu’un cours de bourse sera une information.

Queue et Topic sont regroupés sous le nom de « Domaine ». Ainsi, « envoyer un message à un domaine » équivaut à « envoyer un message à une queue ou à un topic ».

Quelques définition

JMS introduit différents termes et concepts que nous allons rapidement parcourir:

JMS Client

Un client JMS est une application écrite en Java envoyant et/ou recevant des messages au moyen de l’API JMS.

Non-JMS Client

Un client non-JMS est une application envoyant et/ou recevant des messages en communiquant avec le JMS Provider selon son protocole particulier, soit en direct, soit par l’intermédiaire des fonctions d’une API. Cette application n'est pas écrite en Java.

JMS Provider

Un Fournisseur JMS est une implémentation des services JMS écrite en Java. Ainsi,i les MOMs que nous étudierons plus loin sont des JMS Providers.

JMS Consumer

Un Consommateur JMS est une application qui reçoit et traite des messages JMS.

JMS Producer

Un Producteur JMS est une application qui crée et envoie des messages JMS. Une même application peut être à la fois JMS Producer et Consumer.

JMS Message

Le message JMS est l'unité fondamentale de JMS. Il est envoyé et reçu par des Client JMS.

JMS Domains

Les deux domaines JMS correspondent aux deux modes de communication déjà évoqués : point à point avec les queues ou publish-subscribe avec les topics.

Destination

Les objets destinations sont des objets servant à identifier la cible des messages à envoyer ou à recevoir, c'est-à-dire des domaines, queues et topics.

Encodages du corps des messages

Même si le contenu et le format du corps sont fondamentalement l’affaire des applications, JMS aide les applications à manipuler certains types d’objets en fournissant différents types de corps de message.

Le corps des messages peut être encodé selon les 5 « Message Types » disponibles :

  • « TextMessage » : Le corps contient des caractères.

 

  • « BytesMessage » : Le corps contient une suite de bytes, selon le
    langage Java

byte[]stockData; /* Stock information as a byte array */
BytesMessage message;
message = session.createBytesMessage();
message.writeBytes(stockData);
byte[]stockInfo; /* Byte array to hold stock information */
int length;
length = message.readBytes(stockData);

  • « MapMessage » : Le corps contient une map. Une map est un type de
    données reliant une clef (codée en String) a une valeur (codée en
    String, Double ou Long)

 

  • « StreamMessage » Ce type permet de concaténer plusieurs type natif (String, Double ou Long).

 

  • « ObjectMessage » : Ce type permet de transférer un objet java.

 

La strucutre du message JMS

Le message manipulé par le MOM JMS est composé des parties suivantes:

  • Une entête, qui a la même structure pour tous les messages, et contient principalement les champs nécessaires à l'identification et au routage du message.
  • Des propriétés, qui viennent en quelque sorte compléter l'entête, avec des attributs spécifiques, soit définis par le MOM en complément de l'entête minimale JMS, soit définis par l'application pour ses besoins particuliers.
  • Le corps du message, qui peut avoir différents formats: texte, objets Java ou données XML.

Les principaux champs de l'entête sont:

  • JMSMessageID : identifiant unique du message
  • JMSDestination : identification de la queue ou du topic destinataire du message
  • JMSCorrelationID : utilisé pour synchroniser de façon applicative deux messages de la forme requête/réponse. Dans ce cas, dans le message réponse, ce champ contient le messageID du message requête

Selon l’image habituelle, l’entête correspond à ce qui est écrit sur l’enveloppe, le corps correspond à ce qui est dans l’enveloppe. Le MOM ne lit et n’utilise que les données de l’entête, y compris les propriétés. Ainsi, la sélection de messages, que l'on verra plus loin, peut dépendre de ces propriétés, mais non du corps du message.

Ordre des messages

Le MOM garantit qu'un message sur une queue sera remis au plus une fois, mais il ne garantit pas que les messages seront remis dans l'ordre dans lequel ils ont été émis.

En fait, il y a presque une impossibilité théorique à garantir l'une et l'autre de ces deux propriétés: la remise unique, et la remise ordonnée. En effet, un consommateur peut lire un message, et ne l'acquitter que longtemps après. Si le consommateur n'acquitte pas, le message doit être recyclé. Ainsi pour assurer la remise ordonnée, le MOM devrait attendre que tous les messages jusqu'à N aient été non seulement reçus, mais acquittés, avant de livrer un message N+1, ce qui aurait un effet catastrophique sur les performances.

Nous verrons plus loin que les MOMs permettent une gestion des transactions, qui permet en quelque sorte d’annuler des opérations qui n’ont pas encore été validées, commitées, en ordonnant un retour arrière, un rollback. Voir « Gestion des transactions ».

La figure suivante montre comment un rollback, soit explicite, soit implicite, c'est-à-dire provoqué par la fermeture de session, oblige à recycler un message alors que les suivants ont déjà été délivrés.

ordre_messages

Durée de vie d'un message

L'application émettrice peut spécifier la durée de vie du message. Le message est donc 'valable' jusqu'à l'expiration de cette durée, au-delà le MOM peut le détruire sans l'avoir remis. La plupart des MOMs choisissent plutôt de l'aiguiller vers la Dead Message Queue, qui permettra de garder la trace de l'événement, et de recycler le message le cas échéant.

À noter que si l'on est dans le contexte d'une transaction, la durée de vie démarre quand même à l'instant d'émission, et non à l’instant du commit.

Priorité

Une fonctionnalité optionnelle, mais utile, proposée par le JMS, est la gestion des priorités, c'est-à-dire que la délivrance des messages s’effectue selon leur priorité.

Un message de plus haute priorité peut donc « doubler » un message de moindre priorité, pour autant que celui-ci n’ait pas encore été lu.

Remarquons que JMS 1.1 n'oblige pas les fournisseurs à implémenter cette fonctionnalité.

Sélection des messages

JMS prévoit que les applications clientes ont la possibilité de sélectionner les messages qu'elles lisent, sur la base des champs d'entête et de propriétés. On voit bien sûr que, s’il y a sélection, les messages ne seront forcément pas délivrés dans l'ordre.

La sélection des messages est définie dans JMS 1.1, elle est donc offerte par tous les MOMs étudiés. La syntaxe est inspirée du SQL, elle peut faire intervenir différents opérateurs de comparaison, d'expressions logiques, et même des opérations arithmétiques.

À titre d'exemple, imaginons une application qui communique avec une queue et lui envoie des messages avec les propriétés suivantes : JMSType, market et amount. Une application cliente ne souhaitant obtenir que les opérations sur le marché Euronext dont le montant est inférieur à 1 000 000 €, appliquera le selector suivant : JMSType = 'order' AND market = ''Euronext' AND amount < 1000000.

Certains MOMs peuvent accepter d'autres types de syntaxe, qui ne sont pas requis par JMS 1.1, typiquement Xpath. Mais dans tous les cas, la sélection porte sur entête et propriétés, et non sur le corps du message.

messages_selected

Aiguillage et spécialisation

On peut donc mettre en œuvre, au moyen de la sélection, une spécialisation des consommateurs. En fait, dans une logique d'affectation et de répartition de tâches, on peut distinguer trois techniques:

  • L'application émettrice, producer, place des messages dans des queues différentes selon la nature de la tâche à effectuer. Et une application spécifique est en lecture sur chacune des queues.

    aiguillage_specification
  • L'application émettrice place les messages dans une queue unique, mais la queue est ensuite éclatée en plusieurs queues, ceci soit au moyen d'une application relais jouant un rôle d'aiguillage, soit au moyen d'un traitementd'aiguillage, si le MOM le permet.
    aiguillage_specification
  • L'application émettrice place les messages dans une même queue, et les applications consumer sélectionnent les messages selon leur spécialisation. Ici « Consumer C1 » prend les messages jaunes, C2 les messages bleus, C3 les messages violets. L’application producer n’a pas à connaître cette répartition.

    aiguillage_specification2

Trois manières de gérer à peu près le même problème, à différents niveaux. Dans le premier cas la logique d'aiguillage est intégrée au producer, dans le dernier cas, elle relève du consumer, et dans le cas intermédiaire, elle est déportée dans une application dédiée.

Synthèse JMS

JMS est une API, et cette API correspond à des services d'échange entre des producteurs et des consommateurs de messages, s’appuyant sur des concepts que nous avons présentés. Au-delà de l’API donc, JMS définit les fonctionnalités centrales des MOMs.

JMS spécifie le service, mais ne spécifie pas comment ce service est mis en œuvre. Chaque fournisseur, JMS Provider, est libre de ses choix d’implémentation.

Comme on l’a vu plus haut, les protocoles d’échanges peuvent également être considérés comme des choix d’implémentation propres à certains MOMs, même si nous considérons qu’ils ont une réelle importance.

La spécification JMS n'est pas en tous points complète. Certaines fonctions essentielles au fonctionnement d'une plateforme MOM ne sont pas décrites dans la spécification et font donc l'objet d'implémentations particulières. C'est le cas en particulier pour la configuration et l'administration du service de messagerie, pour la sécurité (intégrité et confidentialité des messages) et pour certains paramètres de qualité de service.

Par ailleurs, la plupart des MOMs proposent des fonctions additionnelles qui se présentent comme des atouts spécifiques par rapport aux offres concurrentes (par exemple les topics hiérarchisés, des fonctions de sécurité et des mécanismes de haute disponibilité, etc.). Bien sûr, la mise en œuvre de ces fonctionnalités se fait au détriment de la capacité à changer de MOM, en respectant l’API JMS.

Comme d’autres spécifications d’interface, comme le SQL par exemple, la promesse de pouvoir changer d’implémentation de MOM JMS de manière transparente, n’est pas facilement tenue. Mais ce n’est pas très grave. La spécification commune apporte déjà le bénéfice d’une communauté de vision, d’approches, et de compétences. Un architecte peut raisonner sur la base d’un MOM sans savoir nécessairement de quelle « marque » il sera, et un développeur qui a pratiqué JMS avec un premier MOM, pourra presque immédiatement en pratiquer un second.