AXOPEN

JBOSS 7 et Message Driven Architecture (MDA)

Configuration pour l’envoi 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 l’activer, 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″>
<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″/>
</netty-connector>
<in-vm-connector name= »in-vm » server-id= »0″/>
</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″/>
<param key= »direct-deliver » value= »false »/>
</netty-acceptor>
<in-vm-acceptor name= »in-vm » server-id= »0″/>
</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 JMS-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: <param key= »host » value= »${hornetq.remoting.netty.host:XXX.XXX.XXX.XXX} »/> avec la bonne adresse IP sinon vous ne pourrez pas vous connecter à votre QUEUE/TOPIC.

Attention, il est aussi important de sécuriser l’accè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:

<socket-binding name= »messaging » port= »15445″/>
<socket-binding name= »messaging-throughput » port= »15455″/>

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’envoi d’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!