CHAPTER 6 Messaging on JBoss - JMS Configuration and Architecture

The JMS API stands for Java? Message Service Application Programming Interface, and it is used by applications to send asynchronous "business quality" messages to other applications. In the JMS world, messages are not sent directly to other applications. Instead, messages are sent to destinations, also known as "queues" or "topics". Applications sending messages do not need to worry if the receiving applications are up and running, and conversely, receiving applications do not need to worry about the sending application's status. Both senders, and receivers only interact with the destinations.

The JMS API is the standardized interface to a JMS provider, sometimes called a Message Oriented Middleware (MOM) system. JBoss comes with a JMS 1.0.2b compliant JMS provider called JBoss Messaging or JBossMQ. When you use the JMS API with JBoss, you are using the JBoss Messaging engine transparently. JBoss Messaging fully implements the JMS specification. Therefore, the best JBoss Messaging user guide is the JMS specification! For more information about the JMS API please visit the JMS Tutorial or JMS Downloads & Specifications .

This chapter focuses on the JBoss specific aspects of using JMS and message driven beans as well as the JBoss Messaging configuration and MBeans.

JMS Examples

Scott Stark

In this section we discuss the basics needed to use the JBoss JMS implementation. JMS leaves the details of accessing JMS connection factories and destinations as provider specific details. What you need to know to use the JBoss Messaging layer is:

  • The location of the javax.jms.QueueConnectionFactory and javax.jms.TopicConnectionFactory . In JBoss both connection factory implementations are located under the JNDI name "ConnectionFactory".
  • How to lookup JMS destinations ( javax.jmx.Queue and javax.jms.Topic ). Destinations are configured via MBeans as we will see when we discuss the messaging MBeans. Several default queues are defined and are located at the JNDI names: "queue/testQueue", "queue/ex". "queue/A", "queue/B", "queue/C", and "queue/D". The default topics are located at the JNDI names: "topic/testTopic", "topic/securedTopic", and "topic/testDurableTopic".
  • The JBoss Messaging jars. These include concurrent.jar, jbossmq-client.jar, jboss-common-client.jar, jboss-system-client.jar, jnp-client.jar, log4j.jar and jnet.jar (jnet.jar is only needed for JDK 1.3)

In the following subsections we will look at examples of the various JMS messaging models and message driven beans. The chapter example source is located under the src/main/org/jboss/chap6 directory of the book examples.

A Point-To-Point Example

Let's start out with a point-to-point (P2P) example. In the P2P model, a sender delivers messages to a queue and a single receiver pulls the message off of the queue. The receiver does not need to be listening to the queue at the time the message is sent. See A P2P JMS client example. shows a complete P2P example that sends a javax.jms.TextMessage to a the queue "queue/testQueue" and asynchronously receives the message from the same queue.

A P2P JMS client example

package org.jboss.chap6.ex1;

import javax.jms.JMSException;

import javax.jms.Message;

import javax.jms.MessageListener;

import javax.jms.Queue;

import javax.jms.QueueConnection;

import javax.jms.QueueConnectionFactory;

import javax.jms.QueueReceiver;

import javax.jms.QueueSender;

import javax.jms.QueueSession;

import javax.jms.TextMessage;

import javax.naming.InitialContext;

import javax.naming.NamingException;

import EDU.oswego.cs.dl.util.concurrent.CountDown;

/** A complete JMS client example program that sends a

TextMessage to a Queue and asynchronously receives the

message from the same Queue.

@author Scott.Stark@jboss.org

@version $Revision:$

*/

public class SendRecvClient

{

static CountDown done = new CountDown(1);

QueueConnection conn;

QueueSession session;

Queue que;

public static class ExListener implements MessageListener

{

public void onMessage(Message msg)

{

done.release();

TextMessage tm = (TextMessage) msg;

try

{

System.out.println("onMessage, recv text="

+ tm.getText());

}

catch(Throwable t)

{

t.printStackTrace();

}

}

}

public void setupPTP()

throws JMSException, NamingException

{

InitialContext iniCtx = new InitialContext();

Object tmp = iniCtx.lookup("ConnectionFactory");

QueueConnectionFactory qcf = (QueueConnectionFactory) tmp;

conn = qcf.createQueueConnection();

que = (Queue) iniCtx.lookup("queue/testQueue");

session = conn.createQueueSession(false,

QueueSession.AUTO_ACKNOWLEDGE);

conn.start();

}

public void sendRecvAsync(String text)

throws JMSException, NamingException

{

System.out.println("Begin sendRecvAsync");

// Setup the PTP connection, session

setupPTP();

// Set the async listener

QueueReceiver recv = session.createReceiver(que);

recv.setMessageListener(new ExListener());

// Send a text msg

QueueSender send = session.createSender(que);

TextMessage tm = session.createTextMessage(text);

send.send(tm);

System.out.println("sendRecvAsync, sent text="

+ tm.getText());

send.close();

System.out.println("End sendRecvAsync");

}

public void stop() throws JMSException

conn.stop(); {

session.close();

conn.close();

}

public static void main(String args[]) throws Exception

{

SendRecvClient client = new SendRecvClient();

client.sendRecvAsync("A text msg");

client.done.acquire();

client.stop();

System.exit(0);

}

}

The client may be run using the following command line:

[nr@toki examples]$ ant -Dchap=chap6 -Dex=1p2p run-example

Buildfile: build.xml

...

run-example1p2p:

[java] [INFO,SendRecvClient] Begin SendRecvClient, now=1083649316059

[java] [INFO,SendRecvClient] Begin sendRecvAsync

[java] [INFO,SendRecvClient] onMessage, recv text=A text msg

[java] [INFO,SendRecvClient] sendRecvAsync, sent text=A text msg

[java] [INFO,SendRecvClient] End sendRecvAsync

[java] [INFO,SendRecvClient] End SendRecvClient

 

BUILD SUCCESSFUL

Total time: 9 seconds

A Pub-Sub Example

The JMS publish/subscribe (Pub-Sub) message model is a one-to-many model. A publisher sends a message to a topic and all active subscribers of the topic receive the message. Subscribers that are not actively listening to the topic will miss the published message. shows a complete JMS client that sends a javax.jms.TextMessage to a topic and asynchronously receives the message from the same topic.

A Pub-Sub JMS client example

package org.jboss.chap6.ex1;

import javax.jms.JMSException;

import javax.jms.Message;

import javax.jms.MessageListener;

import javax.jms.Topic;

import javax.jms.TopicConnection;

import javax.jms.TopicConnectionFactory;

import javax.jms.TopicPublisher;

import javax.jms.TopicSubscriber;

import javax.jms.TopicSession;

import javax.jms.TextMessage;

import javax.naming.InitialContext;

import javax.naming.NamingException;

import EDU.oswego.cs.dl.util.concurrent.CountDown;

/** A complete JMS client example program that sends a

TextMessage to a Topic and asynchronously receives the

message from the same Topic.

@author Scott.Stark@jboss.org

@version $Revision:$

*/

public class TopicSendRecvClient

