JBOSS 7 et Message Driven Architecture (MDA)

Gestion des Queues et Topics sous Jboss 7. @MessageDriven et configuration
Pierre LISERONMis à jour le 8 Août 2012
jbossas7_splash.jpg

Configuration pour lenvoi et la réception et message JMS avec Jboss 7

Dans la configuration Full de Jboss 7, un broker de messagerie est intégré. (HornetQ)

Pour lactiver, il suffit de lancer son Jboss avec la configuration full (-c=standalone-full.xml).

Configuration de Jboss 7 messaging

La configuration des queues et topics se fait dans le subsystem urn:jboss:domain:messaging.


> <subsystem xmlns= »urn:jboss:domain:messaging:1.1&Prime;>
  
> <hornetq-server>
  
> <persistence-enabled>true</persistence-enabled>
  
> <journal-file-size>102400</journal-file-size>
  
> <journal-min-files>2</journal-min-files>
> 
> <connectors>
  
> <netty-connector name= »netty » socket-binding= »messaging »/>
  
> <netty-connector name= »netty-throughput » socket-binding= »messaging-throughput »>
  
> <param key= »batch-delay » value= »50&Prime;/>
  
> </netty-connector>
  
> <in-vm-connector name= »in-vm » server-id= »0&Prime;/>
  
> </connectors>
> 
> <acceptors>
  
> <netty-acceptor name= »netty » socket-binding= »messaging »>
  
> <param key= »host » value= »${hornetq.remoting.netty.host:XXX.XXX.XXX.XXX} »/>
  
> <param key= »port » value= »${hornetq.remoting.netty.port:15445} »/>
  
> </netty-acceptor>
  
> <netty-acceptor name= »netty-throughput » socket-binding= »messaging-throughput »>
  
> <param key= »batch-delay » value= »50&Prime;/>
  
> <param key= »direct-deliver » value= »false »/>
  
> </netty-acceptor>
  
> <in-vm-acceptor name= »in-vm » server-id= »0&Prime;/>
  
> </acceptors>
> 
> <security-settings>
  
> <security-setting match= »# »>
  
> <permission type= »send » roles= »guest »/>
  
> <permission type= »consume » roles= »guest »/>
  
> <permission type= »createNonDurableQueue » roles= »guest »/>
  
> <permission type= »deleteNonDurableQueue » roles= »guest »/>
  
> </security-setting>
  
> </security-settings>
> 
> <address-settings>
  
> <address-setting match= »# »>
  
> <dead-letter-address>jms.queue.DLQ</dead-letter-address>
  
> <expiry-address>jms.queue.ExpiryQueue</expiry-address>
  
> <redelivery-delay>0</redelivery-delay>
  
> <max-size-bytes>10485760</max-size-bytes>
  
> <address-full-policy>BLOCK</address-full-policy>
  
> <message-counter-history-day-limit>10</message-counter-history-day-limit>
  
> </address-setting>
  
> </address-settings>
> 
> <jms-connection-factories>
  
> <connection-factory name= »InVmConnectionFactory »>
  
> <connectors>
  
> <connector-ref connector-name= »in-vm »/>
  
> </connectors>
  
> <entries>
  
> <entry name= »java:/ConnectionFactory »/>
  
> </entries>
  
> </connection-factory>
  
> <connection-factory name= »RemoteConnectionFactory »>
  
> <connectors>
  
> <connector-ref connector-name= »netty »/>
  
> </connectors>
  
> <entries>
  
> <entry name= »RemoteConnectionFactory »/>
  
> <entry name= »java:jboss/exported/jms/RemoteConnectionFactory »/>
  
> </entries>
  
> <connection-ttl>6000000</connection-ttl>
  
> </connection-factory>
  
> <pooled-connection-factory name= »hornetq-ra »>
  
> <transaction mode= »xa »/>
  
> <connectors>
  
> <connector-ref connector-name= »in-vm »/>
  
> </connectors>
  
> <entries>
  
> <entry name= »java:/JmsXA »/>
  
> </entries>
  
> </pooled-connection-factory>
  
> </jms-connection-factories>
> 
> <jms-destinations>
  
> <jms-queue name= »testQueue »>
  
> <entry name= »queue/test »/>
  
> <entry name= »java:jboss/exported/jms/queue/test »/>
  
> </jms-queue>
  
> <jms-topic name= »testTopic »>
  
> <entry name= »topic/test »/>
  
> <entry name= »java:jboss/exported/jms/topic/test »/>
  
> </jms-topic>
  
> </jms-destinations>
  
> </hornetq-server>
  
> </subsystem>

