Most JMS destinations (queues and topics) are created administratively and are treated as static resources, even though dynamic destinations (temporary queues and temporary topics) are supported in JMS. Using static queues to communicate between tiers of a client/server application creates barriers to scalability and maintainability. In this article, we will look at the benefits and drawbacks of using temporary destinations in an enterprise healthcare system. We will also look at design perspectives for using temporary queues as an alternative to static queues and explore some design strategies using synchronous requests and replies.
Temporary Destinations: An Overview
Temporary destinations are proposed as a lightweight alternative in a scalable system architecture that could be used as unique destinations for replies. Such destinations have a scope limited to the connection that created it, and are removed on the server side as soon as the connection is closed. Only a single well-known static queue is required for producers/senders to connect with consumers using temporary destinations. The JMS header field JMSReplyTo is always used in conjunction with temporary destinations.
Since the identity of the temporary destination is known only by the connection or session that created it, the consumer/receiver cannot know the destination name. The solution is to have the producer/sender send the name of its temporary destination as a header field (JMSReplyTo), as part of a message, sent to a known static queue listened to by the producer/sender.
Limitations of Temporary Destinations
There are a few limitations that must be recognized regarding temporary destinations:
- A temporary destination can only be consumed by the connection that created it.
- The life span of temporary destinations is only for the duration of the connection where they are created.
- When you close the connection that has a temporary destination, the destination is closed and its contents are lost.
- You cannot have durable subscriptions to a TemporaryTopic.
- Each temporary destination is unique and cannot be copied.
- Temporary destinations cannot be routed using an enterprise messaging service.
Static Destinations Versus Dynamic DestinationsFunctionally, static and dynamic destinations have contrasting attributes:
- Are created administratively from outside of the application as part of initial deployment
- Have well-known identities (resolved with JNDI) with both consumers and producers
- Can support concurrent processing by configuring multiple sessions
- Are intended for asynchronous messaging
- Message aging and resource allocation is specified as part of the administrative creation of the destination (not defined by JMS spec)
- Are dynamically created by the application itself
- Are created by a consumer and destroyed as soon as the session is closed
- Destination identity must be communicated in some other manner to producers
- Are typically used for synchronous messaging (one request/one reply paradigm), even though there is no limit to how many messages a temporary destination can hold
- The actual length of time a message is held by a queue and the consequences of resource overflow are not defined by JMS
Despite the limitations of temporary destinations, there are definite advantages to their use in real-time applications. In this section, we will examine a representative messaging application using JMS.
An enterprise healthcare system accepts updates to client information (such as adding a new member or deleting a member) from multiple interfaces (different providers or health care groups). Responses to these update requests must be sent synchronously to ensure that proper business validation or other transactional security is maintained. This requires the application to support multiple clients who may send thousands of messages, with each client waiting for a reply to each message.
There are two ways you can design the solution:
1. Using only static queues for both request and response
2. Using a combination of static and dynamic queues
In the first approach, if you have a single static queue for the requests and a single static queue for responses for multiple clients, you could employ some selection logic using Message Selectors (JMS Specification section 126.96.36.199) to filter the messages from the same static queue, as depicted in Figure 1.
|Figure 1. Single static queue for multiple clients model|
|Figure 2. Pair of static queues per client model|
In the second approach, there would be a single static queue for all client requests. Each client initially creates a temporary queue for receiving responses (TQa, TQb, and TQc). The client sends the name of its temporary queue as a part of each request to the static queue, as depicted in Figure 3.
|Figure 3. Temporary queues for multiple clients model|
In this configuration, temporary destinations can be viewed as analogous to callbacks in synchronous processing, i.e., when the callee wants to reach out to the caller in a decoupled way, without the caller and callee having to know about each other in advance.
A Suggested Architecture for the Server Side Using Temporary Queues
For this example, we will look at using a message-driven bean (or MDB) as a message listener, and a session facade that coordinates with one or more business objects (stateful or stateless session beans), which generates the response message and sends the outbound message (reply) to the temporary destination as shown in Figure 4.
|Figure 4. Suggested design pattern class diagram|
The MDB will initially register itself with a static destination through an administrative task. Upon receiving a message, the MDB passes the message to a session facade that picks up the identity of the temporary destination from the value of JMSReplyTo in the message header. It then interacts with other business object(s) to perform the requested workflow, as shown in Figure 5. MDB will then use OutboundProcessor (stateful or stateless session bean) to send the message out to the temporary destination.
|Figure 5. Suggested design pattern sequence diagram|
Some Considerations for the Client Side When Using Temporary Queues
The session should be closed as soon as processing is completed so that TemporaryQueues will be deleted on the server side. While the JMS session doesn't support concurrency, this can be implemented with connection objects. A session is a single-threaded context to produce and consume the temporary messages. According to the JMS specification:
A session supports transactions and it is difficult to implement transactions that are multithreaded; a session should not be used concurrently by multiple threads.
Even though you are not using a transacted session, you are still required to coordinate individual sessions to implement concurrent processing. The only method in the session object method that can be concurrently called is close(). Threads are good candidates for blocking calls since they could be executed concurrently.
There is no need to close the consumers (QueueReceiver) of a closed session. As soon as the connection that created the temporary queue is closed, all the constituents of the closed connection and session are closed. Relying on garbage collection to eventually reclaim these resources may not be timely enough, especially in the case of JMS resources that are created outside of JVM.
The following code excerpt shows how to create Temporary Destinations. We use common interfaces like Session as opposed to specific domain constructs like QueueSession or TopicSession. Sun encourages using common interfaces without programming specific to a single message domain so that the JMS application is domain-independent.
"blue">/** Get the Initial Context Factory */</font>
Hashtable env = new Hashtable();
String conFactoryClass = "VendorSpecificCFC";
String url = "MyServer:port";
env.put(Context.SECURITY_PRINCIPAL, "userid" );
Context = new InitialContext(env);
"blue">/**Access the resources by looking up the JNDI
/**QueueConnectionFactory is a Factory for QueueConnection
javax.jms.ConnectionFactory qcf =
javax.jms.Connection qConnection =
javax.jms.Queue myQueue =
javax.jms.Topic myTopic =
<font color="blue">/**TopicConnectionFactory is a Factory for
javax.jms.ConnectionFactory tcf =
javax.jms.TopicConnection tConnection =
<font color="blue">/**Create a Session using Connection
javax.jms.Session qSession =
javax.jms.Session tSession =
"blue">/**Create the Temporary Destinations using the Session
javax.jms.Queue replyQueue = qSession.createTemporaryQueue();
javax.jms.Topic replyTopic = tSession.createTemporaryTopic()