{

static CountDown done = new CountDown(1);

TopicConnection conn = null;

TopicSession session = null;

Topic topic = null;

public static class ExListener implements MessageListener

{

public void onMessage(Message msg)

{

done.release();

TextMessage tm = (TextMessage) msg;

try

{

System.out.println("onMessage, recv text="

+ tm.getText());

}

catch(Throwable t)

{

t.printStackTrace();

}

}

}

public void setupPubSub()

throws JMSException, NamingException

{

InitialContext iniCtx = new InitialContext();

Object tmp = iniCtx.lookup("ConnectionFactory");

TopicConnectionFactory tcf = (TopicConnectionFactory) tmp;

conn = tcf.createTopicConnection();

topic = (Topic) iniCtx.lookup("topic/testTopic");

session = conn.createTopicSession(false,

TopicSession.AUTO_ACKNOWLEDGE);

conn.start();

}

public void sendRecvAsync(String text)

throws JMSException, NamingException

{

System.out.println("Begin sendRecvAsync");

// Setup the PubSub connection, session

setupPubSub();

// Set the async listener

TopicSubscriber recv = session.createSubscriber(topic);

recv.setMessageListener(new ExListener());

// Send a text msg

TopicPublisher send = session.createPublisher(topic);

TextMessage tm = session.createTextMessage(text);

send.publish(tm);

System.out.println("sendRecvAsync, sent text="

+ tm.getText());

send.close();

System.out.println("End sendRecvAsync");

}

public void stop() throws JMSException

{

conn.stop();

session.close();

conn.close();

}

public static void main(String args[]) throws Exception

{

System.out.println("Begin TopicSendRecvClient, now="+System.currentTimeMillis());

TopicSendRecvClient client = new TopicSendRecvClient();

client.sendRecvAsync("A text msg, now="+System.currentTimeMillis());

client.done.acquire();

client.stop();

System.out.println("End TopicSendRecvClient");

System.exit(0);

}

}

The client may be run using the following command line:

[nr@toki examples]$ ant -Dchap=chap6 -Dex=1ps run-example

Buildfile: build.xml

...

run-example1ps:

[java] Begin TopicSendRecvClient, now=1083649449640

[java] Begin sendRecvAsync

[java] onMessage, recv text=A text msg, now=1083649449642

[java] sendRecvAsync, sent text=A text msg, now=1083649449642

[java] End sendRecvAsync

[java] End TopicSendRecvClient

 

BUILD SUCCESSFUL

Total time: 3 seconds

Now let's break the publisher and subscribers into separate programs to demonstrate that subscribers only receive messages while they are listening to a topic. See A JMS publisher client. shows a variation of the previous Pub-Sub client that only publishes messages to the "topic/testTopic" topic. The subscriber only client is shown in See A JMS subscriber client..

A JMS publisher client

package org.jboss.chap6.ex1;

import javax.jms.JMSException;

import javax.jms.Message;

import javax.jms.MessageListener;

import javax.jms.Topic;

import javax.jms.TopicConnection;

import javax.jms.TopicConnectionFactory;

import javax.jms.TopicPublisher;

import javax.jms.TopicSubscriber;

import javax.jms.TopicSession;

import javax.jms.TextMessage;

import javax.naming.InitialContext;

import javax.naming.NamingException;

/** A JMS client example program that sends a TextMessage to a Topic

@author Scott.Stark@jboss.org

@version $Revision:$

*/

public class TopicSendClient

{

TopicConnection conn = null;

TopicSession session = null;

Topic topic = null;

public void setupPubSub()

throws JMSException, NamingException

{

InitialContext iniCtx = new InitialContext();

Object tmp = iniCtx.lookup("ConnectionFactory");

TopicConnectionFactory tcf = (TopicConnectionFactory) tmp;

conn = tcf.createTopicConnection();

topic = (Topic) iniCtx.lookup("topic/testTopic");

session = conn.createTopicSession(false,

TopicSession.AUTO_ACKNOWLEDGE);

conn.start();

}

public void sendAsync(String text)

throws JMSException, NamingException

{

System.out.println("Begin sendAsync");

// Setup the pub/sub connection, session

setupPubSub();

// Send a text msg

TopicPublisher send = session.createPublisher(topic);

TextMessage tm = session.createTextMessage(text);

send.publish(tm);

System.out.println("sendAsync, sent text="

+ tm.getText());

send.close();

System.out.println("End sendAsync");

}

public void stop() throws JMSException

{

conn.stop();

session.close();

conn.close();

}

public static void main(String args[]) throws Exception

{

System.out.println("Begin TopicSendClient, now="+System.currentTimeMillis());

TopicSendClient client = new TopicSendClient();

client.sendAsync("A text msg, now="+System.currentTimeMillis());

client.stop();

System.out.println("End TopicSendClient");

System.exit(0);

}

}

A JMS subscriber client

package org.jboss.chap6.ex1;

import javax.jms.JMSException;

import javax.jms.Message;

import javax.jms.MessageListener;

import javax.jms.Topic;

import javax.jms.TopicConnection;

import javax.jms.TopicConnectionFactory;

import javax.jms.TopicPublisher;

import javax.jms.TopicSubscriber;

import javax.jms.TopicSession;

import javax.jms.TextMessage;

import javax.naming.InitialContext;

import javax.naming.NamingException;

/** A JMS client example program that synchronously receives a message a Topic

@author Scott.Stark@jboss.org

@version $Revision:$

*/

public class TopicRecvClient

{

TopicConnection conn = null;

TopicSession session = null;

Topic topic = null;

public void setupPubSub()

throws JMSException, NamingException

{

InitialContext iniCtx = new InitialContext();

Object tmp = iniCtx.lookup("ConnectionFactory");

TopicConnectionFactory tcf = (TopicConnectionFactory) tmp;

conn = tcf.createTopicConnection();

topic = (Topic) iniCtx.lookup("topic/testTopic");

session = conn.createTopicSession(false,

TopicSession.AUTO_ACKNOWLEDGE);

conn.start();

}

public void recvSync()

throws JMSException, NamingException

{

System.out.println("Begin recvSync");

// Setup the pub/sub connection, session

setupPubSub();

// Wait upto 5 seconds for the message

TopicSubscriber recv = session.createSubscriber(topic);

Message msg = recv.receive(5000);

if( msg == null )

System.out.println("Timed out waiting for msg");

else

System.out.println("TopicSubscriber.recv, msgt="+msg);

}

public void stop() throws JMSException

{

conn.stop();

session.close();

conn.close();

}

public static void main(String args[]) throws Exception

{

System.out.println("Begin TopicRecvClient, now="+System.currentTimeMillis());

TopicRecvClient client = new TopicRecvClient();

client.recvSync();

client.stop();

System.out.println("End TopicRecvClient");

System.exit(0);

}

}

Run the TopicSendClient followed by the TopicRecvClient as follows:

[nr@toki examples]$ ant -Dchap=chap6 -Dex=1ps2 run-example

Buildfile: build.xml

...

run-example1ps2:

[java] Begin TopicSendClient, now=1083649621287

[java] Begin sendAsync

[java] sendAsync, sent text=A text msg, now=1083649621289

[java] End sendAsync

[java] End TopicSendClient

[java] Begin TopicRecvClient, now=1083649625592

[java] Begin recvSync

[java] Timed out waiting for msg

[java] End TopicRecvClient

 

BUILD SUCCESSFUL

 

