20 January 2005

Additional Info for ActiveMQ

ActiveMQ is cool. Imagine building destinations for queues and topics without touching the JMS Provider or the MQ server, has a small footprint, uses a tried and tested embedded database. These create-on-the-fly destinations are truly an intelligent feature every JMS vendor should include in their products. Let's try a simple example.

ActiveMQ supports JNDI, just like any other J2EE components. So for this example we will use JNDI for looking up destinations and connection factories.

Listing 1: jndi.properties



java.naming.factory.initial = org.codehaus.activemq.jndi.ActiveMQInitialContextFactory

# use the following property to embed a broker inside this JVM
#useEmbeddedBroker = true

# use the following property to specify a class path resource or URL
# used to configure an embedded broker using the XML configuration file
#brokerXmlConfig = file:src/conf/sample-conf/default.xml

# use the following property to configure the default connector
brokerURL = tcp://10.121.54.70:61616

# use the following property to specify the JNDI name the connection factory
# should appear as.
#connectionFactoryNames = connectionFactory, queueConnectionFactory, topicConnectionFactry

# register some queues in JNDI using the form
# queue.[jndiName] = [physicalName]
queue.MyQueue = example.MyQueue


# register some topics in JNDI using the form
# topic.[jndiName] = [physicalName]
topic.MyTopic = example.MyTopic



We have registered a queue and a topic. But for the example, we will use the queue. The code listing below shows a simple JMS message producer that uses Sun's j2ee.jar library.

Listing 2: SimpleProducer.java


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.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;

/**
* A simple polymorphic JMS producer which can work with Queues or Topics
* which uses JNDI to lookup the JMS connection factory and destination
*
* @version $Revision: 1.1 $
*/
public class SimpleProducer {

/**
* @param args the destination name to send to and optionally,
* the number of messages to send
*/
public static void main(String[] args) {
Context jndiContext = null;
ConnectionFactory connectionFactory = null;
Connection connection = null;
Session session = null;
Destination destination = null;
MessageProducer producer = null;
String destinationName = null;
final int NUM_MSGS;

if ((args.length < 1) || (args.length > 2)) {
System.out.println("Usage: java SimpleProducer []");
System.exit(1);
}
destinationName = new String(args[0]);
System.out.println("Destination name is " + destinationName);
if (args.length == 2) {
NUM_MSGS = (new Integer(args[1])).intValue();
}
else {
NUM_MSGS = 1;
}

/*
* Create a JNDI API InitialContext object
*/
try {
jndiContext = new InitialContext();
}
catch (NamingException e) {
System.out.println("Could not create JNDI API context: " + e.toString());
System.exit(1);
}

/*
* Look up connection factory and destination.
*/
try {
connectionFactory = (ConnectionFactory) jndiContext.lookup("ConnectionFactory");
destination = (Destination) jndiContext.lookup(destinationName);
}
catch (NamingException e) {
System.out.println("JNDI API lookup failed: " + e);
System.exit(1);
}

/*
* Create connection.
* Create session from connection; false means session is not transacted.
* Create sender and text message.
* Send messages, varying text slightly.
* Send end-of-messages message.
* Finally, close connection.
*/
try {
connection = connectionFactory.createConnection();
session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
producer = session.createProducer(destination);
TextMessage message = session.createTextMessage();
for (int i = 0; i < NUM_MSGS; i++) {
message.setText("This is a schmuck message " + (i + 1));
System.out.println("Sending message: " + message.getText());
producer.send(message);
}

/*
* Send a non-text control message indicating end of messages.
*/
producer.send(session.createMessage());
}
catch (JMSException e) {
System.out.println("Exception occurred: " + e);
}
finally {
if (connection != null) {
try {
connection.close();
}
catch (JMSException e) {
}
}
}
}
}



If we run the message producer above it will register the queue name specified in the command line argument and optionally the number of times it will send the message. Notice that in the ActiveMQ's Getting Started guide, nothing was mentioned about configuring queues or topics in the server. So the code will just create the destination if it does not exist yet and send the message.


ActiveMQ's documentation for JNDI support only showed the SimpleProducer.java example. The listing below will show how the message sent by SimpleProducer will be consumed.


Listing 3: SimpleConsumer.java



import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageConsumer;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;

/**
*
* Created Jan 20, 2005 10:41:06 AM
* @author Jared Odulio
*
* Description:
*
*/
public class SimpleConsumer {

/**
*
*/
public SimpleConsumer() {
super();
// TODO Auto-generated constructor stub
}

public static void main(String[] args) {
Context jndiContext = null;
ConnectionFactory connectionFactory = null;
Connection connection = null;
Session session = null;
Destination destination = null;
MessageConsumer consumer = null;
TextMessage message = null;
String destinationName = null;
final int NUM_MSGS;

if ((args.length < 1) || (args.length > 2)) {
System.out.println("Usage: java SimpleProducer []");
System.exit(1);
}
destinationName = new String(args[0]);
System.out.println("Destination name is " + destinationName);
if (args.length == 2) {
NUM_MSGS = (new Integer(args[1])).intValue();
}
else {
NUM_MSGS = 1;
}

/*
* Create a JNDI API InitialContext object
*/
try {
jndiContext = new InitialContext();
}
catch (NamingException e) {
System.out.println("Could not create JNDI API context: " + e.toString());
System.exit(1);
}

/*
* Look up connection factory and destination.
*/
try {
connectionFactory = (ConnectionFactory) jndiContext.lookup("ConnectionFactory");
destination = (Destination) jndiContext.lookup(destinationName);
}
catch (NamingException e) {
System.out.println("JNDI API lookup failed: " + e);
System.exit(1);
}

try {
connection = connectionFactory.createConnection();
session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
//producer = session.createProducer(destination);
consumer = session.createConsumer(destination);
connection.start();
//message = session.createTextMessage();
for (int i = 0; i < NUM_MSGS; i++) {

Message msg = consumer.receive();
if (msg instanceof TextMessage){
message = (TextMessage)msg;
System.out.println(message.getText());

}
}

/*
* Send a non-text control message indicating end of messages.
*/

}
catch (JMSException e) {
System.out.println("Exception occurred: " + e);
}
finally {
if (connection != null) {
try {
connection.close();
}
catch (JMSException e) {
}
}
}
}


}




So who needs a JMS implementation where you have to define the queues and topic thru the some XML configuration file in order to use them?

No comments: