Les spécifications de JMS 2.0 partie 2

1. Introduction

Après avoir présenté les APIs de JMS 1.0.2b et JMS 1.1 dans la première partie, nous allons nous focaliser en détail sur les nouveautés proposées par la spécification JMS 2.0, qui a permis de clarifier et corriger quelques incohérences restées en suspens dans les anciennes versions de JMS.

Par exemple, un fournisseur de services JMS était libre d’implémenter le mode d’échange qu’il voulait avec un MOM : Point à Point ou Publication / Abonnement, mais depuis la spécification JMS 2.0, les fournisseurs de services JMS sont obligés d’implémenter les deux modes d’échanges.

Aussi, dans les anciennes spécifications, l’utilisation de JMS dans un contexte JEE n’était pas décrite. Chaque spécification JEE décrivait comment utiliser JMS. Maintenant, l’utilisation de JMS dans un contexte JEE est documentée dans la spécification JMS 2.0

Enfin, les autres nouveautés seront abordées dans les prochains paragraphes avec des exemples d’implémentation

2. Nouveautés de JMS 2.0

Le changement majeur apporté par la spécification JMS 2.0 est l’ajout d’une nouvelle API permettant de simplifier le code java nécessaire pour implémenter un envoi ou une réception de message dans une application Java.

Aussi, JMS 2.0 a enrichi l’ancienne API avec les nouveautés suivantes :

  • Nouvelles méthodes pour simplifier la création de la session
  • Nouvelles méthodes pour extraire le contenu d’un message
  • Possibilité d’envoyer des messages en mode asynchrone
  • L’émetteur du message peut préciser au MOM le délai de livraison d’un message au destinataire
  • Implémentation de l’interface lang.AutoCloseable par les interfaces JMS ayant une méthode close
  • Obligation de valoriser la propriété JMSXDeliveryCount par les fournisseurs des services JMS (MOM)

Pour la suite de l’article, l’API classique fera référence à l’API historique de JMS 1.1

2.1     Nouvelle API

La nouvelle API propose trois interfaces :

JMS nouvelle API

  • jms.JMSContext : l’instance de cette interface est créée par la ConnectionFactory. Elle se charge de créer une connexion vers le fournisseur de services JMS (MOM) et initialiser un contexte pour envoyer ou réceptionner les messages. Elle remplace les deux interfaces Session et Connection de l’API classique. Comme pour la session, JMSContext est mono-thread et une exception de type JMSRuntimeException est déclenchée s’il y a une tentative d’instancier plus d’une fois un objet JMSContext dans le même thread.
  • jms.JMSProducer : l’instance de cette interface est créée par JMSContext pour envoyer les messages vers la destination : Queue ou Topic. Elle remplace l’interface MessageProducer de l’API classique
  • jms.JMSConsumer : l’instance de cette interface est créée par JMSContext pour réceptionner les messages postés dans la Queue ou le Topic. Elle remplace l’interface MessageConsumer de l’API classique

En plus de ces interfaces, une nouvelle exception de type unchecked a été ajoutée, JMSRuntimeException, pour remonter les erreurs d’exécution des méthodes définies dans les nouvelles interfaces. Ainsi, la signature des méthodes proposées par la nouvelle API ne contient plus l’identifiant de l’exception déclenchée.

Pour rappel, les méthodes de l’API classique, JMS 1.1, déclenchent une exception de type checked, JMSException, c’est-à-dire, la signature des méthodes contient l’identifiant de l’exception déclenchée.

Enfin, d’autres changements intégrés par la nouvelle API seront détaillés dans les exemples d’utilisation de cette API.

a)  Envoi de messages

envoi de message avec API JMS

L’implémentation d’un envoi de messages avec la nouvelle API de JMS 2.0 a besoin de moins de lignes de code que l’utilisation l’API classique de JMS 1.1.

  • JMS 2.0 a ajouté une nouvelle méthode sans argument dans l’interface ConnectionFactory pour créer un objet JMSContext avec les caractéristiques suivantes :
    • Le mode d’acquittement des messages reçus par défaut est : AUTO_ACKNOWLEDGE
    • Le comportement transactionnel est configuré automatiquement et dépend de de l’environnement d’exécution de l’objet JMSContext :
      • Java SE : non transactionnel
      • Conteneur WEB ou Conteneur EJB sans transaction JTA : non transactionnel
      • Conteneur WEB ou Conteneur EJB avec transaction JTA : transactionnel
  • L’utilisation de l’objet TextMessage n’est plus nécessaire pour créer un corps de message de type String. JMS 2.0 permet d’envoyer directement une String dans le corps du message avec la méthode send
  • L’appel explicite dans le code de la méthode close de l’objet JMSContext pour libérer les ressources n’est pas requis puisque JMSContext implémente la nouvelle interface land.AutoCloseable de Java SE 7 et instancié dans l’instruction try-with-resources qui se charge d’invoquer implicitement la méthode close

b)    Réception de messages en Synchrone

Réception de message en Synchrone