Total time: 10 seconds

The output shows that the topic subscriber client (TopicRecvClient) fails to receive the message sent by the publisher due to a timeout.

A Pub-Sub With Durable Topic Example

JMS supports a messaging model that is a cross between the P2P and Pub-Sub models. When a Pub-Sub client wants to receive all messages posted to the topic it subscribes to even when it is not actively listening to the topic, the client may achieve this behavior using a durable topic. Let's look at a variation of the preceding subscriber client that uses a durable topic to ensure that it receives all messages, include those published when the client is not listening to the topic. See A durable topic JMS client example. shows the durable topic client with the key differences between the See A JMS subscriber client. client highlighted in bold.

A durable topic JMS client example

package org.jboss.chap6.ex1;

import javax.jms.JMSException;

import javax.jms.Message;

import javax.jms.MessageListener;

import javax.jms.Topic;

import javax.jms.TopicConnection;

import javax.jms.TopicConnectionFactory;

import javax.jms.TopicPublisher;

import javax.jms.TopicSubscriber;

import javax.jms.TopicSession;

import javax.jms.TextMessage;

import javax.naming.InitialContext;

import javax.naming.NamingException;

/** A JMS client example program that synchronously receives a message a Topic

@author Scott.Stark@jboss.org

@version $Revision:$

*/

public class DurableTopicRecvClient

{

TopicConnection conn = null;

TopicSession session = null;

Topic topic = null;

public void setupPubSub()

throws JMSException, NamingException

{

InitialContext iniCtx = new InitialContext();

Object tmp = iniCtx.lookup("ConnectionFactory");

TopicConnectionFactory tcf = (TopicConnectionFactory) tmp;

conn = tcf.createTopicConnection("john", "needle");

topic = (Topic) iniCtx.lookup("topic/testTopic");

session = conn.createTopicSession(false,

TopicSession.AUTO_ACKNOWLEDGE);

conn.start();

}

public void recvSync()

throws JMSException, NamingException

{

System.out.println("Begin recvSync");

// Setup the pub/sub connection, session

setupPubSub();

// Wait upto 5 seconds for the message

TopicSubscriber recv = session.createDurableSubscriber(topic, "chap6-ex1dtps");

Message msg = recv.receive(5000);

if( msg == null )

System.out.println("Timed out waiting for msg");

else

System.out.println("DurableTopicRecvClient.recv, msgt="+msg);

}

public void stop() throws JMSException

{

conn.stop();

session.close();

conn.close();

}

public static void main(String args[]) throws Exception

{

System.out.println("Begin DurableTopicRecvClient, now="+System.currentTimeMillis());

DurableTopicRecvClient client = new DurableTopicRecvClient();

client.recvSync();

client.stop();

System.out.println("End DurableTopicRecvClient");
System.exit(0);

}

}

Now run the previous topic publisher with the durable topic subscriber as follows:

[nr@toki examples]$ ant -Dchap=chap6 -Dex=1psdt run-example

Buildfile: build.xml

...

run-example1psdt:

[java] Begin DurableTopicSetup

[java] End DurableTopicSetup

[java] Begin TopicSendClient, now=1083649712652

[java] Begin sendAsync

[java] sendAsync, sent text=A text msg, now=1083649712655

[java] End sendAsync

[java] End TopicSendClient

[java] Begin DurableTopicRecvClient, now=1083649716858

[java] Begin recvSync

[java] DurableTopicRecvClient.recv, msgt=org.jboss.mq.SpyTextMessage {

[java] Header {

[java] jmsDestination : TOPIC.testTopic.DurableSubscriberExample.chap6-ex1dtps

[java] jmsDeliveryMode : 2

[java] jmsExpiration : 0

[java] jmsPriority : 4

[java] jmsMessageID : ID:5-10836497160641

[java] jmsTimeStamp : 1083649716064

[java] jmsCorrelationID: null

[java] jmsReplyTo : null

[java] jmsType : null

[java] jmsRedelivered : false

[java] jmsProperties : {}

[java] jmsPropertiesReadWrite:false

[java] msgReadOnly : true

[java] producerClientId: ID:5

[java] }

[java] Body {

[java] text :A text msg, now=1083649712655

[java] }

[java] }

[java] End DurableTopicRecvClient

 

BUILD SUCCESSFUL

Total time: 6 seconds

Items of note for the durable topic example include:

  • The TopicConnectionFactory creation in the durable topic client used a username and password, and the TopicSubscriber creation was done using the createDurableSubscriber(Topic, String) method. This is a requirement of durable topic subscribers. The messaging server needs to know what client is requesting the durable topic and what the name of the durable topic subscription is. We will discuss the details of durable topic setup in the configuration section.
  • An org.jboss.chap6.DurableTopicSetup client was run prior to the TopicSendClient . The reason for this is a durable topic subscriber must have registered a subscription at some point in the past in order for the messaging server to save messages. JBoss supports dynamic durable topic subscribers and the DurableTopicSetup client simply creates a durable subscription receiver and then exits. This leaves an active durable topic subscriber on the "topic/testTopic" and the messaging server knows that any messages posted to this topic must be saved for latter delivery.
  • The TopicSendClient does not change for the durable topic. The notion of a durable topic is a subscriber only notion.
  • The DurableTopicRecvClient sees the message published to the "topic/testTopic" even though it was not listening to the topic at the time the message was published.

A Point-To-Point With MDB Example

The EJB 2.0 specification added the notion of message driven beans (MDB). A MDB is a business component that may be invoked asynchronously. As of the EJB 2.0 specification, JMS was the only mechanism by which MDBs could be accessed.See A TextMessage processing MDB. shows an MDB that transforms the TextMessages it receives and sends the transformed messages to the queue found in the incoming message JMSReplyTo header.

A TextMessage processing MDB

package org.jboss.chap6.ex2;

import javax.ejb.MessageDrivenBean;

import javax.ejb.MessageDrivenContext;

import javax.ejb.EJBException;

import javax.jms.JMSException;

import javax.jms.Message;

import javax.jms.MessageListener;

import javax.jms.Queue;

import javax.jms.QueueConnection;

import javax.jms.QueueConnectionFactory;

import javax.jms.QueueSender;

import javax.jms.QueueSession;

import javax.jms.TextMessage;

import javax.naming.InitialContext;

import javax.naming.NamingException;

/** An MDB that transforms the TextMessages it receives and send the transformed

messages to the Queue found in the incoming message JMSReplyTo header.

@author Scott.Stark@jboss.org

@version $Revision:$

*/

public class TextMDB implements MessageDrivenBean, MessageListener