La partie la plus intéressante est la partie JMSJava Messaging Service-DESTINATIONS qui permet de créer des queue et des topic ainsi que de configurer leurs noms.

Deux types de noms sont présent: par exemple pour testQueue, vous avez le nom interne (depuis le serveur) et le nom externe depuis une autre application (si vous souhaitez exposer vos Queues).

Le nom interne est: queue/test tandis que le nom externe est : java:jboss/exported/jms/queue/test.

 

En remontant un peu dans le fichier, vous trouverez les factorys, de même deux factory sont présentes (remote et local) avec leurs noms JNDI. Ces factorys font références à des connecteur (ici netty). Pour chaque connecteur vous avez la possibilité de choisir les acceptors (flux entrants). Pensez bien à configurer:  avec la bonne adresse IP sinon vous ne pourrez pas vous connecter à votre QUEUE/TOPIC.

Attention, il est aussi important de sécuriser laccès à vos queues en créer une sécurité:

> <security-domain name= »messaging » cache-type= »default »>
  
> <authentication>
  
> <login-module code= »UsersRoles » flag= »required »>
  
> <module-option name= »usersProperties » value= »${jboss.server.config.dir}/messaging-users.properties »/>
  
> <module-option name= »rolesProperties » value= »${jboss.server.config.dir}/messaging-roles.properties »/>
  
> </login-module>
  
> </authentication>
  
> </security-domain>

Les fichiers messaging-users.properties et messaging-roles.properties sont bien sur à créer.

Enfin il ne reste plus quà configurer les ports pour votre messagerie de la sorte:

Et voici un exemple de message bean qui se trouve sur le serveur:

> import javax.annotation.PostConstruct;
  
> import javax.annotation.PreDestroy;
  
> import javax.annotation.Resource;
  
> import javax.ejb.ActivationConfigProperty;
  
> import javax.ejb.EJBException;
  
> import javax.ejb.MessageDriven;
  
> import javax.ejb.MessageDrivenBean;
  
> import javax.ejb.MessageDrivenContext;
  
> import javax.inject.Inject;
  
> import javax.jms.Connection;
  
> import javax.jms.ConnectionFactory;
  
> import javax.jms.JMSException;
  
> import javax.jms.Message;
  
> import javax.jms.MessageListener;
  
> import javax.jms.ObjectMessage;
  
> import javax.jms.Session;
> 
> import fr.axopen.logging.message.JmsMessage;
> 
> @MessageDriven(activationConfig = {
  
> @ActivationConfigProperty(propertyName = « acknowledgeMode », propertyValue = « Auto-acknowledge »),
  
> @ActivationConfigProperty(propertyName = « destinationType », propertyValue = « javax.jms.Queue »),
  
> @ActivationConfigProperty(propertyName = « destination », propertyValue = « java:jboss/exported/jms/queue/test »),
> 
> })
  
> public class ListingQueue implements MessageDrivenBean, MessageListener {
  
> /**
  
> *
  
> */
  
> private static final long serialVersionUID = 1L;
  
> @Resource(mappedName = « java:/JmsXA »)
  
> private ConnectionFactory factory;
> 
> private Connection connection;
> 
> private Session session;
> 
> @SuppressWarnings(« unused »)
  
> private MessageDrivenContext messageDrivenContext;
> 
> @PreDestroy
  
> protected void preDestroy() throws JMSException {
  
> session.close();
  
> connection.close();
  
> }
> 
> @PostConstruct
  
> protected void postConstruct() throws JMSException {
  
> connection = factory.createConnection();
  
> session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
  
> }
> 
> @Override
  
> public void setMessageDrivenContext(MessageDrivenContext ctx)
  
> throws EJBException {
  
> this.messageDrivenContext = ctx;
  
> }
> 
> @Override
  
> public void ejbRemove() throws EJBException {
  
> }
> 
> @Override
  
> public void onMessage(Message message) {
> 
> try {
> 
> } catch (JMSException jmse) {
  
> throw new RuntimeException(jmse);
  
> }
  
> }
> 
> }

Enfin si vous souhaitez vous connecter à la file JMS à distance, voici un exemple:

## Exemple d&rsquo;envoi d&rsquo;un message JMS

import java.io.PrintWriter;

> import java.io.StringWriter;
  
> import java.util.Date;
  
> import java.util.HashMap;
  
> import java.util.List;
  
> import java.util.Map;
  
> import java.util.Properties;
> 
> import javax.jms.Connection;
  
> import javax.jms.JMSException;
  
> import javax.jms.MessageProducer;
  
> import javax.jms.ObjectMessage;
  
> import javax.jms.Queue;
  