Pour la réception des messages, les changements majeurs apportés par JMS 2.0 avec la nouvelle API sont :

  • Pas besoin d’invoquer explicitement la méthode start de l’objet JMSContext dans le code pour déclencher la réception des messages puisque cette action est déclenchée automatiquement lors de la création l’instance de l’objet JMSConsumer. Cette nouvelle simplification est valable pour la réception des messages en mode asynchrone.
  • Avec JMS 1.1, il faillait convertir le message vers le bon type avant d’extraire son contenu

conversion de message

Cette conversion n’est plus requise puisque l’interface JMSConsumer de JMS 2.0 fournit la méthode receveiveBody qui permet de consommer le message et extraire son le corps du message dans le bon type.

receveiveBody

c)     Injection de JMSContext dans un conteneur JEE

Dans une application JEE, l’objet JMSContext peut être injecté via l’annotation javax.inject.Inject dans les classes qui supportent l’injection des dépendances avec la spécification CDI, tel que : une servlet ou un bean session. Ainsi, la gestion du cycle de vie de l’objet JMSContext (création et clôture) est déléguée au conteneur JEE : WEB ou EJB.

JMSContext

Il est possible d’indiquer le nom JNDI de la fabrique de connexion à utiliser lors de l’injection de l’objet JMSContext avec l’annotation javax.jms.JMSConnectionFactory.

JMSContext javax.jms.JMSConnectionFactory

2.2     Création de la session JMS

Dans JMS 1.1, la méthode de création de l’objet javax.jms.Session dans l’interface javax.jms.Connection avait besoin de deux arguments :

javax.jms.Session

  • transacted : argument pour indiquer si la session est transactionnelle
  • acknowledgeMode : argument pour définir le mode d’acquittement des messages reçus

Cependant, dans certains cas, les deux paramètres sont ignorés et n’ont pas d’effet sur la création de l’objet Session, ce qui peut être une source de confusion auprès du développeur, par exemple :

  • Si le paramètre transacted égale true, l’argument acknowledgeMode est ignoré puisque l’acquittement du message reçu est réalisé après validation de la transaction, commit
  • Si la méthode createSession est exécutée dans un conteneur WEB ou EJB dans une transaction JTA active, les deux arguments sont ignorés

Pour ces raisons, JMS 2.0 a introduit deux nouvelles méthodes dans l’interface Connection pour simplifier la création de l’objet Session et corriger les imperfections de l’ancienne méthode.

JMS 2.0 création objet session

Avec ces deux nouvelles méthodes, l’activation du support des transactions n’est plus déterminée par un argument de méthode, mais dépend de l’environnement d’exécution de la session.

La méthode sans argument permet de créer un objet Session avec AUTO_ACKNOWLEDGE comme mode d’acquittement des messages reçus et le comportement transactionnel de la session dépendra des conditions suivantes :

  • La session est non transactionnelle si elle est utilisée dans environnement Java SE ou dans un conteneur JEE (Web,EJB) où la transaction JTA n’est pas active
  • La session est transactionnelle si elle est utilisée dans un conteneur JEE où la transaction JTA est active. Dans ce cas, le mode d’acquittement par défaut, AUTO_ACKNOWLEDGE, est ignoré

La méthode avec un argument permet d’indiquer le mode d’acquittement des messages reçus lors de la création de l’objet Session dans un environnement java SE. Les modes d’acquittement disponibles sont :

  • AUTO_ACKNOWLEDGE : l’accusé de réception est envoyé au MOM dès que le message est consommé par l’application.
  • CLIENT_ACKNOWLEDGE : l’accusé de réception est envoyé au MOM lorsque l’application cible exécute l’appel de la méthode : acknowledge après la consommation du message.
  • DUPS_OK_ACKNOWLEDGE : dans ce mode le MOM peut livrer un message plusieurs fois vers la même destination.

Le comportement transactionnel de la session créée par la méthode createSession avec un argument dépendra des conditions suivantes :

  • La session est transactionnelle dans deux cas suivants:
    • La valeur de sessionMode est SESSION_TRANSACTED lors de la création de la session dans un environnement Java SE

SESSION_TRANSACTED

  • L’objet Session est utilisé dans un conteneur JEE où une transaction JTA est active. Dans ce cas la valeur de l’argument sessionMode est ignorée
  • La session est non transactionnelle dans les deux cas suivants :
    • Java SE : la valeur de sessionMode est AUTO_ACKNOWLEDGE, CLIENT_ACKNOWLEDGE ou DUPS_OK_ACKNOWLEDGE lors de la création de la session
    • JEE : pas de transaction JTA active lors de lors de l’utilisation de l’objet Session. Dans ce cas les valeurs possibles de l’argument sessionMode sont : AUTO_ACKNOWLEDGE, et DUPS_OK_ACKNOWLEDGE. Le mode CLIENT_ACKNOWLEDGE n’est pas permis dans un conteneur JEE

Enfin, dans un conteneur JEE, la méthode createSession avec un argument peut être utilisée uniquement si l’on choisit d’appliquer le mode d’acquittement DUPS_OK_ACKNOWLEDGE sinon il est recommandé d’utiliser la méthode createSession sans argument.