{

private MessageDrivenContext ctx = null;

private QueueConnection conn;

private QueueSession session;

public TextMDB()

{

System.out.println("TextMDB.ctor, this="+hashCode());

}

public void setMessageDrivenContext(MessageDrivenContext ctx)

{

this.ctx = ctx;

System.out.println("TextMDB.setMessageDrivenContext, this="+hashCode());

}

public void ejbCreate()

{

System.out.println("TextMDB.ejbCreate, this="+hashCode());

try

{

setupPTP();

}

catch(Exception e)

{

throw new EJBException("Failed to init TextMDB", e);

}

}

public void ejbRemove()

{

System.out.println("TextMDB.ejbRemove, this="+hashCode());

ctx = null;

try

{

if( session != null )

session.close();

if( conn != null )

conn.close();

}

catch(JMSException e)

{

e.printStackTrace();

}

}

public void onMessage(Message msg)

{

System.out.println("TextMDB.onMessage, this="+hashCode());

try

{

TextMessage tm = (TextMessage) msg;

String text = tm.getText() + "processed by: "+hashCode();

Queue dest = (Queue) msg.getJMSReplyTo();

sendReply(text, dest);

}

catch(Throwable t)

{

t.printStackTrace();

}

}

private void setupPTP()

throws JMSException, NamingException

{

InitialContext iniCtx = new InitialContext();

Object tmp = iniCtx.lookup("java:comp/env/jms/QCF");

QueueConnectionFactory qcf = (QueueConnectionFactory) tmp;

conn = qcf.createQueueConnection();

session = conn.createQueueSession(false,

QueueSession.AUTO_ACKNOWLEDGE);

conn.start();

}

private void sendReply(String text, Queue dest)

throws JMSException

{

System.out.println("TextMDB.sendReply, this="+hashCode()

+", dest="+dest);

QueueSender sender = session.createSender(dest);

TextMessage tm = session.createTextMessage(text);

sender.send(tm);

sender.close();

}

}

The MDB ejb-jar.xml and jboss.xml deployment descriptors are shown in See The MDB ejb-jar.xml and jboss.xml descriptors..

The MDB ejb-jar.xml and jboss.xml descriptors

// The ejb-jar.xml descriptor

<?xml version="1.0"?>

<!DOCTYPE ejb-jar

PUBLIC "-//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 2.0//EN"

"http://java.sun.com/dtd/ejb-jar_2_0.dtd"

>

<ejb-jar>

<enterprise-beans>

<message-driven>

<ejb-name>TextMDB</ejb-name>

<ejb-class>org.jboss.chap6.ex2.TextMDB</ejb-class>

<transaction-type>Container</transaction-type>

<acknowledge-mode>AUTO_ACKNOWLEDGE</acknowledge-mode>

<message-driven-destination>

<destination-type>javax.jms.Queue</destination-type>

</message-driven-destination>

<res-ref-name>jms/QCF</res-ref-name> <resource-ref>

<res-type>javax.jms.QueueConnectionFactory</res-type>

<res-auth>Container</res-auth>

</resource-ref>

</message-driven>

</enterprise-beans>

</ejb-jar>

// The jboss.xml descriptor

<?xml version="1.0"?>

<jboss>

<enterprise-beans>

<message-driven>

<ejb-name>TextMDB</ejb-name>

<destination-jndi-name>queue/B</destination-jndi-name>

<resource-ref>

<res-ref-name>jms/QCF</res-ref-name>

<jndi-name>ConnectionFactory</jndi-name>

</resource-ref>

</message-driven>

</enterprise-beans>

</jboss>

See A JMS client that interacts with the TextMDB. shows a variation of the P2P client that sends several messages to the "queue/B" destination and asynchronously receives the messages as modified by TextMDB from Queue A.

A JMS client that interacts with the TextMDB

package org.jboss.chap6.ex2;

import javax.jms.JMSException;

import javax.jms.Message;

import javax.jms.MessageListener;

import javax.jms.Queue;

import javax.jms.QueueConnection;

import javax.jms.QueueConnectionFactory;

import javax.jms.QueueReceiver;

import javax.jms.QueueSender;

import javax.jms.QueueSession;

import javax.jms.TextMessage;

import javax.naming.InitialContext;

import javax.naming.NamingException;

import EDU.oswego.cs.dl.util.concurrent.CountDown;

/** A complete JMS client example program that sends N

TextMessages to a Queue B and asynchronously receives the

messages as modified by TextMDB from Queue A.

@author Scott.Stark@jboss.org

@version $Revision:$

*/

public class SendRecvClient

{

static final int N = 10;

static CountDown done = new CountDown(N);

QueueConnection conn;

QueueSession session;

Queue queA;

Queue queB;

public static class ExListener implements MessageListener

{

public void onMessage(Message msg)

{

done.release();

TextMessage tm = (TextMessage) msg;

try

{

System.out.println("onMessage, recv text="+tm.getText());

}

catch(Throwable t)

{

t.printStackTrace();

}

}

}

public void setupPTP()

throws JMSException, NamingException

{

InitialContext iniCtx = new InitialContext();

Object tmp = iniCtx.lookup("ConnectionFactory");

QueueConnectionFactory qcf = (QueueConnectionFactory) tmp;

conn = qcf.createQueueConnection();

queA = (Queue) iniCtx.lookup("queue/A");

queB = (Queue) iniCtx.lookup("queue/B");

session = conn.createQueueSession(false,

QueueSession.AUTO_ACKNOWLEDGE);

conn.start();

}

public void sendRecvAsync(String textBase)

throws JMSException, NamingException, InterruptedException

{

System.out.println("Begin sendRecvAsync");

// Setup the PTP connection, session

setupPTP();

// Set the async listener for queA

QueueReceiver recv = session.createReceiver(queA);

recv.setMessageListener(new ExListener());

// Send a few text msgs to queB

QueueSender send = session.createSender(queB);

for(int m = 0; m < 10; m ++)

{

TextMessage tm = session.createTextMessage(textBase+"#"+m);

tm.setJMSReplyTo(queA);

send.send(tm);

System.out.println("sendRecvAsync, sent text="+tm.getText());

}

System.out.println("End sendRecvAsync");

}

public void stop() throws JMSException

{

conn.stop();

session.close();

conn.close();

}

public static void main(String args[]) throws Exception

{

System.out.println("Begin SendRecvClient,now="+System.currentTimeMillis());

SendRecvClient client = new SendRecvClient();

client.sendRecvAsync("A text msg");

client.done.acquire();

client.stop();

System.exit(0);

System.out.println("End SendRecvClient");

}

}

Run the client as follows:

[nr@toki examples]$ ant -Dchap=chap6 -Dex=2 run-example

Buildfile: build.xml

...

run-example2:

[copy] Copying 1 file to G:\JBoss\jboss-3.2.1\server\default\deploy

[echo] Waiting 5 seconds for deploy...

[java] Begin SendRecvClient, now=1056767530834

[java] Begin sendRecvAsync

[java] sendRecvAsync, sent text=A text msg#0

[java] sendRecvAsync, sent text=A text msg#1

[java] sendRecvAsync, sent text=A text msg#2

[java] sendRecvAsync, sent text=A text msg#3

[java] sendRecvAsync, sent text=A text msg#4

[java] sendRecvAsync, sent text=A text msg#5

[java] sendRecvAsync, sent text=A text msg#6

[java] sendRecvAsync, sent text=A text msg#7

[java] sendRecvAsync, sent text=A text msg#8

[java] sendRecvAsync, sent text=A text msg#9

[java] End sendRecvAsync

[java] onMessage, recv text=A text msg#2processed by: 23715584

[java] onMessage, recv text=A text msg#6processed by: 322649

[java] onMessage, recv text=A text msg#1processed by: 27534070

[java] onMessage, recv text=A text msg#3processed by: 23966866

