JMS dans WildFly


Dans WildFly, les fonctionnalités de messaging JMS sont prises en charge par HornetQ. De ce fait, la configuration du subsystem messaging a pas mal de similitudes avec celle d'un serveur HornetQ autonome. L'extension messaging n'est pas présente dans la configuration par défaut de WildFly. Pour l'avoir, il faut utiliser le fichier de configuration standalone-full.xml ou le profil full, en mode domaine. Il est aussi possible d'ajouter la fonctionnalité de messaging au profil par défaut en ajoutant l'extension org.jboss.as.messaging, le subsystem urn:jboss:domain:messaging et les socket-bindings messaging et messaging-throughput.

Toute la configuration JMS se fait dans ce subsystem messaging. Plus précisément, elle se fait dans son élément enfant <hornetq-server>.

Destinations

Le terme destination est générique aux queues et topics. Les destinations sont dans des sous-éléments de jms-destination qui sont jms-queue et jms-topic. Pour chaque destination, la configuration minimal est constituée d'un nom de destination et d'au moins une entrée JNDI.

<jms-destinations>

  <jms-queue name="SwQueue">
    <entry name="java:/queue/SwQueue"/>
    <durable>true</durable>
  </jms-queue>
  
  <jms-topic name="SwTopic">
    <entry name="java:/topic/SwTopic"/>
  </jms-queue>

</jms-destinations>

La queue et le topic peuvent aussi être déclarés par jboss-cli :

/subsystem=messaging/hornetq-server=default/jms-queue=SwQueue:add(entries=[java:/queue/SwQueue])

/subsystem=messaging/hornetq-server=default/jms-topic=Swtopic:add(entries=[java:/topic/SwTopic])

On notera que la queue et le topic configurés ci-dessus ne sont pas accessible à distance puisqu'ils n'ont pas d'entrée JNDI dans l'espace de nommage java:jboss/exported/.

Sécurité

Accès distant

Pour accéder à une destination, un client externe à WildFly passe par JNDI via un accès distant. Cette accès est sécurisé par l'ApplicationRealm.

Permissions par destinations

L'ajout de permissions à une destination ou un ensemble de destinations se fait par des security-settings.

   <security-settings>
      <security-setting match="jms.queue.SwQueue">
          <permission type="consume" roles="swuser"/>
          <permission type="send" roles="swuser"/>
      </security-setting>
   </security-settings>

Un security-setting avec match="#" s'applique à toutes les destinations. Un security-setting avec match="jms.queue.SwQueue" ne s'applique qu'à la queue JMS dont le nom est SwQueue.

La liste des permissions est la suivante :

La même configuration par cli :

/subsystem=messaging/hornetq-server=default/security-setting="jms.queue.SwQueue":add
/subsystem=messaging/hornetq-server=default/security-setting="jms.queue.SwQueue"/role=swuser:add(send=true, consume=true)

Attention, l'authentification se fait par l'appel de la méthode connectionFactory.getConnection(username, password). Il n'y a aucune propagation automatique lorsqu'on appelle connectionFactory.getConnection().

Destinations de gestion

Dans les destinations de gestion, je regroupe la Dead Letter Queue qui reçoit les messages qui n'ont pas pu être consommés et l'Expiry Queue qui reçoit les messages dont la date d'expiration est dépassée. Même si ces destinations n'existent pas pas défaut, leurs noms sont dans la configuration globale :

<address-settings>
  <address-setting match="#">
    <dead-letter-address>jms.queue.DLQ</dead-letter-address>
    <expiry-address>jms.queue.ExpiryQueue</expiry-address>
    ...
  </address-setting>
</address-settings>

Pour monitorer ces destinations et consulter leur contenu, il faut donc les créer.

Expiry Queue

La file d'expiration reçoit les messages qui ont expiré. Cela peut être dû à une durée de vie limité fixée par le producteur, avant l'envoi :

producer.setTimeToLive(10000L);

L'expiration peut aussi être provoquée par un script jboss-cli, pour tous les messages d'une destination :

/subsystem=messaging/hornetq-server=default/jms-queue=SwQueue:expire-messages

Pour un unique message d'une destination, identifié par son JMSMessageID :

/subsystem=messaging/hornetq-server=default/jms-queue=SwQueue:expire-message(message-id=ID:f0671793-faec-11e2-9d0d-2d43143133bb)


Enfin, pour créer l'ExpiryQueue qui correspond à la configuration par défaut :

/subsystem=messaging/hornetq-server=default/jms-queue=ExpiryQueue:add(entries=["java:/queue/ExpiryQueue"])

Dead Letter Queue

La file de rebuts reçoit les messages qui n'ont pas pu être délivrés, ou plus précisément ceux dont qui n'ont pas pu être livrés après un nombre d'échecs égal au paramètre max-delivery-attempts. C'est le cas par exemple pour des messages consommés dans le cadre de transactions annulées (rollback).

La valeur par défaut de ce paramètre est 10, mais il peut être modifié :

/subsystem=messaging/hornetq-server=default/address-setting=#:write-attribute(name=max-delivery-attempts, value=5)

Il est aussi possible de forcer l'envoi de tous les messages d'une destination dans la DLQ :

/subsystem=messaging/hornetq-server=default/jms-queue=SwQueue:send-messages-to-dead-letter-address

Pour un unique message d'une destination, identifié par son JMSMessageID :

/subsystem=messaging/hornetq-server=default/jms-queue=SwQueue:send-message-to-dead-letter-address(message-id=ID:6c28635a-faef-11e2-9d0d-2d43143133bb)


Enfin, pour créer la DLQ qui correspond à la configuration par défaut :

/subsystem=messaging/hornetq-server=default/jms-queue=DLQ/:add(entries=["java:/queue/DLQ"])

Références