The
MOM Player: JAVA MESSAGING SERVICE
Java
Message Service (JMS) defines a standard API that
allows Java developers to easily build enterprise
applications. A overview of this technology
As
opposed to regular request/reply based communication
in traditional client/server systems, messaging
provides more flexibility and scalability
Internet-based
software solutions require a fast, reliable and
scalable link between broad variety of newly developed
legacy applications and data sources. Communication
in this loosely coupled environment is made possible
by a specific type of middleware called MOM. The
process of integrating an application with other
applications which are not meant for Internet is
a daunting task.
Messaging for large organizations has been via EDI
or proprietary messaging middleware products like
IBM MQ Series and TIBCO RV. Both are difficult to
configure and maintain with high overheads.
Asynchronous messaging is a proven communication
model for developing large-scale, distributed enterprise
applications. As opposed to regular request/reply
based communication in traditional client/server
systems, messaging provides more flexibility and
scalability because senders and receivers of messages
are de-coupled and are no longer required to execute
in lockstep.
The Java Message Service (JMS) defines a standard
API that allows Java developers to easily build
enterprise applications. JMS is important in its
own right because it provides a simplified and common
way for Java clients to access message-oriented
middleware. More importantly, JMS is tightly integrated
into J2EE and is the messaging standard for Enterprise
Java Beans (EJB).
From an application design perspective, message-based
application design can be categorized into three
basic domains:
1. Point-to-point messaging: Point-to-point design
is a many-to-one paradigm, where many clients can
send messages to a single client. The same client
can be a sender, receiver, or both sender and receiver.
The working of this communication in JMS is based
on the concept of a "queue." Senders put
messages into a queue and receivers take messages
out. The queue has optional persistence built in
to save the messages. The working can be compared
to an e-mail. Many people can send e-mails to your
address and you retrieve them one after the other
from the mailbox. The mail server stores the e-mails
until they are retrieved.
2. Publish-subscribe messaging: Publish-subscribe
messaging is a many-to-many paradigm. It is the
design used when we want multiple applications/clients
to receive the same message or when a group of applications
want to notify each other. It is like multiple listeners
attached to a component. In a JMS message, publishers
send messages to a topic, and subscribers receive
messages sent to the topic. There can be multiple
senders and multiple receivers. The application
can again be both a sender and a receiver.
3. Request-reply messaging: Request-reply messaging
refers to the design wherein an application sends
a message and expects a reply to that message from
the receiver. This is a feature rather than a separate
design because a point-to-point or publish-subscribe
design could also be request-reply based.
JMS
doesn't explicitly support request-reply messaging,
but allows the use of a "reply to" field
in the message. A program can reply to a message
by checking this field. This response is optional
and left for the client to decide.
Another way of doing this is to create a new queue
say, 'acknowledge-queue' to which the client will
send an acknowledgement. The requester can retrieve
the acknowledgements from this queue.
What is Java Messaging Service API?
The Java Message Service is an API defined by Sun
Microsystems. The purpose of JMS is to provide a
unified Java-based API to all messaging middleware
systems. Developers that use JMS are thus able to
write client applications without too much concern
about the ultimate message middleware that the clients
are going to use. Also, the message system can be
replaced with no or few client modifications. JMS
follows a Hub and Spoke Topology. In a Hub and Spoke
architecture all the applications are connected
to a central process called a message server. The
message server handles all communication between
connected applications called clients. The message
server is responsible for routing messages correctly,
authenticating and authorizing
user access and guaranteeing the delivery of the
messages. Each application
client can be a sender, a receiver or both.
JMS
supports a point-to-point model and a publish/subscribe
model, and it defines a number of message types
that publishers and subscribers can exchange. Messages
support properties that define how they should be
treated by the message system. Subscribes can filter
messages using an SQL grammar. Clients can be transient
or durable and messages can be sent or received
in the context of a transaction.
The JMS is a client API. It only defines how a Java
client accesses the messaging capabilities of an
enterprise messaging system. Other important aspects
of a messaging system including administration and
security are not defined by JMS. Each JMS vendor
is expected to give support for administration of
the messaging system using proprietary methods and
tools.
The Concept behind JMS
Fig 2 shows the main concepts in JMS. Although publish/subscribe
and point-to-point communication models are very
different from a conceptual viewpoint, the models
have a lot in common. JMS is therefore centered
on a generic messaging model and publish/subscribe
and point- to-point models are derived (in the sense
of interface inheritance) from the generic model.
The typical steps that a JMS developer performs
when developing a client applications are:
1. Resolve a connection factory and a destination
from JNDI. A destination is either a queue or a
topic.
2. Create a connection using the connection factory.
3. Create a session with the desired properties
from the connection.
4. If the application is a supplier, create a MessageProducer;
if the application is a consumer, create a MessageConsumer
from the session.
5. Start to send or receive messages using the producer
or consumer object. A producer will use the session
to create different kinds of messages.
JMS
supports six different kinds of messages, which
are used to carry different types of payload/data.
The header of a message is the same regardless of
payload, which means filtering is same for all six
different message types. A message supports number
of properties to set priority, reliability and other
QoS properties, which will be interpreted and handled
by JMS. In order to properly support durable messages,
JMS uses the notion of a durable subscriber. This
is only necessary in the publish/subscribe model
as messages on a queue will be consumed by any queue
receiver that connects to the queue in question.
A durable subscriber is identified by a name and
the same operation is conveniently used to both
create and re-create the subscriber.
JMS, like other Java enterprise APIs, is interface-based
and consists of two parts: the client interfaces
that the application programs use and the provider
that implements the services. The provider can use
any underlying mechanism it chooses. In JDBC, for
example, applications use the client interfaces
and the driver provides implementations using anything
ranging from raw sockets to a SQLnet protocol.
The JMS implementation of point-to-point and publish-subscribe
paradigms uses these same fundamental concepts,
but has specialized classes to handle them. The
architecture consists of a common set of base interfaces
and at least two sub interfaces for each base interface-one
for the point-to-point model, the other for the
publish/subscribe model.
What are Administered Objects?
An administered object is an object that the application
program retrieves from the JNDI context and works
with as though it were a local object. The application
administrator uses a vendor provided tool or mechanism
to configure these objects. This is similar to the
way long-distance telephone carriers work. The phone
company can configure the administered "carrier"
object as BPL or MaxTouch for example. To the client,
the call will work the same way (until the bills
come!) and he doesn't have to buy a new telephone
set every time he changes his mobile plan.
What is the Destination Interface?
Destinations represent an abstraction of a message
delivery or endpoint. The Destination interface
is used by the provider to define the location where
messages are delivered; the provider will decide
the underlying implementation mechanism. The clients
never see the details but, this interface works
with the sub interfaces javax.jms.Queue and javax.jms.Topic,
depending on the message style. The Destination
is an administered object.
Getting connection to a Provider: The ConnectionFactory
is an abstraction used to encapsulate the specifics
of connecting to a JMS provider from an application.
The task of a ConnectionFactory is to create a provider-specific
connection to the JMS. This is similar to how the
driver manager (java.sql.DriverManager) works in
JDBC. The application programmer need only connect
with the database-specific driver which returns
a connection to the database. The ConnectionFactory
is an administered object
Client connecting to a Provider: Depending on the
messaging style chosen, the connections are created
differently from the ConnectionFactory. However,
all connections have to implement the Connection
interface and thus methods standard to all JMS connections.
A connection should be closed when the program is
done using it.
The JMS Session: One of the connection's main jobs-to
create sessions-is hidden in its implementation.
A session in JMS is single-threaded, which means
that any message sending and receiving happens in
a serial order, one after the other. For example,
if A and B sent C four messages each simultaneously,
the session ensures that C is notified one at a
time. Although notification is synchronized, it
may occur in a different thread from the one that
created the session if the program uses the MessageListener
(discussed later). Sessions can also provide a transactional
context. This context stores messages for delivery
until the transaction is committed, in which case
all the messages are considered a single atomic
unit. If the transaction is rolled back, then all
messages are destroyed and the session returns to
its initial state.
Non-Transacted Session: There are 3 types of Non-transactional
sessions AUTO_ACKNOWLEDGE (The session automatically
acknowledges a client's receipt of a message), CLIENT_ACKNOWLEDGE
(The client acknowledges a message explicitly by
invoking the acknowledge() method in the message)
and DUPS_OK_ACKNOWLEDGE (This acknowledgement mode
instructs the session to acknowledge the delivery
of messages).
Sending a message: To send a message to a destination,
a client application must ask the session to create
a message producer. The message producer has to
implement the javax.jms.MessageProducer interface.
The MessageProducer is used to get and set default
values that are stored in the message when it is
sent. The producer needs to be closed once the work
is finished.
MessageConsumer: Message consumers are created by
the session for clients that want to receive messages.
Message consumers are attached to a destination
and are designed to retrieve messages sent
to those destinations. Just like
other interfaces, depending on
the messaging style, the javax.jms.QueueReceiver
or javax.jms.TopicSubscriber are used.
Messages: The message consists of the header, the
properties, and the body. A message is the actual
data sent from the sender to the receiver. Again,
although the object implementation is provider-specific,
a message implements the javax.jms.Message interface.
Message Selectors and Message Filters: In an enterprise
environment, a destination may require filtering
on business rules. For example, a Bank-Teller object
listening for Bank-Account objects as messages may
be required to do something only when the account
balance is below $3,000. To support filtering, JMS
provides the concept of a selector. A selector is
a SQL92 string that is passed to the message consumer.
The client can use the selector to decide if the
message is of interest. The selector cannot reference
the contents of the message but it can access the
properties and headers. Some examples of selectors
are: amount between 300 and 3000, area code like
'333'. From the client's perspective, messages that
don't meet the selection criteria simply don't exist.
Message Persistence in JMS: Persistence is the ability
of the provider to store messages. The client can
mark a message as Persistent if it is crucial, and
the provider will store this message until it is
delivered to the recipients. A message marked as
non-persistent may be lost in the delivery process
and should only be used for non-crucial messages.
Though persistent messages are more reliable, they
take up more storage space. Non-persistent messages
are ideal for non-crucial tasks where the application
is not affected by delivery failure (such as log
files, registry).
Message Time-To-Live: A client can specify a time-to-live
value in milliseconds for each message it sends.
It is up to the provider to "expire" the
message or to ignore this property.
Distributed Transactions in JMS
In addition to supporting transactions in the session,
JMS provides support for distributed transactions
by using Java Transaction API (JTA). Developers
can choose between using JMS without JTA or with
JTA by using the separate classes provided with
the XA prefix (few of the classes are XAQueueConnectionFactory,
XATopicConnectionFactory, XAQueueConnection, XATopicConnection,
XAQueueSession , XATopicSession ).
JMS-based communication is a potential solution
in any distributed computing scenario that needs
to pass data, not references, either synchronously
or asynchronously, between application components.
It offers a good solution for business integration
in heterogeneous environments and for connecting
to legacy systems. For example, an enterprise computing
strategy can use JMS-based distributed software
components as a middleware solution that functions
as a bridge among legacy applications. A common
application for JMS involves interfacing Enterprise
JavaBeans with legacy applications and sending legacy-related
data between the two.
When working with JMS, we have quite a few architectural
choices and application design factors to consider.
If we are working with distributed objects, our
choices are usually narrowed down to using RMI,
RMI over IIOP, or JMS. JMS may provide advantages
over these other techniques, but when using JMS
many factors (such as performance, load balancing,
and clustering) depend on which provider and underlying
implementation you choose.
Ajay Barvey is a Senior Programmer with Plexus Technologies
and can be reached at ajay_barvey@yahoo.com
<<