[java] onMessage, recv text=A text msg#0processed by: 28532430

[java] onMessage, recv text=A text msg#4processed by: 1734943

[java] onMessage, recv text=A text msg#9processed by: 24814248

[java] onMessage, recv text=A text msg#7processed by: 21845470

[java] onMessage, recv text=A text msg#8processed by: 17243666

[java] onMessage, recv text=A text msg#5processed by: 403211

 

BUILD SUCCESSFUL

Total time: 9 seconds

The corresponding JBoss server console output is:

19:32:07,209 INFO [MainDeployer] Starting deployment of package: file:/G:/JBoss/jboss-3.2.1/server/default/deploy/chap6

-ex2.jar

19:32:07,760 INFO [EjbModule] Creating

19:32:07,770 INFO [EjbModule] Deploying TextMDB

19:32:07,810 INFO [MessageDrivenContainer] Creating

19:32:07,810 INFO [MessageDrivenInstancePool] Creating

19:32:07,810 INFO [MessageDrivenInstancePool] Created

19:32:07,810 INFO [JMSContainerInvoker] Creating

19:32:07,820 INFO [JMSContainerInvoker] Created

19:32:07,820 INFO [MessageDrivenContainer] Created

19:32:07,820 INFO [EjbModule] Created

19:32:07,820 INFO [EjbModule] Starting

19:32:07,820 INFO [MessageDrivenContainer] Starting

19:32:07,830 INFO [JMSContainerInvoker] Starting

19:32:07,830 INFO [DLQHandler] Creating

19:32:07,890 INFO [DLQHandler] Created

19:32:08,191 WARN [SecurityManager] No SecurityMetadadata was available for B adding default security conf

19:32:08,201 INFO [DLQHandler] Starting

19:32:08,201 INFO [DLQHandler] Started

19:32:08,201 INFO [JMSContainerInvoker] Started

19:32:08,201 INFO [MessageDrivenInstancePool] Starting

19:32:08,211 INFO [MessageDrivenInstancePool] Started

19:32:08,211 INFO [MessageDrivenContainer] Started

19:32:08,211 INFO [EjbModule] Started

19:32:08,211 INFO [EJBDeployer] Deployed: file:/G:/JBoss/jboss-3.2.1/server/default/deploy/chap6-ex2.jar

19:32:08,241 INFO [MainDeployer] Deployed package: file:/G:/JBoss/jboss-3.2.1/server/default/deploy/chap6-ex2.jar

19:32:12,136 WARN [SecurityManager] No SecurityMetadadata was available for A adding default security conf

19:32:12,206 INFO [TextMDB] TextMDB.ctor, this=28532430

19:32:12,216 INFO [TextMDB] TextMDB.ctor, this=27534070

19:32:12,307 INFO [TextMDB] TextMDB.ctor, this=23966866

19:32:12,307 INFO [TextMDB] TextMDB.ctor, this=23715584

19:32:12,307 INFO [TextMDB] TextMDB.setMessageDrivenContext, this=27534070

19:32:12,307 INFO [TextMDB] TextMDB.setMessageDrivenContext, this=28532430

19:32:12,347 INFO [TextMDB] TextMDB.ejbCreate, this=27534070

19:32:12,347 INFO [TextMDB] TextMDB.ejbCreate, this=28532430

19:32:12,347 INFO [TextMDB] TextMDB.setMessageDrivenContext, this=23966866

19:32:12,357 INFO [TextMDB] TextMDB.ejbCreate, this=23966866

19:32:12,377 INFO [TextMDB] TextMDB.setMessageDrivenContext, this=23715584

19:32:12,377 INFO [TextMDB] TextMDB.ejbCreate, this=23715584

19:32:12,387 INFO [TextMDB] TextMDB.ctor, this=1734943

19:32:12,387 INFO [TextMDB] TextMDB.setMessageDrivenContext, this=1734943

19:32:12,387 INFO [TextMDB] TextMDB.ejbCreate, this=1734943

19:32:12,387 INFO [TextMDB] TextMDB.ctor, this=403211

19:32:12,387 INFO [TextMDB] TextMDB.setMessageDrivenContext, this=403211

19:32:12,397 INFO [TextMDB] TextMDB.ejbCreate, this=403211

19:32:12,397 INFO [TextMDB] TextMDB.ctor, this=322649

19:32:12,397 INFO [TextMDB] TextMDB.setMessageDrivenContext, this=322649

19:32:12,397 INFO [TextMDB] TextMDB.ejbCreate, this=322649

19:32:12,437 INFO [TextMDB] TextMDB.ctor, this=21845470

19:32:12,437 INFO [TextMDB] TextMDB.ctor, this=17243666

19:32:12,467 INFO [TextMDB] TextMDB.ctor, this=24814248

19:32:12,467 INFO [TextMDB] TextMDB.setMessageDrivenContext, this=21845470

19:32:12,467 INFO [TextMDB] TextMDB.setMessageDrivenContext, this=24814248

19:32:12,467 INFO [TextMDB] TextMDB.ejbCreate, this=24814248

19:32:12,477 INFO [TextMDB] TextMDB.ejbCreate, this=21845470

19:32:12,487 INFO [TextMDB] TextMDB.setMessageDrivenContext, this=17243666

19:32:12,487 INFO [TextMDB] TextMDB.ejbCreate, this=17243666

19:32:12,537 INFO [TextMDB] TextMDB.onMessage, this=28532430

19:32:12,537 INFO [TextMDB] TextMDB.sendReply, this=28532430, dest=QUEUE.A

19:32:12,537 INFO [TextMDB] TextMDB.onMessage, this=23715584

19:32:12,537 INFO [TextMDB] TextMDB.onMessage, this=23966866

19:32:12,537 INFO [TextMDB] TextMDB.onMessage, this=322649

19:32:12,547 INFO [TextMDB] TextMDB.onMessage, this=27534070

19:32:12,547 INFO [TextMDB] TextMDB.sendReply, this=23715584, dest=QUEUE.A

19:32:12,547 INFO [TextMDB] TextMDB.sendReply, this=23966866, dest=QUEUE.A

19:32:12,547 INFO [TextMDB] TextMDB.sendReply, this=322649, dest=QUEUE.A

19:32:12,567 INFO [TextMDB] TextMDB.sendReply, this=27534070, dest=QUEUE.A

19:32:12,647 INFO [TextMDB] TextMDB.onMessage, this=24814248

19:32:12,647 INFO [TextMDB] TextMDB.sendReply, this=24814248, dest=QUEUE.A

19:32:12,667 INFO [TextMDB] TextMDB.onMessage, this=1734943

19:32:12,677 INFO [TextMDB] TextMDB.sendReply, this=1734943, dest=QUEUE.A

19:32:12,687 INFO [TextMDB] TextMDB.onMessage, this=21845470

19:32:12,687 INFO [TextMDB] TextMDB.sendReply, this=21845470, dest=QUEUE.A

19:32:12,687 INFO [TextMDB] TextMDB.onMessage, this=17243666

19:32:12,697 INFO [TextMDB] TextMDB.onMessage, this=403211

19:32:12,727 INFO [TextMDB] TextMDB.sendReply, this=17243666, dest=QUEUE.A