> import javax.jms.QueueConnectionFactory;
  
> import javax.jms.Session;
  
> import javax.naming.Context;
  
> import javax.naming.InitialContext;
  
> import javax.naming.NamingException;
  
> import javax.servlet.ServletRequest;
  
> import javax.servlet.http.HttpServletRequest;
> 
> import org.apache.commons.lang.exception.ExceptionUtils;
  
> import org.hornetq.api.core.TransportConfiguration;
  
> import org.hornetq.api.jms.HornetQJMSClient;
  
> import org.hornetq.api.jms.JMSFactoryType;
  
> import org.hornetq.core.remoting.impl.netty.NettyConnectorFactory;
  
> import org.hornetq.core.remoting.impl.netty.TransportConstants;
  
> import org.hornetq.jms.client.HornetQConnectionFactory;
> 
> import com.workinlive.framework.Config;
> 
> import fr.axopen.logging.message.JmsMessage;
  
> import fr.axopen.logging.message.TypeMessageEnum;
> 
> public class JmsConnectionFactory {
  
> private static JmsConnectionFactory instance;
> 
> private Context mContext;
  
> Connection mConnection = null;
> 
> QueueConnectionFactory mConnectionFactory;
  
> Queue mQueue = null;
  
> HornetQConnectionFactory mHornetConnectionFactory;
  
> private boolean mIsOperationnel = false;
> 
> private void connect() {
  
> try {
  
> System.out.println(« JMS Connection »);
  
> Properties props = new Properties();
  
> props.put(Context.INITIAL\_CONTEXT\_FACTORY,
  
> « org.jboss.naming.remote.client.InitialContextFactory »);
  
> props.put(Context.PROVIDER\_URL, Config.JMS\_PROVIDER_URL);
  
> props.put(Context.SECURITY\_PRINCIPAL, Config.JMS\_SECURITY_PRINCIPAL);
  
> props.put(Context.SECURITY_CREDENTIALS,
  
> Config.JMS\_SECURITY\_CREDENTIALS);
> 
> mContext = new InitialContext(props);
> 
> final Map<String, Object> p = new HashMap<String, Object>();
  
> TransportConfiguration tc;
> 
> p.put(TransportConstants.HOST\_PROP\_NAME, Config.JMS\_HOST\_LOGGING);
  
> p.put(TransportConstants.PORT\_PROP\_NAME, Config.JMS\_HOST\_PORT);
> 
> tc = new TransportConfiguration(
  
> NettyConnectorFactory.class.getName(), p);
> 
> mHornetConnectionFactory = HornetQJMSClient
  
> .createConnectionFactoryWithoutHA(JMSFactoryType.QUEUE_CF,
  
> tc);
> 
> mQueue = (Queue) mContext.lookup(Config.JMS\_JNDI\_QUEUE);
> 
> mConnection = mHornetConnectionFactory.createConnection();
> 
> mIsOperationnel = true;
  
> } catch (NamingException e) {
  
> e.printStackTrace();
  
> System.err.println(« Problème de connexion JMS »);
  
> } catch (JMSException e) {
  
> e.printStackTrace();
  
> System.err.println(« Erreur de connexion JMS »);
  
> }
> 
> }
> 
> private JmsConnectionFactory() {
  
> connect();
> 
> }
> 
> public static JmsConnectionFactory getInstance() {
  
> if (instance == null) // 1
  
> instance = new JmsConnectionFactory(); // 2
  
> return instance; // 3
  
> }
> 
> public Connection getConnection() {
  
> if (mConnection == null || !mIsOperationnel) {
  
> closeSession();
  
> mIsOperationnel = true;
  
> connect();
  
> }
> 
> return mConnection;
  
> }
> 
> public Queue getQueue() {
  
> return mQueue;
  
> }
> 
> public void closeSession() {
  
> try {
  
> if (mContext != null) {
  
> mContext.close();
  
> }
  
> } catch (NamingException e) {
  
> e.printStackTrace();
  
> }
  
> try {
  
> if (mHornetConnectionFactory != null)
  
> mHornetConnectionFactory.close();
  
> } catch (Exception e) {
  
> e.printStackTrace();
  
> }
  
> try {
  
> if (mConnection != null)
  
> mConnection.close();
  
> } catch (JMSException e) {
  
> e.printStackTrace();
  
> }
> 
> }
> 
> public boolean isOperationnel() {
  
> return mIsOperationnel;
  
> }
> 
> public void setOperationnel(boolean pIsOperationnel) {
  
> mIsOperationnel = pIsOperationnel;
  
> }

N'hésitez pas si vous avez des questions!