2.3     Extraction du contenu d’un message

L’extraction du contenu du message nécessitait trois opérations avec JMS 1.1 :

  • Réception du message
  • Conversion (cast) du message vers le type adéquat : BytesMessage, MapMessage, ObjectMessage, StreamMessage, TextMessage,
  • Extraction du corps du message

JMS 1.1 Extraction du corps du message

Comme pour la nouvelle API, JMS 2.0 a enrichi l’interface javax.jms.Message avec une nouvelle méthode qui permet d’extraire le corps du message avec le type adéquat et éviter l’opération de conversion de type : cast.

javax.jms.Message cast

2.4     Envoi d’un message en asynchrone

L’envoi des messages en asynchrone est une autre nouvelle fonctionnalité de JMS 2.0 qui pourrait être une alternative à l’envoi des messages en synchrone. Dans ce mode d’envoi, l’application n’est pas contrainte, après un envoi de message, d’attendre l’accusé de réception du serveur MOM pour continuer l’exécution de la suite des traitements.

Quand le serveur MOM reçoit le message, le provider JMS invoque le callback onCompletion de l’interface javax.jms.CompletionListener pour notifier la fin de l’envoi du message avec succès à l’application. Si le MOM ne reçoit pas le message, le provider JMS invoque le callback onException pour notifier l’échec de l’envoi à l’application.

Ainsi, avec ce nouveau mode, l’application peut envoyer plusieurs messages sans attendre l’accusé de réception des messages du serveur MOM.

Enfin, l’envoi des messages en asynchrone est possible uniquement dans un environnement Java SE. L’utilisation de cette fonctionnalité n’est pas permise dans un conteneur WEB ou EJB.

  • API classique

API Classique asynchrone

Dans l’API classique, l’enregistrement du listener se fait au niveau de la méthode send de l’interface javax.jms.MessageProducer.

  • Nouvelle API

Nouvelle API Asynchrone

  • Classe d’implémentation de l’interface javax.jms.CompletionListener

JMS 2.0 interface javax.jms.CompletionListener

2.5     Implémentation de l’interface java.lang.AutoCloseable

A partir de JMS 2.0, toutes les interfaces ayant la méthode close implémentent la nouvelle l’interface AutoCloseable de Java SE 7 qui permet d’invoquer implicitement la méthode close à la fin des traitements, si l’objet est géré par la nouvelle instruction try-with-resources de java SE 7. Ainsi, l’appel explicite à la méthode close n’est plus nécessaire dans le code et les ressources mobilisées pour réaliser un envoi ou une réception de message seront libérées automatiquement à la fin des traitements. Voici un exemple d’utilisation :

  • API classique

JMS 2.0 AutoCloseable de Java SE 7

Dans cet exemple, c’est la méthode close de l’objet Connection qui va être exécutée à la fin du traitement. La clôture de la connexion libère implicitement les ressources utilisées par les deux objets Session et MessageProducer.

  • Nouvelle API

JMS 2.0 setDeliveryDelay

2.6     Délai de livraison du message

Une nouvelle méthode, setDeliveryDelay, est disponible dans l’interface MessageProducer qui permet de définir le délai de livraison du message, c’est-à-dire, le MOM ne livrera le message que lorsque ce délai est passé.

  • API classique

JMS 2.0 2.6 Délai de livraison du message- API classique

  • Nouvelle API

JMS 2.0 2.5 Implémentation de l’interface java.lang.AutoCloseable

2.7     JMSXDeliveryCount

A partir de JMS 2.0, les fournisseurs des services JMS, MOM, ont l’obligation d’implémenter cette propriété qui était optionnelle dans JMS 1.1.

Cette propriété permet d’indiquer à l’application consommatrice du message combien de fois le MOM a essayé de transmettre le message. Si le message est livré plus d’une fois, cela veut dire, qu’il y a eu un problème lors de la réception du message : serveur arrêté, application non disponible où le traitement de l’application est en erreur à cause du message.

Certains MOM permettent de configurer le transfert des messages vers une file d’attente des messages en erreur lorsque le nombre de tentatives de livraison défini dans la propriété JMSXDeliveryCount est atteint.

JMS 2.0 JMSXDeliveryCount

3. Conclusion

JMS 2.0 a introduit beaucoup de nouveautés à l’API la plus utilisée dans le développement des échanges de message avec MOM et qui n’a pas évolué depuis 2002.

Cependant, l’évolution majeure de JMS 2.0 est l’introduction de la nouvelle API qui va simplifier les tâches d’implémentation des fonctions d’envoi ou de réception de messages aux développeurs dans une application JEE ou Java SE.

Enfin, une nouvelle version de JMS, 2.1, est en cours de préparation sous la JSR 368 qui va corriger des bugs remontés dans JMS 2.0 et introduire des simplifications sur l’API de réception des messages en mode asynchrone. Cette nouvelle version sera disponible dans la plateforme JEE 8.

0 commentaires

votre commentaire

Se joindre à la discussion ?
Vous êtes libre de contribuer !

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Inscription newsletter

Ne manquez plus nos derniers articles !