19:32:12,727 INFO [TextMDB] TextMDB.sendReply, this=403211, dest=QUEUE.A

Items of note in this example include:

  • The JMS client has no explicit knowledge that it is dealing with an MDB. The client simply uses the standard JMS APIs to send messages to a queue and receive messages from another queue.
  • The MDB declares whether it will listen to a queue or topic in the ejb-jar.xml descriptor. The name of the queue or topic must be specified using a jboss.xml descriptor. In this example the MDB also sends messages to a JMS queue. MDBs may act as queue senders or topic publishers within their onMessage callback.
  • The messages received by the client include a "processed by: NNN" suffix, where NNN is the hashCode value of the MDB instance that processed the message. This shows that many MDBs may actively process messages posted to a destination. Concurrent processing is one of the benefits of MDBs.

JBoss Messaging Overview

Adrian Brock, Scott Stark

JBossMQ is composed of several services working together to provide JMS API level services to client applications. The services that make up the JBossMQ JMS implementation are introduced in this section.

Invocation Layer

The Invocation Layer (IL) services are responsible for handling the communication protocols that clients use to send and receive messages. JBossMQ can support running different types of Invocation Layers concurrently. All Invocation Layers support bidirectional communication which allows clients to send and receive messages concurrently. ILs only handle the transport details of messaging. They delegate messages to the JMS server JMX gateway service known as the invoker. This is similar to how the detached invokers expose the EJB container via different transports.

Each IL service binds a JMS connection factory to a specific location in the JNDI tree. Clients choose the protocol they wish to use by the JNDI location used to obtain the JMS connection factory. JBossMQ currently has six different invocation layers, and they are introduced in the following sections.

RMI IL (deprecated)

The first IL that was developed was based on Java's Remote Method Invocation (RMI). This is a robust IL since it is based on standard RMI technology, but it has a high overhead compared to other ILs and will likely be dropped in future releases.

NOTE: This IL will try to establish a TCP/IP socket from the server to the client. Therefore, clients that sit behind firewalls or have security restrictions prohibiting the use of SeverSockets should not use this IL.

OIL IL (deprecated)

The next IL that was developed was the "Optimized" IL (OIL). The OIL uses a custom TCP/IP protocol and serialization protocol that has very low overhead. This was the recommended socket based protocol until the addition of the UIL2 protocol.

NOTE: This IL will try to establish a TCP/IP socket from the server to the client. Therefore, clients that sit behind firewalls or have security restrictions prohibiting the use of SeverSockets should not use this IL.

UIL IL (deprecated)

The Unified Invocation Layer (UIL) was developed to allow clients that cannot have a connection created from the server back to the client due to firewall or other restrictions. It is almost identical to the OIL protocol except that a multiplexing layer is used to provide the bidirectional communication. The multiplexing layer creates two virtual sockets over one physical socket. This IL is slower than the OIL due to the higher overhead incurred by the multiplexing layer. This invocation layer is now deprecated in favor of UIL2.

UIL2 IL

The Unified version 2 Invocation Layer (UIL2) is a variation of the UIL protocol that also uses a single socket between the client and server. However, unlike all other socket based invocation layers like RMI, UIL and OIL which use a blocking round-trip message at the socket level, the UIL2 protocol uses true asynchronous send and receive messaging at the transport level. This provides for improved throughput and utilization and as such, it is the preferred socket invocation layer.

JVM IL

The Java Virtual Machine (JVM) Invocation Layer was developed to cut out the TCP/IP overhead when the JMS client is running in the same JVM as the server. This IL uses direct method calls for the server to service the client requests. This increases efficiency since no sockets are created and there is no need for the associated worker threads. This is the IL that should be used by Message Driven Beans (MDB) or any other component that runs in the same virtual machine as the server such as servlets, MBeans, or EJBs.

HTTP IL

The HTTP Invocation Layer (HTTPIL) allows for accessing the JBossMQ service over the HTTP or HTTPS protocols. This IL relies on the servlet deployed in the deploy/jms/jbossmq-httpil.sar to handle the http traffic. This IL is useful for access to JMS through a firewall when the only port allowed requires HTTP.

Security Manager

The JBossMQ SecurityManager is the service that enforces an access control list to guard access to your destinations. This subsystem works closely with the StateManager service.

Destination Manager

The DestinationManager can be thought as being the central service in JBossMQ. It keeps track of all the destinations that have been created on the server. It also keeps track of the other key services such as the MessageCache, StateManager, and PersistenceManager.

Message Cache

Messages created in the server are passed to the MessageCache for memory management. JVM memory usage goes up as messages are added to a destination that does not have any receivers. These messages are held in the main memory until the receiver picks them up. If the MessageCache notices that the JVM memory usage starts passing the defined limits, the MessageCache starts moving those messages from memory to persistent storage on disk. The MessageCache uses a least recently used (LRU) algorithm to determine which messages should go to disk.

State Manager

The StateManager (SM) is in charge of keeping track of who is allowed to log into the server and what their durable subscriptions are.

Persistence Manager

The PersistenceManager (PM) is used by a destination to store messages marked as being persistent. JBossMQ has several different implementations of the persistent manager, but only one can be enabled per server instance. You should enable the persistence manager that best matches your requirements.

File PM

The File PM is a robust persistence manager that comes with JBossMQ. It creates separate directories for each of the destination created on the server, and stores each persistent message as a separate file in the appropriate directory. It has poor performance characteristics since it is frequently opening and closing files.

Rolling Logged PM

The Rolling Logged PM is also a file based persistence manager that has better performance than the File PM because it stores multiple messages in one file, reducing the overhead of opening/closing multiple files. This is a very fast PM but it is less transactionally reliable than the File PM due to its use of the FileOutputStream.flush() method call. On some operating systems/JVMs the FileOutputStream.flush() method does not guarantee that the data has been written to disk by the time the call returns.

JDBC2 PM

The JDBC2 PM is the second version of the original JDBC PM in JBossMQ 2.4.x. It has been substantially simplified and improved. This PM allows you to store persistent messages to a relational database using JDBC. The performance of this PM is directly related to the performance that can be obtained from the database. This PM has a very low memory overhead compared to the other persistence managers. Furthermore it is also highly integrated with the MessageCache to provide efficient persistence on a system that has a very active MessageCache.

Destinations

A destination is the object on the JBossMQ server that clients use to send and receive messages. There are two types of destination objects, Queues and Topics. References to the destinations created by JBossMQ are stored in JNDI.

Queues

Clients that are in the Point-to-Point paradigm typically use Queues. They expect that message sent to a Queue will be receive by only one other client once and only once. If multiple clients are receiving messages from a single queue, the messages will be load balanced across the receivers. Queue objects, by default, will be stored under the JNDI "queue/" sub context.

Topics

Topics are used in the Publish-Subscribe paradigm. When a client publishes a message to a topic, he expects that a copy of the message will be delivered to each client that has subscribed to the topic. Topic messages are delivered in the same manner a television show is delivered. Unless you have the TV on and are watching the show, you will miss it. Similarly, if the client is not up, running and receiving messages from the topics, it will miss messages published to the topic. To get around this problem of missing messages, clients can start a durable subscription. This is like having a VCR record a show you cannot watch at its scheduled time so that you can see what you missed when you turn your TV back on.

