In this message, I will guide the reader through the process of writing a simple sender-receiver application that uses a Java Message Service queue for the JBoss Application Server 7.1. It may be my fault, but as the time of writing of this message, I failed to find good documentation on how to run the most basic example of JMS in JBoss AS 7. This is what I show here. I will assume that the reader is familiar with JMS. There are plenty of resources out there on the web covering this topic, and it is not the goal of this blog to do the same.
I tried all this on Mac OS X Lion with the Brontes version of JBoss.
The first thing to know is that by default JBoss doesn't start with messaging. Therefore, you must explicitly use a different configuration that enables messaging. In the standalone case, you can do as follows, but you may want to defer starting the server to a later stage, after performing all necessary changes I describe:
./standalone.sh --server-config=standalone-full.xml
In other words, you need to specify the configuration file standalone-full.xml. The bad news is that we will need to change this configuration file, but this is not particularly difficult.
But before going into the server details, let us focus on the client applications. I will create one sender and one receiver application. They are pretty basic, in the sense that they only exchange one message and finish. I present them here. You can create your own standard Java project in Eclipse (or NetBeans) and add these two classes to the default package:
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.MessageProducer;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.naming.InitialContext;
import javax.naming.NamingException;
public class Sender {
private ConnectionFactory cf;
private Connection c;
private Session s;
private Destination d;
private MessageProducer mp;
public Sender() throws NamingException, JMSException {
InitialContext init = new InitialContext();
this.cf = (ConnectionFactory) init.lookup("jms/RemoteConnectionFactory");
this.d = (Destination) init.lookup("jms/queue/PlayQueue");
this.c = (Connection) this.cf.createConnection("joao", "pedro");
this.c.start();
this.s = this.c.createSession(false, Session.AUTO_ACKNOWLEDGE);
this.mp = this.s.createProducer(this.d);
}
private void send(String string) throws JMSException {
TextMessage tm = this.s.createTextMessage(string);
this.mp.send(tm);
}
private void close() throws JMSException {
this.c.close();
}
/**
* @param args
* @throws JMSException
* @throws NamingException
*/
public static void main(String[] args) throws NamingException, JMSException {
Sender s = new Sender();
s.send("Ola ca estou eu!");
s.close();
}
}
|
The Receiver:
import javax.jms.Connection; import javax.jms.ConnectionFactory; import javax.jms.Destination; import javax.jms.JMSException; import javax.jms.MessageConsumer; import javax.jms.Session; import javax.jms.TextMessage; import javax.naming.InitialContext; import javax.naming.NamingException; private ConnectionFactory cf; private Connection c; private Session s; private Destination d; private MessageConsumer mc; InitialContext init = new InitialContext(); this.cf = (ConnectionFactory) init.lookup("jms/RemoteConnectionFactory"); this.d = (Destination) init.lookup("jms/queue/PlayQueue"); this.c = (Connection) this.cf.createConnection("joao", "pedro"); this.c.start(); this.s = this.c.createSession(false, Session.AUTO_ACKNOWLEDGE); mc = s.createConsumer(d); } TextMessage msg = (TextMessage) mc.receive(); return msg.getText(); } this.c.close(); }
/**
* @param args
* @throws JMSException
* @throws NamingException
*/
public static void main(String[] args) throws NamingException, JMSException {Receiver r = new Receiver(); System.out.println("Mensagem: " + msg); r.close(); } |
In this source code, what I found really problematic was to initialize the destination (the queue) and the ConnectionFactory. Eventually, I managed to use JNDI, as I should. I summarize the process in following lines:
InitialContext init = new InitialContext();
this.cf = (QueueConnectionFactory) init.lookup("jms/RemoteConnectionFactory");
this.d = (Destination) init.lookup("jms/queue/PlayQueue");
this.c = (Connection) this.cf.createConnection("joao", "pedro");
|
We need the extra "jms" before the name of the resource. For this to work, we also need an extra file, the jndi.properties. Place this file in the src folder of your project (this will not work for WildFly. Check the new version in this message):
java.naming.factory.initial=org.jboss.naming.remote.client.InitialContextFactory
java.naming.provider.url=remote://localhost:4447jboss.naming.client.ejb.context=true
#username
java.naming.security.principal=joao
#password
java.naming.security.credentials=pedro |
To use the JMS libraries (and other JBoss client libraries by the way) you need to add the following jar file: (jboss-home)/bin/client/jboss-client.jar.
Note that we are providing the (very weak) user credentials of "joao" with password "pedro" to create the connection. For this to work, we need to add this user in the server running the add-user.sh (or .bat) available in the bin directory. The script will let us know in exactly which files did it do the modifications, but this is for the sake of curiosity only. I show this process in the next figure.
For this example to work we also need to add the queue to the standallone-full.xml file (refer to the command line in the top).
Now, you should be able to start the server first and then run the receiver and the sender in any order. Good luck!
<jms-destinations>
<jms-queue name="testQueue">
<entry name="queue/test"/>
<entry name="java:jboss/exported/jms/queue/test"/>
</jms-queue>
<jms-queue name="PlayQueue">
<entry name="queue/PlayQueue"/>
<entry name="java:jboss/exported/jms/queue/PlayQueue"/>
</jms-queue>
<jms-topic name="testTopic">
<entry name="topic/test"/>
<entry name="java:jboss/exported/jms/topic/test"/>
</jms-topic>
</jms-destinations>
|
Now, you should be able to start the server first and then run the receiver and the sender in any order. Good luck!