JBoss Messaging Configuration and MBeans

Adrian Brock, Scott Stark

This section defines the MBean services that correspond to the components introduced in the previous section along with their MBean attributes. The configuration and service files that make up the JBossMQ system include:

  • conf/jbossmq-state.xml: the configuration file read by the org.jboss.mq.sm.file.DynamicStateManager MBean. This is the default security store for the JMS valid username/passwords used to authenticate connections, as well as the active durable topic subscriptions.
  • deploy/jms/jbossmq-destinations-service.xml: This service describes defines default JMS queue and topic destination configurations used by the testsuite unit tests. You can add/remove destinations to this file, or deploy another *-service.xml descriptor with the destination configurations.
  • deploy/jms/jbossmq-service.xml: This service descriptor configures the core JBossMQ MBeans like the Invoker, SecurityManager, DynamicStateManager, and core interceptor stack. It also defines the MDB default dead letter queue "DLQ".
  • deploy/jms/jms-ra.rar: This is a JCA resource adaptor for JMS providers.
  • deploy/jms/jms-ds.xml: This is a JCA connection factory and JMS provider MDB integration services configuration which sets JBossMQ as the JMS provider.
  • deploy/jms/hsqldb-jdbc2-service.xml: This service descriptor configures the DestinationManager, MessageCache, and jdbc2 PersistenceManager for hsqldb.
  • deploy/jms/jvm-il-service.xml: This service descriptor configures the JVMServerILService which provides the JVM IL transport.
  • deploy/jms/oil-service.xml: This service descriptor configures the OILServerILService which provides the OIL transport. The queue and topic connection factory for this IL is bound under the JNDI name "ConnectionFactory".
  • deploy/jms/oil2-service.xml: This is an experimental version OIL transport that should not be used. Remove this descriptor as it will be dropped in the next release.
  • deploy/jms/rmi-il-service.xml: This service descriptor configures the RMIServerILService which provides the RMI IL. The queue and topic connection factory for this IL is bound under the name "RMIConnectionFactory".
  • deploy/jms/uil2-service.xml: This service descriptor configures the UILServerILService which provides the UIL2 transport. The queue and topic connection factory for this IL is bound under the name "UIL2ConnectionFactory" as well as "UILConnectionFactory" to replace the deprecated version 1 UIL service.

We will discuss the associated MBeans in the following subsections.

org.jboss.mq.il.jvm.JVMServerILService

The org.jboss.mq.il.jvm.JVMServerILService MBean is used to configure the JVM IL. The configurable attributes are as follows:

  • Invoker: This attribute specifies JMX ObjectName of the JMS entry point service that is used to pass incoming requests to the JMS server. This attribute should be setup via a <depends optional-attribute-name="Invoker"> tag. This is not something you would typically change from the "jboss.mq:service=Invoker" setting unless you change the entry point service.
  • ConnectionFactoryJNDIRef: The JNDI location that this IL will bind a ConnectionFactory setup to use this IL.
  • XAConnectionFactoryJNDIRef: The JNDI location that this IL will bind a XAConnectionFactory setup to use this IL.
  • PingPeriod: How often, in milliseconds, the client should send a ping message to the server to validate that the connection is still valid. If this is set to zero, then no ping message will be sent. Since it is impossible for JVM IL connection to go bad, it is recommended that you keep this set to "0".

org.jboss.mq.il.rmi.RMIServerILService (deprecated)

The org.jboss.mq.il.rmi.RMIServerILService is used to configure the RMI IL. The configurable attributes are as follows:

  • Invoker: This attribute specifies JMX ObjectName of the JMS entry point service that is used to pass incoming requests to the JMS server. This attribute should be setup via a <depends optional-attribute-name="Invoker"> tag. This is not something you would typically change from the "jboss.mq:service=Invoker" setting unless you change the entry point service.
  • ConnectionFactoryJNDIRef: The JNDI location that this IL will bind a ConnectionFactory setup to use this IL.
  • XAConnectionFactoryJNDIRef: The JNDI location that this IL will bind a XAConnectionFactory setup to use this IL.
  • PingPeriod: How often, in milliseconds, the client should send a ping message to the server to validate that the connection is still valid. If this is set to zero, then no ping message will be sent.

org.jboss.mq.il.oil.OILServerILService (deprecated)

The org.jboss.mq.il.oil.OILServerILService is used to configure the OIL IL. The configurable attributes are as follows:

  • Invoker: This attribute specifies JMX ObjectName of the JMS entry point service that is used to pass incoming requests to the JMS server. This attribute should be setup via a <depends optional-attribute-name="Invoker"> tag. This is not something you would typically change from the "jboss.mq:service=Invoker" setting unless you change the entry point service.
  • ConnectionFactoryJNDIRef: The JNDI location that this IL will bind a ConnectionFactory setup to use this IL.
  • XAConnectionFactoryJNDIRef: The JNDI location that this IL will bind a XAConnectionFactory setup to use this IL.
  • PingPeriod: How often, in milliseconds, the client should send a ping message to the server to validate that the connection is still valid. If this is set to zero, then no ping message will be sent.
  • ReadTimeout: The period in milliseconds is passed onto as the SoTimeout value of the UIL2 socket. This allows detection of dead sockets that are not responsive and are not capable of receiving ping messages. Note that this setting should be longer in duration than the PingPeriod setting.
  • ServerBindPort: The protocol listening port for this IL. If not specified default is 0, which means that a random port will be chosen.
  • BindAddress: The specific address this IL listens on. This can be used on a multi-homed host for a java.net.ServerSocket that will only accept connection requests on one of its addresses.
  • EnableTcpNoDelay: If set to true, then the TcpNoDelay option is enabled. This improves request response times since TCP/IP packets are sent a soon as the request is flushed. Otherwise request packets may be buffered by the operating system to create larger IP packets.
  • ServerSocketFactory: The the javax.net.ServerSocketFactory implementation class name to use to create the service java.net.ServerSocket . If not specified the default factory will be obtained from javax.net.ServerSocketFactory.getDefault() .
  • ClientSocketFactory: The javax.net.SocketFactory implementation class name to use on the client. If not specified the default factory will be obtained from javax.net.SocketFactory.getDefault() .
  • SecurityDomain: Specify the security domain name to use with JBoss SSL aware socket factories. This is the JNDI name of the security manager implementation as described for the security-domain element of the jboss.xml and jboss-web.xml descriptors in Enabling Declarative Security in JBoss Revisited.

org.jboss.mq.il.uil.UILServerILService (deprecated)

The org.jboss.mq.il.uil.UILServerILService is used to configure the UIL IL. Note that this service has been removed from the default distribution as of 3.2.2, but an example configuration file can be found in the docs/examples/jca directory.

The configurable attributes of the UILServerILService are as follows:

  • Invoker: This attribute specifies JMX ObjectName of the JMS entry point service that is used to pass incoming requests to the JMS server. This attribute should be setup via a <depends optional-attribute-name="Invoker"> tag. This is not something you would typically change from the "jboss.mq:service=Invoker" setting unless you change the entry point service.
  • ConnectionFactoryJNDIRef: The JNDI location that this IL will bind a ConnectionFactory setup to use this IL.
  • XAConnectionFactoryJNDIRef: The JNDI location that this IL will bind a XAConnectionFactory setup to use this IL.
  • PingPeriod: How often, in milliseconds, the client should send a ping message to the server to validate that the connection is still valid. If this is set to zero, then no ping message will be sent.
  • ServerBindPort: The protocol listening port for this IL. If not specified default is 0, which means that a random port will be chosen.
  • BindAddress: The specific address this IL listens on. This can be used on a multi-homed host for a java.net.ServerSocket that will only accept connection requests on one of its addresses.
  • EnableTcpNoDelay: If set to true, then the TcpNoDelay option is enabled. This improves request response times since TCP/IP packets are sent a soon as the request is flushed. Otherwise request packets may be buffered by the operating system to create larger IP packets.
  • ServerSocketFactory: The the javax.net.ServerSocketFactory implementation class name to use to create the service java.net.ServerSocket . If not specified the default factory will be obtained from javax.net.ServerSocketFactory.getDefault() .
  • ClientSocketFactory: The javax.net.SocketFactory implementation class name to use on the client. If not specified the default factory will be obtained from javax.net.SocketFactory.getDefault().
  • SecurityDomain: Specify the security domain name to use with JBoss SSL aware socket factories. This is the JNDI name of the security manager implementation as described for the security-domain element of the jboss.xml and jboss-web.xml descriptors in Enabling Declarative Security in JBoss Revisited.

org.jboss.mq.il.uil2.UILServerILService

The org.jboss.mq.il.uil2.UILServerILService is used to configure the UIL2 IL. The configurable attributes are as follows:

  • Invoker: This attribute specifies JMX ObjectName of the JMS entry point service that is used to pass incoming requests to the JMS server. This attribute should be setup via a <depends optional-attribute-name="Invoker"> tag. This is not something you would typically change from the "jboss.mq:service=Invoker" setting unless you change the entry point service.
  • ConnectionFactoryJNDIRef: The JNDI location that this IL will bind a ConnectionFactory setup to use this IL.
  • XAConnectionFactoryJNDIRef: The JNDI location that this IL will bind a XAConnectionFactory setup to use this IL.
  • PingPeriod: How often, in milliseconds, the client should send a ping message to the server to validate that the connection is still valid. If this is set to zero, then no ping message will be sent.
  • ReadTimeout: The period in milliseconds is passed onto as the SoTimeout value of the UIL2 socket. This allows detection of dead sockets that are not responsive and are not capable of receiving ping messages. Note that this setting should be longer in duration than the PingPeriod setting.
  • BufferSize: The size in bytes used as the buffer over the basic socket streams. This corresponds to the java.io.BufferedOutputStream buffer size.
  • ChunkSize: The size in bytes between stream listener notifications. The UIL2 layer uses the org.jboss.util.stream.NotifyingBufferedOutputStream and NotifyingBufferedInputStream implementations that support the notion of a heartbeat that is triggered based on data read/written to the stream. Whenever ChunkSize bytes are read/written to a stream. This allows serves as a ping or keepalive notification when large reads or writes require a duration greater than the PingPeriod.
  • ServerBindPort: The protocol listening port for this IL. If not specified default is 0, which means that a random port will be chosen.
  • BindAddress: The specific address this IL listens on. This can be used on a multi-homed host for a java.net.ServerSocket that will only accept connection requests on one of its addresses.
  • EnableTcpNoDelay: If set to true, then the TcpNoDelay option is enabled. This improves request response times since TCP/IP packets are sent a soon as the request is flushed. Otherwise request packets may be buffered by the operating system to create larger IP packets.
  • ServerSocketFactory: The the javax.net.ServerSocketFactory implementation class name to use to create the service java.net.ServerSocket . If not specified the default factory will be obtained from javax.net.ServerSocketFactory.getDefault() .
ClientSocketFactory: The javax.net.SocketFactory implementation class name to use on the client. If not specified the default factory will be obtained from javax.net.SocketFactory.getDefault() .
  • SecurityDomain: Specify the security domain name to use with JBoss SSL aware socket factories. This is the JNDI name of the security manager implementation as described for the security-domain element of the jboss.xml and jboss-web.xml descriptors in Enabling Declarative Security in JBoss Revisited.

Configuring ILs for SSL

The UIL2 and OIL services support the use of SSL through custom socket factories that integrate JSSE using the security domain associated with the IL service. An example UIL2 service descriptor fragment that illustrates the use of the custom JBoss SSL socket factories is shown in See An example UIL2 config fragment for using SSL..

An example UIL2 config fragment for using SSL

<mbean code="org.jboss.mq.il.uil2.UILServerILService"

name="jboss.mq:service=InvocationLayer,type=HTTPSUIL2">

<depends optional-attribute-name="Invoker">jboss.mq:service=Invoker

</depends>

<attribute name="ConnectionFactoryJNDIRef">SSLConnectionFactory

</attribute>

<attribute name="XAConnectionFactoryJNDIRef">SSLXAConnectionFactory

</attribute>

...

<!-- SSL Socket Factories -->

<attribute name="ClientSocketFactory">

org.jboss.security.ssl.ClientSocketFactory

</attribute>

<attribute name="ServerSocketFactory">

org.jboss.security.ssl.DomainServerSocketFactory

</attribute>

<!-- Security domain - see below -->

<attribute name="SecurityDomain">java:/jaas/SSL</attribute>

</mbean>

 

<!-- Configures the keystore on the "SSL" security domain

This mbean is better placed in conf/jboss-service.xml where it

can be used by other services, but it will work from anywhere.

Use keytool from the sdk to create the keystore.

-->

<mbean code="org.jboss.security.plugins.JaasSecurityDomain"

name="jboss.security:service=JaasSecurityDomain,domain=SSL">

<!-- This must correlate with the java:/jaas/SSL above -->

<constructor>

<arg type="java.lang.String" value="SSL"/>

</constructor>

<!-- The location of the keystore resource: loads from the

classpath and the server conf dir is a good default -->

<attribute name="KeyStoreURL">resource:uil2.keystore</attribute>

<attribute name="KeyStorePass">changeme</attribute>

</mbean>

 

org.jboss.mq.il.http.HTTPServerILService

The org.jboss.mq.il.http.HTTPServerILService is used to manage the HTTP/S IL. This IL allows for the use of the JMS service over http or https connections. The relies on the servlet deployed in the deploy/jms/jbossmq-httpil.sar to handle the http traffic. The configurable attributes are as follows:

  • TimeOut: The default timeout in seconds that the client HTTP requests will wait for messages. This can be overridden on the client by setting the system property org.jboss.mq.il.http.timeout to the number of seconds.
  • RestInterval: The number of seconds the client will sleep after each request. The default is 0, but you can set this value in conjunction with the TimeOut value to implement a pure timed based polling mechanism. For example, you could simply do a short lived request by setting the TimeOut value to 0 and then setting the RestInterval to 60. This would cause the client to send a single non-blocking request to the server, return any messages if available, then sleep for 60 seconds, before issuing another request. Like the TimeOut value, this can be explicitly overridden on a given client by specifying the org.jboss.mq.il.http.restinterval with the number of seconds you wish to wait between requests.