Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
May 2013
This guide provides information about concepts and
procedures for developing Java messaging applications (Java
clients) that work with Message Queue.
Open Message Queue Developer's Guide for Java Clients, Release 5.0
Contents
Preface ................................................................................................................................................................ vii
1 Overview
Setting Up Your Environment................................................................................................................ 1-1
Starting and Testing a Message Broker................................................................................................ 1-2
To Start a Broker................................................................................................................................. 1-2
To Test a Broker.................................................................................................................................. 1-3
Developing a Client Application .......................................................................................................... 1-4
To Produce Messages ........................................................................................................................ 1-4
To Consume Messages ...................................................................................................................... 1-6
Compiling and Running a Client Application................................................................................... 1-8
To Compile and Run the HelloWorldMessage Application.................................................... 1-10
Deploying a Client Application ......................................................................................................... 1-11
Example Application Code.................................................................................................................. 1-12
iii
2-13
2-13
2-14
2-14
2-15
2-15
2-16
2-17
2-17
2-18
2-18
2-18
2-18
2-19
2-20
2-20
2-22
2-23
2-24
2-48
2-48
2-49
2-50
2-51
2-51
2-52
2-54
2-54
2-54
3-1
3-2
3-3
3-3
3-3
3-4
3-4
3-4
3-7
3-7
3-8
3-9
5-1
5-2
5-3
5-3
5-3
5-4
5-4
5-7
5-8
7-1
7-2
7-3
7-3
7-3
7-4
7-4
vi
Preface
This book provides information about concepts and procedures for developing Java
messaging applications (Java clients) that work with Message Queue.
This preface consists of the following sections:
Documentation Conventions
Related Documentation
Documentation Accessibility
vii
Description
Chapter 1, "Overview"
Explains how to use the simplified API introduced by the Java Message
Service (JMS) specification, Version 2.0, in your client application.
Explains how to use the Message Queue Java API in your client application.
Explains how you send and receive SOAP messages with and without
Message Queue support.
Documentation Conventions
This section describes the following conventions used in Message Queue
documentation:
Typographic Conventions
Symbol Conventions
Typographic Conventions
The following table describes the typographic conventions that are used in this book.
Typeface
Meaning
Example
AaBbCc123
machine_name% su
Password:
aabbcc123
AaBbCc123
viii
Symbol Conventions
The following table explains symbols that might be used in this book.
Symbol
Description
Example
Meaning
[ ]
Contains optional
arguments and
command options.
ls [-l]
{ | }
Contains a set of
choices for a required
command option.
-d {y|n}
${ }
Indicates a variable
reference.
${com.sun.javaRoot}
Joins simultaneous
multiple keystrokes.
Control-A
Joins consecutive
multiple keystrokes.
Ctrl+A+N
>
Prompt
machine-name%
machine-name#
C:\>
ix
Variable
Description
IMQ_HOME
IMQ_VARHOME
IMQ_JAVAHOME
Related Documentation
The information resources listed in this section provide further information about
Message Queue in addition to that contained in this manual. The section covers the
following resources:
JavaDoc
Online Help
Document
Audience
Description
Technical Overview
Developers and
administrators
Release Notes
Developers and
administrators
Administration Guide
Administrators,
also recommended
for developers
Document
Audience
Description
Developers
Developers
Administrators
JavaDoc
JMS and Message Queue API documentation in JavaDoc format is included in
Message Queue installations at IMQ_HOME/javadoc/index.html. This documentation
can be viewed in any HTML browser. It includes standard JMS API documentation as
well as Message Queue-specific APIs.
Online Help
Online help is available for the Message Queue command line utilities; for details, see
"Command Line Reference" in Open Message Queue Administration Guide. The Message
Queue graphical user interface (GUI) administration tool, the Administration Console,
also includes a context-sensitive help facility; for details, see "Administration Console
Online Help" in Open Message Queue Administration Guide.
xi
Documentation (http://docs.oracle.com/)
Support (http://www.oracle.com/us/support/044752.html)
Training (http://education.oracle.com/pls/web_prod-plq-dad/db_
pages.getpage?page_id=315)
Documentation Accessibility
For information about Oracle's commitment to accessibility, visit the Oracle
Accessibility Program website at
http://www.oracle.com/pls/topic/lookup?ctx=acc&id=docacc.
Access to Oracle Support
Oracle customers have access to electronic support through My Oracle Support. For
information, visit
http://www.oracle.com/pls/topic/lookup?ctx=acc&id=info or visit
http://www.oracle.com/pls/topic/lookup?ctx=acc&id=trs if you are
hearing impaired.
xii
1
Overview
The minimum Java Development Kit (JDK) level required to compile and run Message
Queue clients is 1.2. For the purpose of this tutorial it is sufficient to run the Message
Queue message broker in a default configuration. For instructions on configuring a
message broker, see "Configuring a Broker" in Open Message Queue Administration
Guide.
Whether your application uses the Simple Object Access Protocol (SOAP)
The table below lists the .jar files you need to compile and run different kinds of
code.
Overview 1-1
Table 11
Type of Code
To Compile
To Run
Remarks
JMS client
jms.jar imq.jar
jndi.jar
jms.jar imq.jar
jndi.jar
Directory
containing
compiled Java
application or '.'
SOAP Client
saaj-api.jar
activation.jar
SOAP Servlet
jaxm-api.jar
saaj-api.jar
activation.jar
Code using
SOAP/JMS
transformer
utilities
imqxm.jar
saaj-api.jar
Directory
containing
compiled Java
application or '.'
A client application must be able to access the file jndi.jar even if the application
does not use the Java Naming and Directory Interface (JNDI) directly to look up
Message Queue administered objects. This is because JNDI is referenced by the
Destination and ConnectionFactory classes.
JNDI .jar files are bundled with JDK 1.4. Thus, if you are using this JDK, you do not
have to add jndi.jar to your CLASSPATH setting. However, if you are using an earlier
version of the JDK, you must include jndi.jar in your CLASSPATH.
If you are using JNDI to look up Message Queue administered objects, you must also
include the following files in your CLASSPATH setting:
If you are using the file-system service provider for JNDI (with any JDK version),
you must include the file fscontext.jar.
If you are using the Lightweight Directory Access Protocol (LDAP) context
with JDK 1.4, all files are already bundled with this JDK.
To Start a Broker
1.
2.
1-2 Open Message Queue 4.5.2 Developer's Guide for Java Clients
The -tty option causes all logged messages to be displayed to the terminal
console (in addition to the log file). The broker will start and display a few
messages before displaying the message
imqbroker@host:7676 ready
To Test a Broker
One simple way to check the broker startup is by using the Message Queue command
utility (imqcmd) to display information about the broker:
1.
2.
Supply the default password of admin when prompted to do so. The output
displayed should be similar to that shown in the next example.
Example 11 Output From Testing a Broker
% imqcmd query bkr -u admin
Querying the broker specified by:
------------------------Host
Primary Port
------------------------localhost
7676
Version
Instance Name
Primary Port
3.6
imqbroker
7676
0
0
unlimited (-1)
unlimited (-1)
70m
Auto
Auto
Auto
Auto
true
true
1
0
Create Queues
Create Topics
Created Queue Max Number of Active Consumers
Created Queue Max Number of Backup Consumers
Cluster
Cluster
Cluster
Cluster
Log Level
Log Rollover Interval (seconds)
Log Rollover Size (bytes)
INFO
604800
unlimited (-1)
Overview 1-3
To Produce Messages
1.
Create a connection.
A Connection object is an active connection to the Message Queue message
service, created by the connection factory you obtained in Developing a Client
Application:
Connection myConnection = myFactory.createConnection();
The first (boolean) argument specifies whether the session is transacted. The second
argument is the acknowledgment mode, such as AUTO_ACKNOWLEDGE, CLIENT_
ACKNOWLEDGE, or DUPS_OK_ACKNOWLEDGE; these are defined as static constants in the
JMS Session interface. See Acknowledgment Modes and Transacted Sessions for
further discussion.
4.
1-4 Open Message Queue 4.5.2 Developer's Guide for Java Clients
or by looking up a predefined destination using the JNDI API. See Working With
Destinations for further discussion.
5.
Create a message.
A Session object provides methods for creating each of the six types of message
defined by JMS: text, object, stream, map, bytes, and null messages. For instance,
you can create a text message with the statement
TextMessage outMsg = mySession.createTextMessage();
You can also use the property mechanism to define custom message properties of
your own: for instance,
outMsg.setStringProperty("MagicWord", "Shazam");
allowing Message Queue to free any resources it may have associated with the
session. See Working With Sessions for further discussion.
10. Close the connection.
When all sessions associated with a connection have been closed, you should close
the connection by calling its close method:
Overview 1-5
myConnection.close();
To Consume Messages
1.
Create a connection.
A Connection object is an active connection to the Message Queue message
service, created by the connection factory you obtained in Developing a Client
Application:
Connection myConnection = myFactory.createConnection();
The first (boolean) argument specifies whether the session is transacted. The second
argument is the acknowledgment mode, such as AUTO_ACKNOWLEDGE, CLIENT_
ACKNOWLEDGE, or DUPS_OK_ACKNOWLEDGE; these are defined as static constants in the
JMS Session interface. See Acknowledgment Modes and Transacted Sessions for
further discussion.
4.
or by looking up a predefined destination using the JNDI API. See Working With
Destinations for further discussion.
1-6 Open Message Queue 4.5.2 Developer's Guide for Java Clients
5.
Receive a message.
The message consumer's receive method requests a message from the destination
with which the consumer is associated:
Message inMsg = myConsumer.receive();
This method is used for synchronous consumption of messages. You can also
configure a message consumer to consume messages asynchronously, by creating a
message listener and associating it with the consumer. See Receiving Messages for
further discussion.
8.
In addition, you may need to retrieve some of the message's header fields: for
instance,
msgPriority = inMsg.getJMSPriority();
You can also use message methods to retrieve custom message properties of your
own: for instance,
magicWord = inMsg.getStringProperty("MagicWord");
allowing Message Queue to free any resources it may have associated with the
session. See Working With Sessions for further discussion.
10. Close the connection.
When all sessions associated with a connection have been closed, you should close
the connection by calling its close method:
myConnection.close();
Overview 1-7
Solaris: /usr/demo/imq/
Linux: opt/sun/mq/examples
Windows: IMQ_HOME/demo
1-8 Open Message Queue 4.5.2 Developer's Guide for Java Clients
//
//
//
Create a connection.
Connection
//
Create a session.
Session
//
myConnection = myFactory.createConnection();
mySession = myConnection.createSession(false,
Session.AUTO_ACKNOWLEDGE);
//
//
//
myProducer = mySession.createProducer(myDest);
myConsumer = mySession.createConsumer(myDest);
Create a message.
TextMessage
outMsg = mySession.createTextMessage("Hello,
World!");
//
//
//
inMsg = myConsumer.receive();
Overview 1-9
//
//
}
catch (Exception jmse)
{ System.out.println("Exception occurred: " + jmse.toString() );
jmse.printStackTrace();
}
}
}
import java.util.*
1-10 Open Message Queue 4.5.2 Developer's Guide for Java Clients
Administered Objects
Connection Factories:
Type
Other attributes
Destinations:
Physical Destinations
Type
Name
Attributes
Name
Port
Overview
1-11
Properties
Example Programs
Directory
Contents
helloworld
Sample programs showing how to create and deploy a JMS client in Message
Queue, including the steps required to create administered objects and to
look up such objects with JNDI from within client code
jms
Sample programs demonstrating the use of the JMS API with Message
Queue
jaxm
applications
monitoring
jdbc
imqobjmgr
1-12 Open Message Queue 4.5.2 Developer's Guide for Java Clients
2
Message Queue Clients: Design and
Features
This chapter addresses architectural and configuration issues that depend upon
Message Queue's implementation of the Java Message Specification. It covers the
following topics:
Make sure your code does not depend on extensions or features that are specific to
Message Queue.
Look up, using JNDI, (rather than instantiate) administered objects for connection
factories and destinations.
Administered objects encapsulate provider-specific implementation and
configuration information. Besides allowing for portability, administered objects
also make it much easier to share connection factories between applications and to
tune a JMS application for performance and resource use. So, even if portability is
not important to you, you might still want to leave the work of creating and
configuring these objects to an administrator. For more information, see Looking
Up a Connection Factory With JNDI and Looking Up a Destination With JNDI.
Simplified API
Classic API
Destination
Destination
Queue
ConnectionFactory
ConnectionFactory
QueueConnectionFact TopicConnectionFact
ory
ory
JMSContext
Connection
QueueConnection
TopicConnection
Session
QueueSession
TopicSession
JMSProducer
MessageProducer
QueueSender
TopicPublisher
JMSConsumer
MessageConsumer
QueueReceiver
TopicSubscriber
The JMS 2.0 specification provides the Simplified API for unified domains. It provides
all the functionality of the Classic API provided by the JMS 1.1 specification but
requires fewer interfaces and is simpler to use. You can choose the API that best suits
your needs. The legacy domain-specific APIs continue to be supported but are not
recommended for new application development.
2-2 Open Message Queue 4.5.2 Developer's Guide for Java Clients
consuming messages. When you are thinking about structuring your client, it is best to
think of the work that is done at the session level.
A session
Supports a single series of transactions that combine work spanning its producers
and consumers into atomic units
Defines a serial order for the messages it consumes and the messages it produces
The requirement that sessions be operated on by a single thread at a time places some
restrictions on the combination of producers and consumers that can use the same
session. In particular, if a session has an asynchronous consumer, it may not have any
other synchronous consumers. For a discussion of the connection and session's use of
threads, see Managing Client Threads. With the exception of these restrictions, let the
needs of your application determine the number of sessions, producers, and
consumers.
JMSContext
The JMS 2.0 Specification provides the JMSContext object is an active connection to a
JMS provider and a single-threaded context for sending and receiving messages. It is
used in the Simplified API to combine the functionality of the Connection and Session
object to reduce the number of objects to send and receive messages. See The JMS
Simplified API.
Are you using an asynchronous message consumer that does not receive messages
often or a producer that is seldom used?
Let the administrator know how to set the ping interval, so that your client gets an
exception if the connection should fail. For more information see Using the Client
Runtime Ping Feature.
Benefits vary with the size and format of messages, the number of consumers,
network bandwidth, and CPU performance; and benefits are not guaranteed. For a
more detailed discussion, see Message Compression.
2-4 Open Message Queue 4.5.2 Developer's Guide for Java Clients
Order the selector expression so that Message Queue can determine its evaluation
as soon as possible. (Evaluation proceeds from left to right.) This can easily double
or triple performance when using selectors, depending on the complexity of the
expression.
If you have two expressions joined by an OR, put the expression that is most
likely to evaluate to TRUE first.
If you have two expressions joined by an AND, put the expression that is most
likely to evaluate to FALSE first.
For example, if size is usually greater than 6, but color is rarely red you'd want
the order of an OR expression to be:
size> 6 OR color = 'red'
applications. This section addresses these issues and offers some guidelines for
managing client threads.
The system does not enforce the requirement that a session be single threaded. If your
client application violates this requirement, you will get a JMSIllegalState exception
or unexpected results.
When you create several asynchronous message consumers in the same session,
messages are delivered serially by the session thread to these consumers. Sharing a
session among several message consumers might starve some consumers of
messages while inundating other consumers. If the message rate across these
consumers is high enough to cause an imbalance, you might want to separate the
consumers into different sessions. To determine whether message flow is
unbalanced, you can monitor destinations to see the rate of messages coming in.
See Using the Metrics Monitoring API.
You can reduce the number of threads allocated to the client application by using
fewer connections and fewer sessions. However, doing this might slow your
application's throughput.
You might be able to use certain JVM runtime options to improve thread memory
usage and performance. For example, if you are running on the Solaris platform,
you may be able to run with the same number (or more) threads by using the
following vm options with the client: Refer to the JDK documentation for details.
Use the Xss128K option to decrease the memory size of the heap.
Use the xconcurrentIO option to improve thread performance in the 1.3 VM.
2-6 Open Message Queue 4.5.2 Developer's Guide for Java Clients
Managing Memory
You can also improve performance by having the administrator set connection factory
attributes to meter the message flow over the client-broker connection and to limit the
message flow for a consumer. For a detailed explanation, please see "Reliability And
Flow Control" in Open Message Queue Administration Guide.
Managing Memory
A client application running in a JVM needs enough memory to accommodate
messages that flow in from the network as well as messages the client creates. If your
client gets OutOfMemoryError errors, chances are that not enough memory was
provided to handle the size or the number of messages being consumed or produced.
Your client might need more than the default JVM heap space. On most systems, the
default is 64 MB but you will need to check the default values for your system.
Consider the following guidelines:
Evaluate the normal and peak system memory footprints when sizing heap space.
You can start by doubling the heap size using a command like the following:
java -Xmx128m MyClass
The best size for the heap space depends on both the operating system and the
JDK release. Check the JDK documentation for restrictions.
The size of the VM's memory allocation pool must be less than or equal to the
amount of virtual memory that is available on the system.
Message Compression
You can use the Message.setBooleanProperty() method to specify that the body of a
message be compressed. If the JMS_SUN_COMPRESS property is set to true, the client
runtime, will compress the body of the message being sent. This happens after the
producer's send method is called and before the send method returns to the caller. The
Compression only affects the message body; the message header and properties are
not compressed.
Two read-only JMS message properties are set by the client runtime after a message is
sent.
Applications can test the properties (JMS_SUN_UNCOMPRESSED_SIZE and JMS_SUN_
COMPRESSED_SIZE) after a send returns to determine whether compression is
advantageous. That is, applications wanting to use this feature, do not have to
explicitly receive a compressed and uncompressed version of the message to
determine whether compression is desired.
If the consumer of a compressed message wants to resend the message in an
uncompressed form, it should call the Message.clearProperties() to clear the JMS_
SUN_COMPRESS property. Otherwise, the message will be compressed before it is sent to
its next destination.
Compression Examples
Example 21 shows how you set and send a compressed message:
Example 21 Sending a Compressed Message
//topicSession and myTopic are assumed to have been created
topicPublisher publisher = topicSession.createPublisher(myTopic);
BytesMessage bytesMessage=topicSession.createBytesMessage();
//byteArray is assumed to have been created
bytesMessage.writeBytes(byteArray);
//instruct the client runtime to compress this message
bytesMessage.setBooleanProperty("JMS_SUN_COMPRESS", true);
2-8 Open Message Queue 4.5.2 Developer's Guide for Java Clients
Example 22 shows how you examine compressed and uncompressed message body
size. The bytesMessage was created as in Example 21:
Example 22 Comparing Compressed and Uncompressed Message Size
//get uncompressed body size
int uncompressed=bytesMessage.getIntProperty("JMS_SUN_UNCOMPRESSED_SIZE");
//get compressed body size
int compressed=bytesMessage.getIntProperty("JMS_SUN_COMPRESSED_SIZE");
For an introduction to dead messages and the dead message queue, see "Using the
Dead Message Queue" in Open Message Queue Administration Guide.
For a description of the destination properties and of the broker properties that
control the system's use of the dead message queue, see "Physical Destination
Property Reference" in Open Message Queue Administration Guide.
This section describes the message properties that you can set or examine
programmatically to determine the following:
Message Queue 3.6 clients can set properties related to the dead message queue on
messages and send those messages to clients compiled against earlier versions.
However clients receiving such messages cannot examine these properties without
recompiling against 3.6 libraries.
The dead message queue is automatically created by the broker and called
mq.sys.dmq. You can use the message monitoring API, described in Using the Metrics
Monitoring API, to determine whether that queue is growing, to examine messages on
that queue, and so on.
You can set the properties described in Table 22 for any message to control how the
broker should handle that message if it deems it to be undeliverable. Note that these
message properties are needed only to override destination, or broker-based behavior.
Table 22
Property
Description
JMS_SUN_PRESERVE_UNDELIVERED
A boolean whose value determines what the broker should do with the
message if it is dead.
The default value of unset, specifies that the message should be handled as
specified by the useDMQ property of the destination to which the message
was sent.
A value of true overrides the setting of the useDMQ property and sends the
dead message to the dead message queue.
A value of false overrides the setting of the useDMQ property and prevents
the dead message from being placed in the dead message queue.
JMS_SUN_LOG_DEAD_MESSAGES
JMS_SUN_TRUNCATE_MSG_BODY
The properties described in Table 23 are set by the broker for a message placed in the
dead message queue. You can examine the properties for the message to retrieve
information about why the message was placed on the queue and to gather other
information about the message and about the context within which this action was
taken.
2-10 Open Message Queue 4.5.2 Developer's Guide for Java Clients
Table 23
Property
Description
JMS_SUN_DMQ_DELIVERY_COUNT
JMS_SUN_DMQ_UNDELIVERED_TIMESTAMP
A Long that specifies the time (in milliseconds) when the message
was placed on the dead message queue.
JMS_SUN_DMQ_UNDELIVERED_REASON
JMS_SUN_DMQ_PRODUCING_BROKER
JMS_SUN_DMQ_DEAD_BROKER
JMS_SUN_DMQ_UNDELIVERED_EXCEPTION
A String that specifies the name of the exception (if the message
was dead because of an exception) on either the client or the broker.
JMS_SUN_DMQ_UNDELIVERED_COMMENT
JMS_SUN_DMQ_BODY_TRUNCATED
A Boolean: a value of true indicates that the message body was not
stored. A value of false indicates that the message body was stored.
If the default value REJECT_NEWEST is specified for the limitBehavior property, the
broker throws out the newest messages received when memory limits are exceeded. If
2-11
the message discarded is a persistent message, the producing client gets an exception
which should be handled by resending the message later.
If any of the other values is selected for the limitBehavior property or if the message
is not persistent, the application client is not notified if a message is discarded.
Application clients should let the administrator know how they prefer this property to
be set for best performance and reliability.
2-12 Open Message Queue 4.5.2 Developer's Guide for Java Clients
You can avoid this problem by having your client do either of the following:
Use one of the synchronous receive methods that specifies a timeout interval.
Use a queue browser to check the queue before calling the receiveNoWait method.
Use of Transactions
Acknowledgment Mode
Message Size
The sections that follow describe the impact of each of these factors on messaging
performance. As a general rule, there is a trade-off between performance and
reliability: factors that increase reliability tend to decrease performance.
Table 24 shows how application design factors affect messaging performance. The
table shows two scenariosa high-reliability, low-performance scenario and a
high-performance, low-reliability scenarioand the choice of application design
factors that characterizes each. Between these extremes, there are many choices and
trade-offs that affect both reliability and performance.
Table 24
Delivery mode
Persistent messages
Nonpersistent messages
Use of transactions
Transacted sessions
No transactions
Acknowledgment mode
AUTO_ACKNOWLEDGE
DUPS_OK_ACKNOWLEDGE
CLIENT_ACKNOWLEDGE
NO_ACKNOWLEDGE
Durable/nondurable
subscriptions
Durable subscriptions
Nondurable subscriptions
Use of selectors
Message filtering
No message filtering
Message size
Small messages
Large messages
2-13
Broker processing of persistent messages is slower than for nonpersistent messages for
the following reasons:
A broker must reliably store a persistent message so that it will not be lost should
the broker fail.
The broker must confirm receipt of each persistent message it receives. Delivery to
the broker is guaranteed once the method producing the message returns without
an exception.
Depending on the client acknowledgment mode, the broker might need to confirm
a consuming client's acknowledgment of a persistent message.
For both queues and topics with durable subscribers, performance was approximately
40% faster for non-persistent messages. We obtained these results using 10K-size
messages and AUTO_ACKNOWLEDGE mode.
Use of Transactions
A transaction guarantees that all messages produced in a transacted session and all
messages consumed in a transacted session will be either processed or not processed
(rolled back) as a unit. Message Queue supports both local and distributed
transactions.
A message produced or acknowledged in a transacted session is slower than in a
non-transacted session for the following reasons:
Acknowledgment Mode
Other than using transactions, you can ensure reliable delivery by having the client
acknowledge receiving a message. If a session is closed without the client
acknowledging the message or if the message broker fails before the acknowledgment
is processed, the broker redelivers that message, setting a JMSRedelivered flag.
For a non-transacted session, the client can choose one of three acknowledgment
modes, each of which has its own performance characteristics:
2-14 Open Message Queue 4.5.2 Developer's Guide for Java Clients
Extra control messages between broker and client are required in AUTO_
ACKNOWLEDGE and CLIENT_ACKNOWLEDGE modes. The additional control messages
add processing overhead and can interfere with JMS payload messages, causing
processing delays.
In AUTO_ACKNOWLEDGE and CLIENT_ACKNOWLEDGE modes, the client must wait until
the broker confirms that it has processed the client's acknowledgment before the
client can consume more messages. (This broker confirmation guarantees that the
broker will not inadvertently redeliver these messages.)
The Message Queue persistent store must be updated with the acknowledgment
information for all persistent messages received by consumers, thereby decreasing
performance.
The Message Queue message broker must persistently store the list of messages
assigned to each durable subscription so that should the broker fail, the list is
available after recovery.
Persistent messages for durable subscriptions are stored persistently, so that
should a broker fail, the messages can still be delivered after recovery, when the
corresponding consumer becomes active. By contrast, persistent messages for
nondurable subscriptions are not stored persistently (should a broker fail, the
corresponding consumer connection is lost and the message would never be
delivered).
2-15
Message Size
Message size affects performance because more data must be passed from producing
client to broker and from broker to consuming client, and because for persistent
messages a larger message must be stored.
However, by batching smaller messages into a single message, the routing and
processing of individual messages can be minimized, providing an overall
performance gain. In this case, information about the state of individual messages is
lost.
In our tests, which compared throughput in kilobytes per second for 1K, 10K, and
100K-sized messages to a queue destination using AUTO_ACKNOWLEDGE mode, we found
that non-persistent messaging was about 50% faster for 1K messages, about 20% faster
for 10K messages, and about 5% faster for 100K messages. The size of the message
affected performance significantly for both persistent and non-persistent messages.
100k messages are about 10 times faster than 10K, and 10K messages are about 5 times
faster than 1K.
While, in general, the message type is dictated by the needs of an application, the more
complicated types (map and object) carry a performance cost the expense of
serializing and deserializing the data. The performance cost depends on how simple or
how complicated the data is.
The following sections describe the events that can trigger notification and explain
how you can create an event listener.
2-16 Open Message Queue 4.5.2 Developer's Guide for Java Clients
Connection Events
The following table lists and describes the events that can be returned by the event
listener.
Note that the JMS exception listener is not called when a connection event occurs. The
exception listener is only called if the client runtime has exhausted its reconnection
attempts. The client runtime always calls the event listener before the exception
listener.
Table 25
Notification Events
Event Type
Meaning
ConnectionClosingEvent
The Message Queue client runtime generates this event when it receives
a notification from the broker that a connection is about to be closed due
to a shutdown requested by the administrator.
ConnectionClosedEvent
ConnectionReconnectedEvent
ConnectionReconnectFailedEvent
2-17
connection.setEventListener ( eListener );
Consumer Events
The following table lists and describes the events that can be returned by the event
listener.
Table 26
Event Type
Meaning
ConsumerEvent
2-18 Open Message Queue 4.5.2 Developer's Guide for Java Clients
(com.sun.messaging.jms.Connection)factory.createConnection();
//create an MQ session
com.sun.messaging.jms.Session session =
(com.sun.messaging.jms.Session)connection.createSession(false,
Session.AUTO_ACKNOWLEDGE);
//create a queue
com.sun.messaging.Queue queue =
(com.sun.messaging.Queue)session.createQueue(strQueueName);
//construct an MQ event listener. The listener implements
//com.sun.messaging.jms.notification.EventListener interface.
com.sun.messaging.jms.notification.EventListener consEvtListener =
new MyConsumerEventListener();
//set consumer event listener.
connection.setConsumerEventListener
( (com.sun.messaging.Destination)queue, consEvtListener );
//perform activities
//remove consumer event listener.
connection.removeConsumerEventListener
( (com.sun.messaging.Destination)queue );
2-19
}
}
}
Enabling Auto-Reconnect
If you are using conventional clusters, you enable automatic reconnection by setting
the connection factory imqReconnectEnabled attribute to true. If you are using a high
availability cluster, the imqReconnectEnabled attribute is ignored; the client runtime
will automatically reconnect to a backup broker if the connection is lost and not
regained after no more than imqReconnectAttempts attempts. This applies to all
deployment configurations: whether Message Queue is used stand alone or whether
the connection is created through a resource adapter.
No matter which type of cluster you are using, you must also configure the connection
factory administered object to specify the following information.
2-20 Open Message Queue 4.5.2 Developer's Guide for Java Clients
The number of iterations to be made over the list of brokers (using the
imqAddressListIterations attribute) when attempting to create a connection or
to reconnect.
For high-availability clusters, the broker will attempt to reconnect forever (no
matter what value you specify for this attribute). If the client does not want this
behavior, it must explicitly close the connection.
Single-Broker Auto-Reconnect
Configure your connection-factory object as follows:
Example 23 Example of Command to Configure a Single Broker
imqobjmgr add -t cf -l "cn=myConnectionFactory" \
-o "imqAddressList=mq://jpgserv/jms" \
-o "imqReconnect=true" \
-o "imqReconnectAttempts=10"
-j "java.naming.factory.initial =
com.sun.jndi.fscontext.RefFSContextFactory
-j "java.naming.provider.url= file:///home/foo/imq_admin_objects"
This command creates a connection-factory object with a single address in the broker
address list. If connection fails, the client runtime will try to reconnect with the broker
10 times. If an attempt to reconnect fails, the client runtime will sleep for three seconds
(the default value for the imqReconnectInterval attribute) before trying again. After
10 unsuccessful attempts, the application will receive a JMSException .
You can ensure that the broker starts automatically at system start-up time. See
"Starting Brokers Automatically" in Open Message Queue Administration Guide for
2-21
This command creates a connection factory object with two addresses in the broker
list. The first address describes a broker instance running on the host myhost1 with a
standard port number (7676). The second address describes a jms connection service
running at a statically configured port number (12345).
Clustered-Broker Auto-Reconnect
Configure your connection-factory objects as follows:
Example 25 Example of Command to Configure a Broker Cluster
imqobjmgr add -t cf -l "cn=myConnectionFactory" \
-o "imqAddressList=mq://myhost1/ssljms, \
mq://myhost2/ssljms, \
mq://myhost3/ssljms, \
mq://myhost4/ssljms" \
-o "imqReconnect=true" \
-o "imqReconnectRetries=5" \
-o "imqAddressListBehavior=RANDOM"
-j "java.naming.factory.initial =
com.sun.jndi.fscontext.RefFSContextFactory
-j "java.naming.provider.url= file:///home/foo/imq_admin_objects"
This command creates a connection factory object with four addresses in the
imqAddressList. All the addresses point to jms services running on SSL transport on
different hosts. Since the imqAddressListBehavior attribute is set to RANDOM, the client
connections that are established using this connection factory object will be distributed
randomly among the four brokers in the address list. If you are using a high
availability cluster, the RANDOM attribute is ignored during a failover reconnect after
losing an existing connection to a broker.
For a conventional cluster, you must configure one of the brokers in the cluster as the
master broker.In the connection-factory address list, you can also specify a subset of all
the brokers in the cluster.
Auto-Reconnect Behaviors
A broker treats an automatic reconnection as it would a new connection. When the
original connection is lost, all resources associated with that connection are released.
For example, in a broker cluster, as soon as one broker fails, the other brokers assume
that the client connections associated with the failed broker are gone. After
auto-reconnect takes place, the client connections are recreated from scratch.
2-22 Open Message Queue 4.5.2 Developer's Guide for Java Clients
In a conventional cluster, persistent messages produced but not yet consumed may
only be delivered to the consumer after the original broker recovers. Other state
information held by the failed or disconnected broker can be lost. The messages
held by the original broker, once it is restored, might be delivered out of order.
In a high availability cluster, messages produced but not yet consumed continue to
be delivered to the consumer without the original broker needing to recover.
A transacted session is the most reliable method of ensuring that a message isn't lost if
you are careful in coding the transaction. If auto-reconnect happens in the middle of a
transaction, any attempt to produce or consume messages will cause the client runtime
to throw a JMSException. In this case, applications must call Session.rollback() to
roll back the transaction.
The Message Queue client runtime may throw a TransactionRolledBackException
when Session.commit() is called during or after a failover occurs. In this case, the
transaction is rolled back and a new transaction is automatically started. Applications
are not required to call Session.rollback() to rollback the transaction after receiving
a TransactionRolledBackException.
The Message Queue client runtime may throw a JMSException when
Session.commit() is called during or after a failover occurs. In this case, the
transaction state is unknown (may or may not be committed). Applications should call
Session.rollback() to roll back the uncommitted transaction.
If you are using a high availability cluster, the only time your transaction might wind
up in an unknown state is if it is not possible to reconnect to any brokers in the cluster.
This should happen rarely if ever. For additional information, see Handling Exceptions
When Failover Occurs.
Automatic reconnection affects producers and consumers differently:
Auto-Reconnect Limitations
Notice the following points when using the auto-reconnect feature:
2-23
Starting a new broker process. (However, the brokers that are already running
continue to function normally even if the master broker goes down.)
You can configure the master broker to restart automatically using Message
Queue broker support for rc scripts or the Windows service manager.
Note:
the failover occurs during the call to Session.commit(). In the first case, the failover is
said to occur during an open transaction; in the second case, the failover occurs during
the commit itself.
In the case of a failover during an open transaction, when the client application calls
Session.commit(), the client runtime will throw a TransactionRolledBackException
and roll back the transaction causing the following to happen.
Messages that have been produced (but not committed) in the transacted session
are discarded and not delivered to the consumer.
All messages that have been consumed (but not committed) in the transacted
session are redelivered to the consumer with the Redeliver flag set.
A new transaction is automatically started.
If the client application itself had called Session.rollback after a failover (before the
Session.commit is executed) the same things would happen as if the application had
received a TransactionRollbackException. After receiving a
TransactionRollbackException or calling Session.rollback(), the client application
must retry the failed transaction. That is, it must re-send and re-consume the messages
that were involved in the failed-over transaction.
In the second case, when the failover occurs during a call to Session.commit, there
may be three outcomes:
The transaction is committed successfully and the call to Session.commit does not
return an exception. In this case, the application client does not have to do
anything.
The runtime throws a TransactionRolledbackException and does not commit the
transaction. The transaction is automatically rolled back by the Message Queue
runtime. In this case, the client application must retry the transaction as described
for the case in which an open transaction is failed-over.
A JMXException is thrown. This signals the fact that the transaction state is
unknown: It might have either succeeded or failed. A client application should
handle this case by assuming failure, pausing for three seconds, calling
Session.rollback, and then retrying the operations. However, since the commit
might have succeeded, when retrying the transacted operations, a producer
should set application-specific properties on the messages it re-sends to signal that
these might be duplicate messages. Likewise, consumers that retry receive
operations should not assume that a message that is redelivered is necessarily a
duplicate. In other words, to ensure once and only once delivery, both producers
and consumers need to do a little extra work to handle this edge case. The code
samples presented next illustrate good coding practices for handling this situation.
If you are using a high availability cluster, the only time this condition might arise
is when the client is unable to connect to any backup broker. This should be
extremely rare.
The next two examples illustrate how stand-alone Message Queue producers and
consumers should handle transactions during a failover. To run the sample programs,
do the following:
1.
Start two high availability brokers. The brokers can be on the same machine or on
different machines, but they must be in the same cluster.
2.
2-25
java DimqAddressList="localhost:777"
test.jmsclient.ha.FailoverQReceiver
It does not matter in what order you start the programs. The only property that
you must specify is imqAddressList. The client application will be automatically
failed over to a backup broker if the connection to its home broker fails. (The
imqReconnectEnabled and imqAddressListIterations properties are ignored for
a high availability cluster.)
3.
Kill the broker to which the producing or consuming application is connected. The
clients will reconnect, validate, and continue the failed transaction. A message
produced or consumed in a transaction is either committed or rolled back after a
successful failover.
4.
You can restart the dead broker and retry the failover operation by killing the new
home broker.
Transacted Session: Failover Producer Example The following code sample shows the work
that a producer in a transacted session needs to do to recover state after a failover.
Note how the application tests both for rollback exceptions and for JMS exceptions.
Note also the use of a counter to allow the producer and consumer to verify message
order and delivery.
/*
* @(#)FailoverQSender.java
1.2 07/04/20
*
* Copyright 2000 Sun Microsystems, Inc. All Rights Reserved
* SUN PROPRIETARY/CONFIDENTIAL
* Use is subject to license terms.
*
*/
package test.jmsclient.ha;
import
import
import
import
java.util.Date;
javax.jms.*;
com.sun.messaging.jms.Connection;
com.sun.messaging.jms.notification.*;
/**
*
* This sample program uses a transacted session to send messages.
* It is designed to run with test.jmsclient.ha.FailoverQReceiver
* @version 1.0
*/
public class FailoverQSender
implements ExceptionListener, EventListener, Runnable {
//constant - commit property name
public static final String COMMIT_PROPERTY_NAME = "COMMIT_PROPERTY";
//constant - message counter
public static final String MESSAGE_COUNTER = "counter";
//constant - destination name
public static final String TEST_DEST_NAME = "FailoverTestDest001";
//queue connection
QueueConnection conn = null;
//session
QueueSession session = null;
//queue sender
QueueSender sender = null;
//queue destination
2-26 Open Message Queue 4.5.2 Developer's Guide for Java Clients
2-27
log("Rollback failed");
log(jmse);
//application may decide to log and continue sending messages
// without closing the application.
close();
}
}
/**
* rollback application data and jms session.
*
*/
private void rollBackAll() {
//rollback jms
rollBackJMS();
//rollback app data
rollBackApplication();
}
/**
* close JMS connection and stop the application
*
*/
private void close() {
try {
if ( conn != null ) {
//close the connection
conn.close();
}
} catch (Exception e) {
//log exception
log (e);
} finally {
//set flag to true. application thread will exit
isConnected = false;
}
}
/**
* Send messages in a loop until the connection is closed.
* Session is committed for each message sent.
*/
public void run () {
//start producing messages
while (isConnected) {
try {
//reset message counter if it reaches max int value
checkMessageCounter();
//create a message
Message m = session.createMessage();
//get the current message counter value
int messageCounter = this.getMessageCounter();
//set message counter to message property
m.setIntProperty(MESSAGE_COUNTER, messageCounter);
//set commit property
m.setBooleanProperty(COMMIT_PROPERTY_NAME, true);
//send the message
sender.send(m);
2-28 Open Message Queue 4.5.2 Developer's Guide for Java Clients
2-29
sender = session.createSender(queue);
//set isConnected flag to true.
this.isConnected = true;
} catch (JMSException jmse) {
this.isConnected = false;
}
}
/**
* get the next message counter.
*/
private synchronized int getMessageCounter () {
return ++ currentCounter;
}
/**
* commit the current transaction/session.
*/
private void commit() throws JMSException {
session.commit();
this.commitCounter = currentCounter;
log ("Transaction committed, commit counter: " +commitCounter);
}
/**
* Get the current connencted broker address.
*/
private String getCurrentConnectedBrokerAddress() {
return ((com.sun.messaging.jms.Connection)conn).getBrokerAddress();
}
/**
* log a string message.
* @param msg
*/
private synchronized void log (String msg) {
System.out.println(new Date() + ": " + msg);
}
/**
* Log an exception received.
*/
private synchronized void log (Exception e) {
System.out.println(new Date() + ": Exception:");
e.printStackTrace();
}
/**
* Log the specified MQ event.
*/
private synchronized void log (Event event) {
try {
System.out.println(new Date() + ": Received MQ event notification.");
System.out.println("*** Event code: " + event.getEventCode() );
System.out.println("*** Event message: " + event.getEventMessage());
} catch (Exception e) {
e.printStackTrace();
2-30 Open Message Queue 4.5.2 Developer's Guide for Java Clients
}
}
/**
* pause the specified milli seconds.
*/
private void sleep (long millis) {
try {
Thread.sleep(millis);
} catch (java.lang.InterruptedException inte) {
log (inte);
}
}
/**
* The main program.
*/
public static void main (String args[]) {
FailoverQSender fp = new FailoverQSender();
fp.run();
}
}
Transacted Session: Failover Consumer Example The following code sample shows the
work that a consumer in a transacted session needs to do in order to recover state after
a failover. Note how the application tests both for rollback exceptions and JMS
exceptions. Note also the use of a counter to allow the producer and consumer to
verify message order and delivery.
/*
* @(#)FailoverQReceiver.java
1.4 07/04/20
*
* Copyright 2000 Sun Microsystems, Inc. All Rights Reserved
* SUN PROPRIETARY/CONFIDENTIAL
* Use is subject to license terms.
*/
package test.jmsclient.ha;
import
import
import
import
java.util.Date;
java.util.Vector;
javax.jms.*;
com.sun.messaging.jms.notification.*;
/**
* This sample program uses a transacted session to receive messages.
* It is designed to run with test.jmsclient.ha.FailoverQSender.
*
* @version 1.0
*/
public class FailoverQReceiver
implements ExceptionListener, EventListener, Runnable {
//queue connection
private QueueConnection conn = null;
//queue session
private QueueSession session = null;
//qreceiver
private QueueReceiver qreceiver = null;
//queue destination
private Queue queue = null;
2-31
//commmitted counter.
private int commitCounter = 0;
//flag to indicate if the connection is connected to the broker.
private boolean isConnected = false;
//flag to indicate if current connection is to HA broker cluster.
private boolean isHAConnection = false;
//application data holder.
private Vector data = new Vector();
/**
* Default constructor - JMS setup.
*/
public FailoverQReceiver() {
//set up JMS environment
setup();
}
/**
* Connection Exception listener.
*/
public void onException (JMSException e) {
//The run() method will exit.
this.isConnected = false;
log ("Exception listener is called. Connection is closed
by MQ client runtime." );
log (e);
}
/**
* log the connection event.
*/
public void onEvent (Event connectionEvent) {
log (connectionEvent);
}
/**
* Roll back application data.
*/
private void rollBackApplication() {
//reset application data
this.reset();
log ("Rolled back application data, current commit counter:
" + commitCounter);
}
/**
* Clear the application data for the current un-committed transaction.
*/
private void reset() {
data.clear();
}
/**
* Roll back JMS transaction and application.
*/
private void rollBackAll() {
try {
2-32 Open Message Queue 4.5.2 Developer's Guide for Java Clients
//rollback JMS
rollBackJMS();
//rollback application data
rollBackApplication();
} catch (Exception e) {
log ("rollback failed. closing JMS connection ...");
//application may decide NOT to close connection if rollback failed.
close();
}
}
/**
* Roll back jms session.
*/
private void rollBackJMS() throws JMSException {
session.rollback();
log("JMS session rolled back ...., commit counter:
" + commitCounter);
}
/**
* Close JMS connection and exit the application.
*/
private void close() {
try {
if ( conn != null ) {
conn.close();
}
} catch (Exception e) {
log (e);
} finally {
isConnected = false;
}
}
/**
* Receive, validate, and commit messages.
*/
public void run () {
//produce messages
while (isConnected) {
try {
//receive message
Message m = qreceiver.receive();
//process message -- add message to the data holder
processMessage(m);
//check if the commit flag is set in the message property
if ( shouldCommit(m) ) {
//commit the transaction
commit(m);
}
} catch (TransactionRolledBackException trbe) {
log ("transaction rolled back by MQ ...");
//rollback application data
2-33
rollBackApplication();
} catch (JMSException jmse) {
//The exception can happen when receiving messages
//and the connected broker is killed.
if ( isConnected == true ) {
//rollback MQ and application data
rollBackAll();
}
} catch (Exception e) {
log (e);
//application may decide NOT to close the connection
//when an unexpected Exception occurred.
close();
}
}
}
/**
* Set up testing parameters - connection, destination, etc
*/
protected void setup() {
try {
//get connection factory
com.sun.messaging.QueueConnectionFactory factory =
new com.sun.messaging.QueueConnectionFactory();
//create jms connection
conn = factory.createQueueConnection();
//set exception listener
conn.setExceptionListener(this);
//set event listener
( (com.sun.messaging.jms.Connection) conn).setEventListener(this);
//test if this is a HA connection
isHAConnection = ( (com.sun.messaging.jms.Connection)
conn).isConnectedToHABroker();
log ("Is connected to HA broker cluster: " + isHAConnection);
//get destination name
String destName = FailoverQSender.TEST_DEST_NAME;
//create a transacted session
session = conn.createQueueSession(true, -1);
//get destination
queue = session.createQueue(destName);
//create queue receiver
qreceiver = session.createReceiver(queue);
//set isConnected flag to true
isConnected = true;
//start the JMS connection
conn.start();
log("Ready to receive on destination: " + destName);
} catch (JMSException jmse) {
isConnected = false;
2-34 Open Message Queue 4.5.2 Developer's Guide for Java Clients
log (jmse);
close();
}
}
/**
* Check if we should commit the transaction.
*/
private synchronized boolean shouldCommit(Message m) {
boolean flag = false;
try {
//get the commit flag set by the FailoverQSender
flag = m.getBooleanProperty(FailoverQSender.COMMIT_PROPERTY_NAME);
if ( flag ) {
//check if message property contains expected message counter
validate (m);
}
} catch (JMSException jmse) {
log (jmse);
}
return flag;
}
/**
* A very simple validation only. More logic may be added to validate
* message ordering and message content.
* @param m Message The last message received for the current transaction.
*/
private void validate (Message m) {
try {
//get message counter property
int counter = m.getIntProperty(FailoverQSender.MESSAGE_COUNTER);
//The counter is set sequentially and must be received in right order.
//Each message is committed after validated.
if (counter != (commitCounter + 1)) {
this.printData();
throw new RuntimeException("validation failed.");
}
log ("messages validated. ready to commit ...");
} catch (JMSException jmse) {
log (jmse);
printData();
throw new RuntimeException("Exception occurred during validation:
" + jmse);
}
}
/**
* Get the message counter and put it in the data holder.
* @param m the current message received
*/
2-35
throws JMSException {
2-36 Open Message Queue 4.5.2 Developer's Guide for Java Clients
Failover Producer Example The following code sample illustrates good coding practices
for handling exceptions during a failover. It is designed to send non-transacted,
persistent messages forever and to handle JMSExceptions when a failover occurs. The
program is able to handle either a true or false setting for the imqReconnectEnabled
property. To run the program enter one of the following commands.
Message Queue Clients: Design and Features
2-37
java dura.example.FailoverProducer
java -DimqReconnectEnabled=true dura.example.FailoverProducer
/*
*
*
*
*
@(#)FailoverProducer.java
1.1 06/06/09
Copyright 2006 Sun Microsystems, Inc. All Rights Reserved
SUN PROPRIETARY/CONFIDENTIAL
Use is subject to license terms. */
package dura.example;
import javax.jms.*;
import com.sun.messaging.ConnectionConfiguration;
import java.util.*;
public class FailoverProducer implements ExceptionListener {
//connection factory
private com.sun.messaging.TopicConnectionFactory factory;
//connection
private TopicConnection pconn = null;
//session
private TopicSession psession = null;
//publisher
private TopicPublisher publisher = null;
//topic
private Topic topic = null;
//This flag indicates whether this test client is closed.
private boolean isClosed = false;
//auto reconnection flag
private boolean autoReconnect = false;
//destination name for this example.
private static final String DURA_TEST_TOPIC = "DuraTestTopic";
//the message counter property name
public static final String MESSAGE_COUNTER = "MESSAGE_COUNTER";
//the message in-doubt-bit property name
public static final String MESSAGE_IN_DOUBT = "MESSAGE_IN_DOUBT";
/**
* Constructor. Get imqReconnectEnabled property value from
* System property.
*/
public FailoverProducer () {
try {
autoReconnect =
Boolean.getBoolean(ConnectionConfiguration.imqReconnectEnabled);
} catch (Exception e) {
this.printException(e);
}
}
/**
* Connection is broken if this handler is called.
* If autoReconnect flag is true, this is called only
* if no more retries from MQ.
*/
public void onException (JMSException jmse) {
2-38 Open Message Queue 4.5.2 Developer's Guide for Java Clients
this.printException (jmse);
}
/**
* create MQ connection factory.
* @throws JMSException
*/
private void initFactory() throws JMSException {
//get connection factory
factory = new com.sun.messaging.TopicConnectionFactory();
}
/**
* JMS setup. Create a Connection,Session, and Producer.
*
* If any of the JMS object creation fails (due to system failure),
* it retries until it succeeds.
*
*/
private void initProducer() {
boolean isConnected = false;
while ( isClosed == false && isConnected == false ) {
try {
println("producer client creating connection ...");
//create connection
pconn = factory.createTopicConnection();
//set connection exception listener
pconn.setExceptionListener(this);
//create topic session
psession = pconn.createTopicSession(false,
Session.CLIENT_ACKNOWLEDGE);
//get destination
topic = psession.createTopic(DURA_TEST_TOPIC);
//publisher
publisher = psession.createPublisher(topic);
//set flag to true
isConnected = true;
println("producer ready.");
}
catch (Exception e) {
println("*** connect failed ... sleep for 5 secs.");
try {
//close resources.
if ( pconn != null ) {
pconn.close();
}
//pause 5 secs.
Thread.sleep(5000);
2-39
2-40 Open Message Queue 4.5.2 Developer's Guide for Java Clients
2-41
}
}
/**
* print the specified exception.
* @param e the exception to be printed.
*/
private void printException (Exception e) {
System.out.println(new Date().toString());
e.printStackTrace();
}
/**
* print the specified message.
* @param msg the message to be printed.
*/
private void println (String msg) {
System.out.println(new Date() + ": " + msg);
}
/**
* Main program to start this example.
*/
public static void main (String args[]) {
FailoverProducer fp = new FailoverProducer();
fp.run();
}
}
java.util.Date;
javax.jms.Destination;
javax.jms.ExceptionListener;
javax.jms.JMSException;
javax.jms.Message;
javax.jms.Connection;
javax.jms.MessageConsumer;
javax.jms.Session;
javax.jms.Topic;
2-42 Open Message Queue 4.5.2 Developer's Guide for Java Clients
import javax.jms.TransactionRolledBackException;
import com.sun.messaging.ConnectionConfiguration;
public class FailoverConsumer implements ExceptionListener, Runnable {
//JMS connection
private Connection conn = null;
//JMS session
private Session session = null;
//JMS Message consumer
private MessageConsumer messageConsumer = null;
//JMS destination.
private Destination destination = null;
//flag indicates whether this program should continue running.
private boolean isConnected = false;
//destination name.
private static final String DURA_TEST_TOPIC = "DuraTestTopic";
//the commit counter, for information only.
private long commitCounter = 0;
/**
* message counter property set by the producer.
*/
public static final String MESSAGE_COUNTER = "MESSAGE_COUNTER";
/**
* Message in doubt bit set by the producer
*/
public static final String MESSAGE_IN_DOUBT = "MESSAGE_IN_DOUBT";
/**
* receive time out
*/
public static final long RECEIVE_TIMEOUT = 0;
/**
* Default constructor * Set up JMS Environment.
*/
public FailoverConsumer() {
setup();
}
/* Connection Exception listener. This is called when connection
* breaks and no reconnect attempts are performed by MQ client runtime.
*/
public void onException (JMSException e) {
print ("Reconnect failed.
/**
* Set this flag to false so that the run() method will exit.
*/
this.isConnected = false;
e.printStackTrace();
}
/**
* Best effort to roll back a jms session.
* open-transaction should be rolled back.
2-43
/**
* Close the JMS connection and exit the program.
*
*/
private void close() {
try {
if ( conn != null ) {
conn.close();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
this.isConnected = false;
}
}
/*Receive messages in a loop until closed.*/
2-44 Open Message Queue 4.5.2 Developer's Guide for Java Clients
2-45
try {
//create connection factory
com.sun.messaging.ConnectionFactory factory =
new com.sun.messaging.ConnectionFactory();
//set auto reconnect to true.
factory.setProperty(ConnectionConfiguration.imqReconnectEnabled,
"true");
//A value of -1 will retry forever if connection is broken.
factory.setProperty(ConnectionConfiguration.imqReconnectAttempts,
"-1");
//retry interval - every 10 seconds
factory.setProperty(ConnectionConfiguration.imqReconnectInterval,
"10000");
//create connection
conn = factory.createConnection();
//set client ID
conn.setClientID(DURA_TEST_TOPIC);
//set exception listener
conn.setExceptionListener(this);
//create a transacted session
session = conn.createSession(true, -1);
//get destination
destination = session.createTopic(DURA_TEST_TOPIC);
//message consumer
messageConsumer = session.createDurableSubscriber((Topic)destination,
DURA_TEST_TOPIC);
//set flag to true
this.isConnected = true;
//we are ready, start the connection
conn.start();
print("<<< Ready to receive on destination: " + DURA_TEST_TOPIC);
} catch (JMSException jmse) {
this.isConnected = false;
jmse.printStackTrace();
this.close();
}
}
/**
* Process the received message message.
* This prints received message counter.
* @param m the message to be processed.
*/
private synchronized void processMessage(Message m) {
try {
//in this example, we do not expect a timeout, etc.
if ( m == null ) {
throw new RuntimeException ("<<< Received null message.
Maybe reached max time out. ");
}
2-46 Open Message Queue 4.5.2 Developer's Guide for Java Clients
2-47
When you compile the resulting code, include both imq.jar and jms.jar in the
class path.
Don't call acknowledge(), acknowledgeThisMessage() , or
acknowledgeUpThroughThisMessage() in any session except one that uses
client-acknowledge mode. Otherwise, the method call is ignored.
Don't use custom acknowledgment in transacted sessions. A transacted session
defines a specific way to have messages acknowledged.
2-48 Open Message Queue 4.5.2 Developer's Guide for Java Clients
If a broker fails, any message that was not acknowledged successfully (that is, any
message whose acknowledgment ended in a JMSException) is held by the broker for
delivery to subsequent clients.
Example 26 demonstrates both types of custom client acknowledgment.
Example 26 Example of Custom Client Acknowledgment Code
...
import javax.jms.*;
...[Look up a connection factory and create a connection.]
Session session = connection.createSession(false,
Session.CLIENT_ACKNOWLEDGE);
...[Create a consumer and receive messages.]
Message message1 = consumer.receive();
Message message2 = consumer.receive();
Message message3 = consumer.receive();
...[Process messages.]
...[Acknowledge one individual message.
Notice that the following acknowledges only message 2.]
((com.sun.messaging.jms.Message)message2).acknowledgeThisMessage();
...[Continue. Receive and process more messages.]
Message message4 = consumer.receive();
Message message5 = consumer.receive();
Message message6 = consumer.receive();
...[Acknowledge all messages up through message 4. Notice that this
acknowledges messages 1, 3, and 4, because message 2 was acknowledged
earlier.]
((com.sun.messaging.jms.Message)message4).acknowledgeUpThroughThisMessage();
...[Continue. Finally, acknowledge all messages consumed in the session.
Notice that this acknowledges all remaining consumed messages, that is,
messages 5 and 6, because this is the standard behavior of the JMS API.]
message5.acknowledge();
2-49
brokers dealing with misbehaving clients who do not acknowledge messages and
therefore tie down broker memory resources unnecessarily. Using this mode has no
effect on producers.
You use this feature by specifying NO_ACKNOWLEDGE for the acknowledgeMode parameter
to the createSession, createQueueSession, or createTopicSession method.
No-acknowledge mode must be used only with the connection methods defined in the
com.sun.messaging.jms package. Note however that the connection itself must be
created using the javax.jms package.
The following are sample variable declarations for connection, queueConnection and
topicConnection:
javax.jms.connection Connection;
javax.jms.queueConnection queueConnection
javax.jms.topicConnection topicConnection
2-50 Open Message Queue 4.5.2 Developer's Guide for Java Clients
Client applications using this feature should upgrade Java SE version to JRE 1.5 or
above.
XML schema validation is enabled using the following physical destination properties:
validateXMLSchemaEnabled, XMLSchemaURIList, and reloadXMLSchemaOnFailure.
These properties are described in "Physical Destination Property Reference" in Open
Message Queue Administration Guide. The property values can be set at destination
creation or update time by using the imqcmd create dst or imqcmd update dst
command, respectively. The XML validation properties should be set when a
destination is inactive: that is, when it has no consumers and producers, and when
there are no messages in the destination.
If any of the XML validation properties are set while a destination is active (for
example, if a producer is connected to the destination), the change will not take effect
until the producer reconnects to the broker. Similarly, if an XSD is changed, as a result
of changing application requirements, all client applications producing XML messages
based on the changed XSD must reconnect to the broker.
If the reloadXMLSchemaOnFailure property is set to true and XML validation fails,
then the Message Queue client runtime will attempt to reload the XSD before
attempting again to validate a message. The client runtime will throw an exception if
the validation fails using the reloaded XSD.
Logging Handlers
Logging Filters
Logging Formatters
2-51
Logging Level
For more information about the Java Logging API, please see the Java Logging
Overview at
http://download.oracle.com/javase/1.4.2/docs/guide/util/logging/
overview.html
Application-defined.
INFO
Application-defined.
CONFIG
Application-defined
FINE
Application-defined.
FINER
Application-defined.
FINEST
Exceptions thrown from the JVM and caught by the client runtime, such as
IOException, are logged by the logger with the logging name space javax.jms at
level WARNING.
JMS exceptions thrown from the client runtime, such as IllegalStateException,
are logged by the logger with the logging name space javax.jms at level FINER.
2-52 Open Message Queue 4.5.2 Developer's Guide for Java Clients
Errors thrown from the JVM and caught by the client runtime, such as
OutOfMemoryError, are logged by the logger with the logging name space
javax.jms at level SEVERE.
The following tables list the events that can be logged and the log level that must be
set to log events for JMS connections and for sessions.
The following table describes log levels and events for connections.
Table 27
Log Level
Events
FINE
Connection created
FINE
Connection started
FINE
Connection closed
FINE
Connection broken
FINE
Connection reconnected
FINER
FINEST
The table below describes log levels and events for sessions.
Table 28
Log Level
Event
FINE
Session created
FINE
Session closed
FINE
Producer created
FINE
Consumer created
FINE
Destination created
FINER
FINEST
Messages produced and consumed. (Message properties and bodies are not
logged in the log records.)
By default, the output log level is inherited from the JRE in which the application is
running. Check the JRE_DIRECTORY/lib/logging.properties file to determine what
that level is.
You can configure logging programmatically or by using configuration files, and you
can control the scope within which logging takes place. The following sections
describe these possibilities.
2-53
# Limit the messages that are printed on the console to INFO and above.
java.util.logging.ConsoleHandler.level = INFO
java.util.logging.ConsoleHandler.formatter =
java.util.logging.SimpleFormatter
# The logger with javax.jms.connection name space will write
# Level.INFO messages to its output handler(s). In this configuration
# the ouput handler is set to java.util.logging.ConsoleHandler.
javax.jms.connection.level = INFO
2-54 Open Message Queue 4.5.2 Developer's Guide for Java Clients
2-55
2-56 Open Message Queue 4.5.2 Developer's Guide for Java Clients
3
The JMS Simplified API
This chapter describes the JMS Simplified API defined by the Java Message Service
(JMS) 2.0 specification and implemented in the Message Queue Java API.
The JMS Classic API offers the same functionality and is
described in The JMS Classic API. For detailed reference information,
see the JavaDoc documentation for each individual class.
Note:
In the Simplified API, the JMSContext combines the behaviors of the Classic API
Connection and Session objects. A Connection continues to represent a physical link
to a JMS server. A Session continues to represent a single-threaded context for
sending or receiving messages. Figure 31 shows an overview of the Simplified API.
3-1
The JMS 2.0 specification is backward compatible with previous JMS specifications.
You can choose the API that best suits your needs. However, the legacy
domain-specific APIs are only provided for compatibility with legacy applications and
are not supported for new application development. Table 21 compares the API
classes for all supported messaging domains.
For more information, see "The Java Message Service specification, version 2.0",
available from http://jcp.org/en/jsr/detail?id=343.
JMSContext
JMSConsumer
QueueBrowser
For example:
. . .
try (JMSContext context = connectionFactory.createContext();){
// use context in this try block
// it will be closed when try block completes
} catch (JMSException e){
// exception handling
}
3-2 Open Message Queue 4.5.2 Developer's Guide for Java Clients
. . .
Use the JMSContext to create the JMSProducer and JMSConsumer objects needed.
See "Java Message Service Examples" in The Java EE 7 Tutorial for additional
information.
3-3
The JMSContext method createContext does not use its underlying session and is
not subject to the single-threading restriction.
The close method on JMSContext or JMSConsumer is not single-threaded since
closing a session or consumer from another thread is permitted.
By default, when createConsumer or createDurableConsumer is used to create a
JMSConsumer, the connection is automatically started. If setMessageListener is
called to configure the asynchronous delivery of messages, the JMSContext's
session immediately becomes dedicated to the thread of control that delivers
messages to the listener. The application must not subsequently call methods on
the JMSContext from another thread of control. However, this restriction does not
apply to applications which call setMessageListener to set a second or
subsequent message listener. The JMS provider is responsible for ensuring that a
second message listener may be safely configured even if the underlying
connection has been started.
See "The JMS API Programming Model" in The Java EE 7 Tutorial for additional
information.
These two types of destination are represented by the Message Queue classes Queue
and Topic, respectively. These, in turn, are both subclasses of the generic class
Destination. A client program that uses the Destination superclass can thus handle
both queue and topic destinations indiscriminately.
See "The JMS API Programming Model" in The Java EE 7 Tutorial for additional
information.
Message Structure
The following section provides information on message structure:
3-4 Open Message Queue 4.5.2 Developer's Guide for Java Clients
Message Headers
Every message must have a header containing identifying and routing information. The
header consists of a set of standard fields, which are defined in the Java Message Service
Specification and summarized in Table 31. Some of these are set automatically by
Message Queue in the course of producing and delivering a message, some depend on
settings specified when a message producer sends a message, and others are set by the
client on a message-by-message basis.
Table 31
Name
Description
JMSMessageID
Message identifier
JMSDestination
JMSReplyTo
JMSCorrelationID
JMSDeliveryMode
JMSDeliveryTime
JMSPriority
Priority level
JMSTimestamp
Time of transmission
JMSExpiration
Expiration time
JMSType
Message type
JMSRedelivered
The JMS Message interface defines the following methods for setting the
corresponding value of each header field. Table 32 lists all of the available header
specification methods for the JMS Message interface.
Table 32
Name
Description
setJMSDestination
Set destination
setJMSReplyTo
setJMSCorrelationID
setJMSCorrelationIDAsBytes
setJMSType
The JMS Producer interface defines the following methods for setting the
corresponding value of each header field. Table 33 lists all of the available header
specification methods.
3-5
Table 33
Name
Description
setJMSMessageID
setJMSDeliveryMode
setJMSPriority
setJMSTimestamp
setJMSExpiration
setJMSRedelivered
setJMSDeliveryTime
See the "Java Message Service specification, version 2.0", available from
http://jcp.org/en/jsr/detail?id=343 for a more detailed discussion of all message
header fields.
Name
Type
Required?
Set by
Description
JMSXUserID
String
Optional
Provider on
Send
JMSXAppID
String
Optional
Provider on
Send
Identity of application
sending message
JMSXDeliveryCount int
Required
Provider on
Receive
Number of delivery
attempts
JMSXGroupID
String
Optional
Client
Identity of message
group to which this
message belongs
JMSXGroupSeq
int
Optional
Client
JMSXProducerTXID
String
Optional
Provider on
Send
Identifier of transaction
within which message
was produced
JMSXConsumerTXID
String
Optional
Provider on
Receive
Identifier of transaction
within which message
was consumed
JMSXRcvTimestamp
long
Optional
Provider on
Receive
JMSXState
int
Optional
Provider
3-6 Open Message Queue 4.5.2 Developer's Guide for Java Clients
Sending Messages
In order to send messages to a message broker, you must create a JMSProducer object
using the createProducer() method on JMSContext. For example:
try (JMSContext context = connectionFactory.createContext();){
context.createProducer().send(inboundQueue,body)
}
The JMS 2.0 specification allows a client to specify a delivery delay value, in
milliseconds, for each message it sends. This value is used to determine a messagess
delivery time which is calculated by adding the delivery delay value specified on the
send to the time the message was sent. See Message Headers.
Table 35 shows the methods defined in the JMSProducer interface.
Table 35
JMSProducer Methods
Name
Description
getDestination
setDeliveryMode
getDeliveryMode
getDeliveryDelay
setDeliveryDelay
setPriority
getPriority
setTimeToLive
getTimeToLive
setDisableMessageID
getDisableMessageID
setDisableMessageTimestamp
getDisableMessageTimestamp
send
Send message
close
3-7
Note: These send methods are the same as methods that are used for
a synchronous send. However, calling setAsync beforehand changes
their behavior.
For more information on how to convert common synchronous send design patterns
to use asynchronous sends, see Asynchronous send.
Receiving Messages
This section provides information on new behaviors and two new subscription types
for clients to use when consuming messages.
Have expired
Shared durable subscriptions are created and a consumer crated on the subscription
using one of the following:
3-8 Open Message Queue 4.5.2 Developer's Guide for Java Clients
Processing Messages
Processing a message after you have received it may entail examining its header fields,
properties, and body.
Table 36
Name
Description
getJMSMessageID
getJMSDestination
Get destination
getJMSReplyTo
getJMSCorrelationID
getJMSCorrelationIDAsBytes
getJMSDeliveryMode
getJMSDeliveryTime
getJMSPriority
getJMSTimestamp
3-9
Description
getJMSExpiration
getJMSType
getJMSRedelivered
3-10 Open Message Queue 4.5.2 Developer's Guide for Java Clients
4
The JMS Classic API
This chapter describes the JMS classic API. The JMS simplified API offers the same
functionality using a simpler implementation and is described in The JMS Simplified
API.
The topics covered include the following:
Messaging Domains
This chapter does not provide exhaustive information about each class and method.
For detailed reference information, see the JavaDoc documentation for each individual
class. For information on the practical design of Message Queue Java programs, see
Message Queue Clients: Design and Features.
Messaging Domains
The Java Message Service (JMS) specification, which Message Queue implements,
supports two commonly used models of interaction between message clients and
message brokers, sometimes known as messaging domains:
In the point-to-point (or PTP) messaging model, each message is delivered from a
message producer to a single message consumer. The producer delivers the
message to a queue, from which it is later delivered to one of the consumers
registered for the queue. Any number of producers and consumers can interact
with the same queue, but each message is guaranteed to be delivered to (and be
successfully consumed by) exactly one consumer and no more. If no consumers
are registered for a queue, it holds the messages it receives and eventually delivers
them when a consumer registers.
In the publish/subscribe (or pub/sub) model, a single message can be delivered from
a producer to any number of consumers. The producer publishes the message to a
topic, from which it is then delivered to all active consumers that have subscribed to
the topic. Any number of producers can publish messages to a given topic, and
each message can be delivered to any number of subscribed consumers. The
model also supports the notion of durable subscriptions, in which a consumer
registered with a topic need not be active at the time a message is published; when
the consumer subsequently becomes active, it will receive the message. If no active
4-1
consumers are registered for a topic, the topic does not hold the messages it
receives unless it has inactive consumers with durable subscriptions.
JMS applications are free to use either of these messaging models, or even to mix them
both within the same application. Historically, the JMS API provided a separate set of
domain-specific object classes for each model. While these domain-specific interfaces
continue to be supported for legacy purposes, client programmers are now
encouraged to use the newer unified domain interface, which supports both models
indiscriminately. For this reason, the discussions and code examples in this manual
focus exclusively on the unified interfaces wherever possible. Table 21 shows the API
classes for all domains.
Sometimes, however, it may be more convenient to dispense with JNDI lookup and
simply create your own connection factory by direct instantiation. Although
hard-coding configuration values for a particular JMS provider directly into your
application code sacrifices flexibility and provider-independence, this approach might
make sense in some circumstances: for example, in the early stages of application
development and debugging, or in applications where reconfigurability and
portability to other providers are not important concerns.
The following sections describe these two approaches to obtaining a connection
factory: by JNDI lookup or direct instantiation.
4-2 Open Message Queue 4.5.2 Developer's Guide for Java Clients
Note:
//
//
Store the environment attributes that tell JNDI which initial context
factory to use and where to find the provider.//
env.put(Context.INITIAL_CONTEXT_FACTORY,
"com.sun.jndi.fscontext.RefFSContextFactory");
env.put(Context.PROVIDER_URL, "file:///C:/imq_admin_objects");
//
//
Create the environment for constructing the initial JNDI naming context.
How you create the initial context depends on whether you are using a file-system
object store or a Lightweight Directory Access Protocol (LDAP) server for your
Message Queue administered objects. The code shown here assumes a file-system
store; for information about the corresponding LDAP object store attributes, see
"Using an LDAP User Repository" in Open Message Queue Administration Guide.
The constructor for the initial context accepts an environment parameter, a hash
table whose entries specify the attributes for creating the context:
Hashtable env = new Hashtable();
You can also set an environment by specifying system properties on the command
line, rather than programmatically. For instructions, see the README file in the JMS
example applications directory.
2.
Store the environment attributes that tell JNDI which initial context factory to use
and where to find the JMS provider.
The names of these attributes are defined as static constants in class Context:
env.put(Context.INITIAL_CONTEXT_FACTORY,
4-3
"com.sun.jndi.fscontext.RefFSContextFactory");
env.put(Context.PROVIDER_URL, "file:///C:/imq_admin_objects");
If you use system properties to set the environment, omit the environment
parameter when creating the context:
Context ctx = new InitialContext();
4.
Look up the connection factory object in the administered object store and typecast
it to the appropriate class:
String CF_LOOKUP_NAME = "MyConnectionFactory";
ConnectionFactory
myFactory = (ConnectionFactory) ctx.lookup(CF_LOOKUP_NAME);
The lookup name you use, CF_LOOKUP_NAME, must match the name used when the
object was stored.
You can now proceed to use the connection factory to create connections to the
message broker, as described under Using Connections.
sets the default password for establishing broker connections. See "Connection Factory
Attributes" in Open Message Queue Administration Guide for complete information on
the available connection factory configuration attributes.
It is also possible to override connection factory properties from the command line, by
using the -D option to set their values when starting your client application. For
example, the command line
java -DimqDefaultPassword=mellon MyMQClient
starts an application named MyMQClient with the same default password as in the
preceding example. Setting a property value this way overrides any other value
specified for it, whether preconfigured in the JNDI object store or set
programmatically with the setProperty method.
4-4 Open Message Queue 4.5.2 Developer's Guide for Java Clients
//
The following procedure explains each program statement in the previous code
sample.
To Instantiate and Configure a Connection Factory Follow this procedure:
1.
Notice that the type declaration for the variable myFactory, to which the
instantiated connection factory is assigned, is also qualified with the full package
name. This is because the setProperty method, used in Instantiating a Connection
Factory, belongs to the ConnectionFactory class defined in the package
com.sun.messaging, rather than to the ConnectionFactory interface defined in
javax.jms . Thus in order for the compiler to recognize this method, myFactory
must be typed explicitly as com.sun.messaging.ConnectionFactory rather than
simply ConnectionFactory (which would resolve to
javax.jms.ConnectionFactory after importing javax.jms.* ).
The JMS Classic API
4-5
2.
When specifying the host name portion of a broker, you can use a literal IPv4 or
IPv6 address instead of a host name. If you use a literal IPv6 address, its format
must conform to RFC2732 (http://www.ietf.org/rfc/rfc2732.txt),
Format for Literal IPv6 Addresses in URL's.
Of course, you can also set any other configuration properties your application
may require. See "Connection Factory Attributes" in Open Message Queue
Administration Guide for a list of the available connection factory attributes.
You can now proceed to use the connection factory to create connections to the
message service, as described in the next section.
Using Connections
Once you have obtained a connection factory, you can use it to create a connection to
the message service. The factory's createConnection method takes a user name and
password as arguments:
Connection
myConnection = myFactory.createConnection("mithrandir", "mellon");
Before granting the connection, Message Queue authenticates the user name and
password by looking them up in its user repository. As a convenience for developers
who do not wish to go to the trouble of populating a user repository during
application development and testing, there is also a parameterless form of the
createConnection method:
Connection myConnection = myFactory.createConnection();
This creates a connection configured for the default user identity, with both user name
and password set to guest.
This unified-domain createConnection method is part of the generic JMS
ConnectionFactory interface, defined in package javax.jms; the Message Queue
version in com.sun.messaging adds corresponding methods createQueueConnection
and createTopicConnection for use specifically with the point-to-point and
publish/subscribe domains.
The following table shows the methods defined in the Connection interface.
Table 41
Connection Methods
Name
Description
createSession
Create session
setClientID
getClientID
4-6 Open Message Queue 4.5.2 Developer's Guide for Java Clients
Description
setEeventListener
setExceptionListener
getExceptionListener
getMetaData
createConnectionConsumer
createDurableConnectionConsumer
start
stop
close
Close connection
The main purpose of a connection is to create sessions for exchanging messages with
the message service:
myConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);
In the event of a problem with the connection, the message broker will call this
method, passing an exception object identifying the nature of the problem.
A connection's getMetaData method returns a ConnectionMetaData object, which in
turn provides methods for obtaining various items of information about the
connection, such as its JMS version and the name and version of the JMS provider.
The createConnectionConsumer and createDurableConnectionConsumer methods (as
well as the session methods setMessageListener and getMessageListener, listed in
Table 42) are used for concurrent message consumption; see the Java Message Service
Specification for more information.
In order to receive incoming messages, you must 7start the connection by calling its
start method:
4-7
myConnection.start();
It is important not to do this until after you have created any message consumers you
will be using to receive messages on the connection. Starting the connection before
creating the consumers risks missing some incoming messages before the consumers
are ready to receive them. It is not necessary to start the connection in order to send
outgoing messages.
If for any reason you need to suspend the flow of incoming messages, you can do so
by calling the connection's stop method:
myConnection.stop();
This automatically closes all sessions, message producers, and message consumers
associated with the connection and deletes any temporary destinations. All pending
message receives are terminated and any transactions in progress are rolled back.
Closing a connection does not force an acknowledgment of client-acknowledged
sessions.
2.
3.
4.
If your client is not using J2SDK 1.4 (which has JSSE and JNDI support built in),
make sure the client has the following files in its class path:jsse.jar, jnet.jar,
jcert, jar, jndi.jar.
2.
Make sure the client has the following Message Queue files in its class path:
imq.jar, jms.jar.
3.
If the client is not willing to trust the broker's self-signed certificate, set the
imqSSLIsHostTrusted attribute to false for the connection factory from which you
get the TLS/SSL connection.
4-8 Open Message Queue 4.5.2 Developer's Guide for Java Clients
4.
Connect to the broker's ssljms service. There are two ways to do this. The first is
to specify the service name ssljms in the address for the broker when you provide
a value for the imqAddressList attribute of the connection factory from which you
obtain the connection. When you run the client, it will be connected to the broker
by a TLS/SSLconnection. The second is to specify the following directive when
you run the command that starts the client.
java -DimqConnectionType=TLS clientAppName
These two types of destination are represented by the Message Queue classes Queue
and Topic, respectively. These, in turn, are both subclasses of the generic class
Destination. A client program that uses the Destination superclass can thus handle
both queue and topic destinations indiscriminately.
Note:
Create the environment for constructing the initial JNDI naming context.
Hashtable env = new Hashtable();
//
//
4-9
env.put(Context.INITIAL_CONTEXT_FACTORY,
"com.sun.jndi.fscontext.RefFSContextFactory");
env.put(Context.PROVIDER_URL, "file:///C:/imq_admin_objects");
//
//
Create the environment for constructing the initial JNDI naming context.
How you create the initial context depends on whether you are using a file-system
object store or a Lightweight Directory Access Protocol (LDAP) server for your
Message Queue administered objects. The code shown here assumes a file-system
store; for information about the corresponding LDAP object store attributes, see
"LDAP Server Object Stores" in Open Message Queue Administration Guide.
The constructor for the initial context accepts an environment parameter, a hash
table whose entries specify the attributes for creating the context:
Hashtable env = new Hashtable();
You can also set an environment by specifying system properties on the command
line, rather than programmatically. For instructions, see the README file in the JMS
example applications directory.
2.
Store the environment attributes that tell JNDI which initial context factory to use
and where to find the JMS provider.
The names of these attributes are defined as static constants in class Context:
env.put(Context.INITIAL_CONTEXT_FACTORY,
"com.sun.jndi.fscontext.RefFSContextFactory");
env.put(Context.PROVIDER_URL, "file:///C:/imq_admin_objects");
If you use system properties to set the environment, omit the environment
parameter when creating the context:
4-10 Open Message Queue 4.5.2 Developer's Guide for Java Clients
Look up the destination object in the administered object store and typecast it to
the appropriate class:
String DEST_LOOKUP_NAME = "MyDest";
Destination MyDest = (Destination) ctx.lookup(DEST_LOOKUP_NAME);
The lookup name you use, DEST_LOOKUP_NAME, must match the name used when
the object was stored. Note that the actual destination object returned from the
object store will always be either a (point-to-point) queue or a (publish/subscribe)
topic, but that either can be assigned to a variable of the generic unified-domain
class Destination.
For topic destinations, a symbolic lookup name that
includes wildcard characters can be used as the lookup string.
Wildcard characters can only be used to match topic names and are
not supported in JNDI names. See "Supported Topic Destination
Names" in Open Message Queue Administration Guide.
Note:
You can now proceed to send and receive messages using the destination, as
described under Sending Messages and Receiving Messages.
Instantiating a Destination
As with connection factories, you may sometimes find it more convenient to dispense
with JNDI lookup and simply create your own queue or topic destination objects by
direct instantiation. Although a variable of type Destination can accept objects of
either class, you cannot directly instantiate a Destination object; the object must
always belong to one of the specific classes Queue or Topic. The constructors for both
of these classes accept a string argument specifying the name of the physical
destination to which the object corresponds:
Destination myDest = new com.sun.messaging.Queue("myDest");
Note, however, that this only creates a Java object representing the destination; it does
not actually create a physical destination on the message broker. The physical
destination itself must still be created by a Message Queue administrator, with the
same name you pass to the constructor when instantiating the object.
Note: Destination names beginning with the letters mq are
reserved and should not be used by client programs.
Temporary Destinations
A temporary destination is one that exists only for the duration of the connection that
created it. You may sometimes find it convenient to create such a destination to use,
for example, as a reply destination for messages you send. Temporary destinations are
created with the session method createTemporaryQueue or createTemporaryTopic
(see Working With Sessions below): for example,
TemporaryQueue tempQueue = mySession.createTemporaryQueue();
Session Methods
Name
Description
createProducer
createConsumer
createDurableSubscriber
unsubscribe
createMessage
createTextMessage
createStreamMessage
createMapMessage
createObjectMessage
4-12 Open Message Queue 4.5.2 Developer's Guide for Java Clients
Description
createBytesMessage
createQueue
createTopic
createTemporaryQueue
createTemporaryTopic
createBrowser
setMessageListener
getMessageListener
getAcknowledgeMode
getTransacted
Is session transacted?
commit
Commit transaction
rollback
recover
close
Close session
Every session exists within the context of a particular connection. The number of
sessions you can create for a single connection is limited only by system resources. As
described earlier (see Using Connections), you use the connection's createSession
method to create a session:
Session
mySession = myConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);
The first (boolean) argument specifies whether the session is transacted; see Transacted
Sessions for further discussion. The second argument is an integer constant
representing the session's acknowledgment mode, as described in the next section.
Acknowledgment Modes
A session's acknowledgment mode determines the way your application handles the
exchange of acknowledgment information when receiving messages from a broker.
The JMS specification defines three possible acknowledgment modes:
The standard JMS Session interface, defined in package javax.jms, defines static
constants for the first three acknowledgment modes (AUTO_ACKNOWLEDGE, CLIENT_
ACKNOWLEDGE, and DUPS_OK_ACKNOWLEDGE), to be used as arguments to the connection's
createSession method. The constant representing the fourth mode (NO_ACKNOWLEDGE)
is defined in the extended Message Queue version of the interface, in package
com.sun.messaging.jms. The session method getAcknowledgeMode returns one of
these constants:
int ackMode = mySession.getAcknowledgeMode();
switch (ackMode)
{
case Session.AUTO_ACKNOWLEDGE:
/* Code here to handle auto-acknowledge mode */
break;
case Session.CLIENT_ACKNOWLEDGE:
/* Code here to handle client-acknowledge mode */
break;
case Session.DUPS_OK_ACKNOWLEDGE:
/* Code here to handle dups-OK-acknowledge mode */
break;
case com.sun.messaging.jms.Session.NO_ACKNOWLEDGE:
/* Code here to handle no-acknowledge mode */
break;
}
Note:
4-14 Open Message Queue 4.5.2 Developer's Guide for Java Clients
In a transacted session (see next section), the acknowledgment mode is ignored and all
acknowledgment processing is handled for you automatically by the Message Queue
client runtime. In this case, the getAcknowledgeMode method returns the special
constant Session.SESSION_TRANSACTED.
Transacted Sessions
Transactions allow you to group together an entire series of incoming and outgoing
messages and treat them as an atomic unit. The message broker tracks the state of the
transaction's individual messages, but does not complete their delivery until you
commit the transaction. In the event of failure, you can roll back the transaction,
canceling all of its messages and restarting the entire series from the beginning.
Transactions always take place within the context of a single session. To use them, you
must create a transacted session by passing true as the first argument to a connection's
createSession method:
Session
mySession = myConnection.createSession(true, Session.SESSION_TRANSACTED);
A transacted session always has exactly one open transaction, encompassing all
messages sent or received since the session was created or the previous transaction
was completed. Committing or rolling back a transaction ends that transaction and
automatically begins another.
Because the scope of a transaction is limited to a single
session, it is not possible to combine the production and
consumption of a message into a single end-to-end transaction.
That is, the delivery of a message from a message producer to a
destination on the broker cannot be placed in the same transaction
with its subsequent delivery from the destination to a consumer.
Note:
When all messages in a transaction have been successfully delivered, you call the
session's commit method to commit the transaction:
mySession.commit();
All of the session's incoming messages are acknowledged and all of its outgoing
messages are sent. The transaction is then considered complete and a new one is
started.
When a send or receive operation fails, an exception is thrown. While it is possible to
handle the exception by simply ignoring it or by retrying the operation, it is
recommended that you roll back the transaction, using the session's rollback method:
mySession.rollback();
All of the session's incoming messages are recovered and redelivered, and its outgoing
messages are destroyed and must be re-sent.
Message Structure
A message consists of the following parts:
Message Header
Every message must have a header containing identifying and routing information. The
header consists of a set of standard fields, which are defined in the Java Message Service
Specification and summarized in Table 43. Some of these are set automatically by
Message Queue in the course of producing and delivering a message, some depend on
settings specified when a message producer sends a message, and others are set by the
client on a message-by-message basis.
Table 43
Name
Description
JMSMessageID
Message identifier
JMSDestination
JMSReplyTo
JMSCorrelationID
JMSDeliveryMode
JMSDeliveryTime
JMSPriority
Priority level
JMSTimestamp
Time of transmission
JMSExpiration
Expiration time
JMSType
Message type
JMSRedelivered
The JMS Message interface defines methods for setting the value of each header field:
for instance,
outMsg.setJMSReplyTo(replyDest);
Name
Description
setJMSMessageID
4-16 Open Message Queue 4.5.2 Developer's Guide for Java Clients
Description
setJMSDestination
Set destination
setJMSReplyTo
setJMSCorrelationID
setJMSCorrelationIDAsBytes
setJMSDeliveryMode
setJMSPriority
setJMSTimestamp
setJMSExpiration
setJMSType
setJMSRedelivered
In persistent mode, the broker logs the message to stable storage, ensuring that it
will not be lost in transit in the event of transmission failure; the message is
guaranteed to be delivered exactly once.
In nonpersistent mode, the message is not logged to stable storage; it will be
delivered at most once, but may be lost in case of failure and not delivered at all.
This mode does, however, improve performance by reducing the broker's
message-handling overhead. It may thus be appropriate for applications in which
performance is at a premium and reliability is not.
Message Properties
A message property consists of a name string and an associated value, which must be
either a string or one of the standard Java primitive data types (int, byte, short, long,
float, double, or boolean). The Message interface provides methods for setting
properties of each type (see Table 45). There is also a setObjectProperty method that
accepts a primitive value in objectified form, as a Java object of class Integer, Byte,
Short, Long, Float , Double, Boolean, or String . The clearProperties method deletes
all properties associated with a message; the message header and body are not
affected.
Table 45
Name
Description
setIntProperty
setByteProperty
setShortProperty
setLongProperty
setFloatProperty
setDoubleProperty
setBooleanProperty
setStringProperty
setObjectProperty
clearProperties
Clear properties
4-18 Open Message Queue 4.5.2 Developer's Guide for Java Clients
The JMS specification defines certain standard properties, listed in Table 46. By
convention, the names of all such standard properties begin with the letters JMSX;
names of this form are reserved and must not be used by a client application for its
own custom message properties. These properties are not enabled by default, an
application must set the name/value pairs it requires on the appropriate connection
factory.
Table 46
Name
Type
Required?
Description
JMSXUserID
String
Optional
JMSXAppID
String
Optional
JMSXDeliveryCoun
t
int
Optional
JMSXGroupID
String
Optional
JMSXGroupSeq
int
Optional
JMSXProducerTXID
String
Optional
JMSXConsumerTXID
String
Optional
JMSXRcvTimestamp
long
Optional
JMSXState
int
Optional
Message Body
The actual content of a message is contained in the message body. JMS defines six
classes (or types) of message, each with a different body format:
Composing Messages
The JMS Session interface provides methods for creating each type of message, as
shown in Table 47. For instance, you can create a text message with a statement such
as
TextMessage outMsg = mySession.createTextMessage();
In general, these methods create a message with an empty body; the interfaces for
specific message types then provide additional methods for filling the body with
content, as described in the sections that follow.
Table 47
Name
Description
createMessage
createTextMessage
createStreamMessage
createMapMessage
createObjectMessage
createBytesMessage
Note:
TextMessage
outMsg = mySession.createTextMessage("Hello, World!");
This places the message in the same state as if it had been newly created, ready to fill
its body with new content.
or simply create an empty message and then use its setText method (see Table 48) to
set its content:
TextMessage outMsg = mySession.createTextMessage();
outMsg.setText("Hello, World!");
4-20 Open Message Queue 4.5.2 Developer's Guide for Java Clients
Table 48
Name
Description
setText
Table 49
Name
Description
writeInt
writeByte
writeBytes
writeShort
writeLong
writeFloat
writeDouble
writeBoolean
writeChar
writeString
writeObject
reset
As a convenience for handling values whose types are not known until execution time,
the writeObject method accepts a string or an objectified primitive value of class
Integer, Byte, Short, Long, Float, Double , Boolean, or Character and writes the
corresponding string or primitive value to the message stream: for example, the
statements
Integer meaningOfLife = new Integer(42);
outMsg.writeObject(meaningOfLife);
are equivalent to
outMsg.writeInt(42);
puts the message body in read-only mode and repositions the stream to the beginning,
ready to read (see Processing Messages). When the message is in this state, any
Table 410
Name
Description
setInt
setByte
setBytes
setShort
setLong
setFloat
setDouble
setBoolean
setChar
setString
setObject
Like stream messages, map messages provide a convenience method (setObject) for
dealing with values whose type is determined dynamically at execution time: for
example, the statements
Integer meaningOfLife = new Integer(42);
outMsg.setObject("The Meaning of Life", meaningOfLife);
are equivalent to
outMsg.setInt("The Meaning of Life", 42);
The object supplied must be either a string object (class String) or an objectified
primitive value of class Integer, Byte , Short, Long, Float, Double, Boolean, or
Character; otherwise an exception (MessageFormatException) will be thrown.
4-22 Open Message Queue 4.5.2 Developer's Guide for Java Clients
The argument to this method can be any serializable object (that is, an instance of any
class that implements the standard Java interface Serializable). If the object is not
serializable, the exception MessageFormatException will be thrown.
Table 411
Name
Description
setObject
As an alternative, you can initialize the message body directly when you create the
message, by passing an object to the session method createObjectMessage:
ObjectMessage outMsg = mySession.createObjectMessage(bodyObject);
Table 412
Name
Description
writeInt
writeByte
writeBytes
writeShort
writeLong
writeFloat
writeDouble
writeBoolean
writeChar
writeUTF
writeObject
reset
As with stream and map messages, you can use the generic object-based method
writeObject to handle values whose type is unknown at compilation time: for
example, the statements
The JMS Classic API 4-23
are equivalent to
outMsg.writeInt(42);
puts the message body in read-only mode and repositions the byte stream to the
beginning, ready to read (see Processing Messages). Attempting to write further
content to a message in this state will cause an exception
(MessageNotWriteableException). The inherited Message method clearBody can be
used to delete the entire message body and make it writeable again.
Sending Messages
In order to send messages to a message broker, you must create a message producer
using the session method createProducer:
MessageProducer myProducer = mySession.createProducer(myDest);
The scope of the message producer is limited to the session that created it and the
connection to which that session belongs. Table 413 shows the methods defined in the
MessageProducer interface.
Table 413
Name
Description
getDestination
setDeliveryMode
getDeliveryMode
setPriority
getPriority
setTimeToLive
getTimeToLive
setDisableMessageID
getDisableMessageID
setDisableMessageTimestamp
getDisableMessageTimestamp
send
Send message
close
in which case you must specify an explicit destination for each message. This option is
typically used for producers that must send messages to a variety of destinations, such
as those designated in the JMSReplyTo header fields of incoming messages (see
Message Header).
Note: The generic MessageProducer interface also has specialized
subinterfaces, QueueSender and TopicPublisher, for sending
messages specifically to a point-to-point queue or a
publish/subscribe topic. These types of producer are created by the
createSender and createPublisher methods of the specialized
session subinterfaces QueueSession and TopicSession,
respectively. However, it is generally more convenient (and
recommended) to use the generic form of message producer
described here, which can handle both types of destination
indiscriminately.
This sends the specified message to the producer's default destination, using the
producer's default delivery mode, priority, and message lifetime. Alternatively, you
can explicitly specify the destination
myProducer.send(myDest, outMsg);
Recall that if you did not specify a destination when creating the message producer,
you must provide an explicit destination for each message you send.
As discussed earlier under Message Header, client applications that have no need for
the message identifier and time stamp fields in the message header can gain some
performance improvement by suppressing the generation of these fields, using the
message producer's setDisableMessageID and setdisableMessageTimestamp
methods. Note that a true value for either of these flags disables the generation of the
corresponding header field, while a false value enables it. Both flags are set to false
by default, meaning that the broker will generate the values of these header fields
unless explicitly instructed otherwise.
When you are finished using a message producer, you should call its close method
myProducer.close();
allowing the broker and client runtime to release any resources they may have
allocated on the producer's behalf.
Asynchronous send
The JMS 2.0 specification allows clients to send a message asynchronously. This
permits the JMS provider to perform part of the work involved in sending the message
in a separate thread.
When a message has been successfully sent, the JMS provider invokes the callback
method onCompletion on an application-specified CompletionListener object. Only
when that callback has been invoked can the application be sure that the message has
been successfully sent with the same degree of confidence as if a synchronous send
had been performed. An application which requires this degree of confidence must
wait for the callback to be invoked before continuing.
The following section provides guidelines on how to convert two common
synchronous send design patterns to use asynchronous sends.
A producer sends messages using a synchronous send to a remote JMS server and
then waits for an acknowledgement to be received before returning.
A producer implements an asynchronous send by sending the message to the
remote JMS server and then returning without waiting for an acknowledgement.
When the acknowledgement is received, the JMS provider would notify the
application by invoking the onCompletion method on the application-specified
CompletionListener object. If for some reason the acknowledgement is not
received, the JMS provider would notify the application by invoking
CompletionListener.onException.
A producer sends messages using a synchronous send to a remote JMS server and
does not wait for an acknowledgement to be received before returning.
A producer implements an asynchronous send by sending the message to the
remote JMS server and then return without waiting for an acknowledgement. The
JMS provider then notifies the application that the send had completed by
invoking the onCompletion method on the application-specified
CompletionListener object.
4-26 Open Message Queue 4.5.2 Developer's Guide for Java Clients
Receiving Messages
Messages are received by a message consumer, within the context of a connection and a
session. Once you have created a consumer, you can use it to receive messages in
either of two ways:
These two forms of message consumption are described in the sections Receiving
Messages Synchronously and Receiving Messages Asynchronously.
If the destination is a queue, the consumer is called a receiver for that queue; if it is a
topic, the consumer is a subscriber to that topic.
Note: The generic MessageConsumer interface also has specialized
subinterfaces, QueueReceiver and TopicSubscriber, for receiving
messages specifically from a point-to-point queue or a
publish/subscribe topic. These types of consumer are created by
the createReceiver and createSubscriber methods of the
specialized session subinterfaces QueueSession and TopicSession,
respectively. However, it is generally more convenient (and
recommended) to use the generic form of message consumer
described here, which can handle both types of destination
indiscriminately.
A subscriber created for a topic destination with the createConsumer method is always
nondurable, meaning that it will receive only messages that are sent (published)to the
topic while the subscriber is active. If you want the broker to retain messages
published to a topic while no subscriber is active and deliver them when one becomes
active again, you must instead create a durable subscriber, as described in Durable
Subscribers.
Table 414 shows the methods defined in the MessageConsumer interface, which are
discussed in detail in the relevant sections below.
Table 414
Name
Description
getMessageSelector
receive
receiveNoWait
setMessageListener
getMessageListener
Description
close
Message Selectors If appropriate, you can restrict the messages a consumer will receive
from its destination by supplying a message selector as an argument when you create
the consumer:
String mySelector = "/* Text of selector here */";
MessageConsumer myConsumer = mySession.createConsumer(myDest, mySelector);
The selector is a string whose syntax is based on a subset of the SQL92 conditional
expression syntax, which allows you to filter the messages you receive based on the
values of their properties (see Message Properties). See the Java Message Service
Specification for a complete description of this syntax. The message consumer's
getMessageSelector method returns the consumer's selector string (or null if no
selector was specified when the consumer was created):
String mySelector = myConsumer.getMessageSelector();
Note:
In some cases, the same connection may both publish and subscribe to the same topic
destination. The createConsumer method accepts an optional boolean argument that
suppresses the delivery of messages published by the consumer's own connection:
String mySelector = "/* Text of selector here */";
MessageConsumer
myConsumer = mySession.createConsumer(myDest, mySelector, true);
4-28 Open Message Queue 4.5.2 Developer's Guide for Java Clients
When a message arrives for the topic and no message consumer is currently active for
it, the message will be retained for later delivery. Whenever you create a consumer
with the given client identifier and subscriber name, it will be considered to represent
this same durable subscriber and will receive all of the accumulated messages that
have arrived for the topic in the subscriber's absence. Each message is retained until it
is delivered to (and acknowledged by) such a consumer or until it expires.
Only one session at a time can have an active consumer for
a given durable subscription. If another such consumer already
exists, the createDurableSubscriber method will throw an
exception.
Note:
Like the createConsumer method described in the preceding section (which creates
nondurable subscribers), createDurableSubscriber can accept an optional message
selector string and a boolean argument telling whether to suppress the delivery of
messages published by the subscriber's own connection:
String mySelector = "/* Text of selector here */";
MessageConsumer myConsumer
= mySession.createDurableSubscriber(myDest, "mySub",
mySelector, true);
You can change the terms of a durable subscription by creating a new subscriber with
the same client identifier and subscription name but with a different topic, selector, or
both. The effect is as if the old subscription were destroyed and a new one created with
the same name. When you no longer need a durable subscription, you can destroy it
with the session method unsubscribe:
mySession.unsubscribe("mySub");
(Note that it is not necessary to start a connection in order to produce messages, only
to consume them.) You can then use the consumer's receive method to receive
messages synchronously from the message broker:
Message inMsg = myConsumer.receive();
This returns the next available message for this consumer. If no message is
immediately available, the receive method blocks until one arrives. You can also
provide a timeout interval in milliseconds:
Message inMsg = myConsumer.receive(1000);
In this case, if no message arrives before the specified timeout interval (1 second in the
example) expires, the method will return with a null result. An alternative method,
receiveNoWait, returns a null result immediately if no message is currently available:
Message inMsg = myConsumer.receiveNoWait();
2.
3.
4.
5.
Once the connection is started, the Message Queue client runtime will call your
message listener's onMessage method each time it has a message to deliver to this
consumer.
To ensure that no messages are lost before your consumer is ready to receive them,
it is important not to start the connection until after you have created the message
listener and associated it with the consumer. If the connection is already started,
you should stop it before creating an asynchronous consumer, then start it again
when the consumer is ready to begin processing.
Setting a consumer's message listener to null removes any message listener
previously associated with it:
myConsumer.setMessageListener(null);
Acknowledging Messages
If you have specified client-acknowledge as your session's acknowledgment mode (see
Acknowledgment Modes), it is your client application's responsibility to explicitly
acknowledge each message it receives. If you have received the message
synchronously, using a message consumer's receive (or receiveNoWait) method, you
should process the message first and then acknowledge it; if you have received it
asynchronously, your message listener's onMessage method should acknowledge the
message after processing it. This ensures that the message broker will not delete the
message from persistent storage until processing is complete.
Note: In a transacted session (see Transacted Sessions), there is no
need to acknowledge a message explicitly: the session's
acknowledgment mode is ignored and all acknowledgment
processing is handled for you automatically by the Message Queue
client runtime. In this case, the session's getAcknowledgeMode
method will return the special constant Session.SESSION_
TRANSACTED.
Table 415 shows the methods available for acknowledging a message. The most
general is acknowledge, defined in the standard JMS interface javax.jms.Message:
inMsg.acknowledge();
Function
Description
acknowledge
acknowledgeThisMessage
acknowledgeUpThroughThisMessage
The Message Queue version of the Message interface, defined in the package
com.sun.messaging.jms, adds two more methods that provide more flexible control
over which messages you acknowledge. The acknowledgeThisMessage method just
acknowledges the single message for which it is called, rather than all messages
consumed by the session; acknowledgeUpThroughThisMessage acknowledges the
message for which it is called and all previous messages; messages received after that
message remain unacknowledged.
Browsing Messages
If the destination from which you are consuming messages is a point-to-point queue,
you can use a queue browser to examine the messages in the queue without consuming
them. The session method createBrowser creates a browser for a specified queue:
QueueBrowser myBrowser = mySession.createBrowser(myDest);
The JMS Classic API 4-31
Table 416 shows the methods defined in the QueueBrowser interface. The getQueue
and getMessageSelector methods return the browser's queue and selector string,
respectively.
Table 416
Name
Description
getQueue
getMessageSelector
getEnumeration
close
Close browser
The most important queue browser method is getEnumeration, which returns a Java
enumeration object that you can use to iterate through the messages in the queue, as
shown in Example 44.
Example 44 Browsing a Queue
Enumeration
Message
queueMessages = myBrowser.getEnumeration();
eachMessage;
while ( queueMessages.hasMoreElements() )
{ eachMessage = queueMessages.nextElement();
/* Do something with the message */
}
The browser's close method closes it when you're through with it:
myBrowser.close();
Closing a Consumer
As a matter of good programming practice, you should close a message consumer
when you have no further need for it. Closing a session or connection automatically
closes all consumers associated with it; to close a consumer without closing the session
or connection to which it belongs, you can use its close method:
myConsumer.close();
For a consumer that is a nondurable topic subscriber, this terminates the flow of
messages to the consumer. However, if the consumer is a queue receiver or a durable
topic subscriber, messages will continue to be accumulated for the destination and will
be delivered the next time a consumer for that destination becomes active. To
terminate a durable subscription permanently, call its session's unsubscribe method
with the subscriber name as an argument:
mySession.unsubscribe("mySub");
4-32 Open Message Queue 4.5.2 Developer's Guide for Java Clients
Processing Messages
Processing a message after you have received it may entail examining its header fields,
properties, and body. The following sections describe how this is done.
Table 417
Name
Description
getJMSMessageID
getJMSDestination
Get destination
getJMSReplyTo
getJMSCorrelationID
getJMSCorrelationIDAsBytes
getJMSDeliveryMode
getJMSPriority
getJMSTimestamp
getJMSExpiration
getJMSType
getJMSRedelivered
timeStamp = inMsg.getLongProperty("JMSXRcvTimestamp");
Table 418
Name
Description
getIntProperty
getByteProperty
getShortProperty
getLongProperty
getFloatProperty
getDoubleProperty
getBooleanProperty
getStringProperty
Description
getObjectProperty
getPropertyNames
propertyExists
timeStampObject = (Long)inMsg.getObjectProperty("JMSXRcvTimestamp");
timeStamp = timeStampObject.longValue();
If the message has no property with the requested name, getObjectProperty will
return null; the message method propertyExists tests whether this is the case.
The getPropertyNames method returns a Java enumeration object for iterating through
all of the property names associated with a given message; you can then use the
retrieval methods shown in the table to retrieve each of the properties by name, as
shown in Example 45.
Example 45 Enumerating Message Properties
Enumeration
String
Object
propNames = inMsg.getPropertyNames();
eachName;
eachValue;
while ( propNames.hasMoreElements() )
{ eachName = propNames.nextElement();
eachValue = inMsg.getObjectProperty(eachName);
/* Do something with the value */
}
Table 419
Name
Description
getText
Name
Description
readInt
readByte
readBytes
readShort
readLong
readFloat
readDouble
readBoolean
readChar
readString
readObject
The readObject method returns the next value from the message stream in objectified
form, as a Java object of the class corresponding to the value's primitive data type: for
instance, if the value is of type int, readObject returns an object of class Integer. The
following statements are equivalent to the one shown above:
Integer
int
Processing Map Messages The MapMessage interface provides the methods shown in
Table 421 for reading the body of a map message. Each access method takes a name
string as an argument and returns the value to which that name is mapped: for
instance, under the example shown in Composing Map Messages, the statement
int meaningOfLife = inMsg.getInt("The Meaning of Life");
Name
Description
getInt
getByte
getBytes
getShort
getLong
getFloat
getDouble
getBoolean
getChar
Description
getString
getObject
itemExists
getMapNames
Like stream messages, map messages provide an access method, getObject, that
returns a value from the map in objectified form, as a Java object of the class
corresponding to the value's primitive data type: for instance, if the value is of type
int, getObject returns an object of class Integer. The following statements are
equivalent to the one shown above:
Integer
int
The itemExists method returns a boolean value indicating whether the message map
contains an association for a given name string:
if ( inMsg.itemExists("The Meaning of Life") )
{ /* Life is meaningful */
}
else
{ /* Life is meaningless */
}
The getMapNames method returns a Java enumeration object for iterating through all of
the names defined in the map; you can then use getObject to retrieve the
corresponding values, as shown in Example 46.
Example 46 Enumerating Map Message Values
Enumeration
String
Object
mapNames = inMsg.getMapNames();
eachName;
eachValue;
while ( mapNames.hasMoreElements() )
{ eachName = mapNames.nextElement();
eachValue = inMsg.getObject(eachName);
/* Do something with the value */
}
Processing Object Messages The ObjectMessage interface provides just one method,
getObject (Table 422), for retrieving the serialized object that is the body of an object
message:
Object messageBody = inMsg.getObject();
You can then typecast the result to a more specific class and process it in whatever way
is appropriate.
4-36 Open Message Queue 4.5.2 Developer's Guide for Java Clients
Table 422
Name
Description
getObject
Processing Bytes Messages The body of a bytes message simply consists of a stream of
uninterpreted bytes; its interpretation is entirely a matter of agreement between sender
and receiver. This type of message is intended primarily for decoding message formats
used by other existing message systems; Message Queue clients should generally use
one of the other, more specific message types instead.
Reading the body of a bytes message is similar to reading a stream message (see
Processing Stream Messages): you use the methods shown in Table 423 to decode
primitive values from the message's byte stream. For example, the statement
int intVal = inMsg.readInt();
retrieves an integer value from the byte stream. The getBodyLength method returns
the length of the entire message body in bytes:
int bodyLength = inMsg.getBodyLength();
Table 423
Name
Description
getBodyLength
readInt
readByte
readUnsignedByte
readBytes
readShort
readUnsignedShort
readLong
readFloat
readDouble
readBoolean
readChar
readUTF
Connection
Session
MessageProducer
MessageConsumer
QueueBrowser
For example:
. . .
try (Connection connection = connectionFactory.createConnection();){
// use connection in this try block
// it will be closed when try block completes
} catch (JMSException e){
// exception handling
}
. . .
4-38 Open Message Queue 4.5.2 Developer's Guide for Java Clients
5
Using the Metrics Monitoring API
Monitoring Overview
Monitoring Overview
Message Queue includes an internal client that is enabled by default to produce
different types of metrics messages. Production is actually enabled when a client
subscribes to a topic destination whose name matches one of the metrics message
types. For example, if a client subscribes to the topic mq.metrics.jvm, the client
receives information about JMV memory usage.
The metrics topic destinations (metric message types) are described in Table 51.
5-1
Monitoring Overview
Table 51
mq.metrics.broker
mq.metrics.jvm
mq.metrics.destination_list
mq.metrics.destination.queue.dn
mq.metrics.destination.topic.dn
The message header has several properties, one that specifies the metrics message
type, one that records the time the message was produced (timestamp), and a
collection of properties identifying the broker that sent the metric message (broker
host, port, and address/URL).
The message body contains name-value pairs that vary with the message type.
The section Format of Metrics Messages provides complete information about the
types of metrics messages and their content (name-value pairs).
Administrative Tasks
By default the Message Queue metrics-message producing client is enabled to produce
nonpersistent messages every sixty seconds. The messages are allowed to remain in
their respective destinations for 5 minutes before being automatically deleted. To
persist metrics messages, to change the interval at which they are produced, or to
change their time-to-live interval, the administrator must set the following properties
in the config.properties file: imq.metrics.topic.persist ,
imq.metrics.topic.interval, and imq.metrics.topic.timetolive .
In addition, the administrator might want to set access controls on the metrics
destinations. This restricts access to sensitive metrics data and helps limit the impact of
metrics subscriptions on overall performance. For more information about
administrative tasks in enabling message-based monitoring and access control, see
"Using the Message-Based Monitoring API" in Open Message Queue Administration
Guide.
5-2 Open Message Queue 4.5.2 Developer's Guide for Java Clients
Implementation Summary
The following task list summarizes the steps required to implement message based
monitoring:
The developer designs and writes a client that subscribes to one or more metrics
destinations.
2.
3.
4.
2.
3.
Create a TopicSession.
4.
5.
Create a TopicSubscriber.
6.
7.
5-3
MapMessage mapMsg;
/*
* mapMsg is the metrics message received
*/
String type = mapMsg.getStringProperty("type");
long timestamp = mapMsg.getLongProperty("timestamp");
You use the appropriate get method in the class javax.jms.MapMessage to extract
the name-value pairs. The get method you use depends on the value type. Three
examples follow:
long value1 = mapMsg.getLong("numMsgsIn");
long value2 = mapMsg.getLong("numMsgsOut");
int value3 = mapMsg.getInt("diskUtilizationRatio");
The message header has properties that are useful to applications. The type
property identifies the type of metric message (and therefore its contents). It is
useful if the same subscriber processes more than one type of metrics message for
example, messages from the topics mq.metrics.broker and mq.metrics.jvm. The
timestamp property indicates when the metric sample was taken and is useful for
calculating rates or drawing graphs. The brokerHost, brokerPort, and
brokerAddress properties identify the broker that sent the metric message and are
useful when a single application needs to process metric messages from different
brokers.
The body of the message contains name-value pairs, and the data values depend
on the type of metrics message. The following subsections describe the format of
each metrics message type.
Note that the names of name-value pairs (used in code to extract data) are
case-sensitive and must be coded exactly as shown. For example, NumMsgsOut is
incorrect; numMsgsOut is correct.
Broker Metrics
The messages you receive when you subscribe to the topic mq.metrics.broker have
the type property set to mq.metrics.broker in the message header and have the data
listed in Table 52 in the message body.
Table 52
Metric Name
numConnections
long
numMsgsIn
long
numMsgsOut
long
5-4 Open Message Queue 4.5.2 Developer's Guide for Java Clients
numMsgs
long
msgBytesIn
long
msgBytesOut
long
totalMsgBytes
long
numPktsIn
long
numPktsOut
long
pktBytesIn
long
Number of packet bytes that have flowed into the broker since
it was last started; this includes both JMS messages and
control messages
pktBytesOut
long
numDestinations long
JVM Metrics
The messages you receive when you subscribe to the topic mq.metrics.jvm have the
type property set to mq.metrics.jvm in the message header and have the data listed in
Table 53 in the message body.
Table 53
Metric Name
Value Type
Description
freeMemory
long
maxMemory
long
totalMemory
long
Destination-List Metrics
The messages you receive when you subscribe to a topic named
mq.metrics.destination_list have the type property set to
mq.metrics.destination_list in the message header.
The message body contains a list of map names. Each destination on the broker is
specified by a unique map name (a name-value pair) in the message body. The type of
the name-value pair is hashtable.
The name (in the name-value pair) depends on whether the destination is a queue or a
topic, and is constructed as follows:
5-5
mq.metrics.destination.queue.monitored_destination_name
mq.metrics.destination.topic.monitored_destination_name
The value (in the name-value pair) is an object of type java.util.Hashtable . This
hashtable contains the key-value pairs described in Table 54.
Table 54
Key (String)
Value type
Value or Description
name
String
Destination name
type
String
isTemporary
Boolean
Is destination temporary?
Notice that the destination name and type could be extracted directly from the metrics
topic destination name, but the hashtable includes it for your convenience.
By enumerating through the map names and extracting the hashtable described in
Table 54, you can form a complete list of destination names and some of their
characteristics.
The destination list does not include the following kinds of destinations:
Destinations that the Message Queue broker creates for internal use
Destination Metrics
The messages you receive when you subscribe to the topic
mq.metrics.destination.queue.monitored_destination_name have the type property
mq.metrics.destination.queue.monitored_destination_name set in the message
header. The messages you receive when you subscribe to the topic
mq.metrics.destination.topic.monitored_destination_name have the type property
mq.metrics.destination.topic. monitored_destination_name set in the message
header. Either of these messages has the data listed in Table 55 in the message body.
Table 55
Metric Name
numActiveConsumers
long
avgNumActiveConsumers
long
peakNumActiveConsumers
long
numBackupConsumers
long
avgNumBackupConsumers
long
peakNumBackupConsumers
long
numMsgsIn
long
5-6 Open Message Queue 4.5.2 Developer's Guide for Java Clients
numMsgsOut
long
numMsgs
long
avgNumMsgs
long
peakNumMsgs
long
msgBytesIn
long
msgBytesOut
long
totalMsgBytes
long
avgTotalMsgBytes
long
peakTotalMsgBytes
long
peakMsgBytes
long
diskReserved
long
diskUsed
long
diskUtilizationRatio
int
5-7
Notice that in the source files, the code for subscribing to metrics topics and processing
messages is actually spread across various methods. However, for the sake of clarity,
the examples are shown here as though they were contiguous blocks of code.
}
private void doTotals(MapMessage mapMsg) {
try {
String oneRow[] = new String[ 8 ];
int i = 0;
/*
* Extract broker metrics
*/
oneRow[i++] = Long.toString(mapMsg.getLong("numMsgsIn"));
5-8 Open Message Queue 4.5.2 Developer's Guide for Java Clients
oneRow[i++] = Long.toString(mapMsg.getLong("numMsgsOut"));
oneRow[i++] = Long.toString(mapMsg.getLong("msgBytesIn"));
oneRow[i++] = Long.toString(mapMsg.getLong("msgBytesOut"));
oneRow[i++] = Long.toString(mapMsg.getLong("numPktsIn"));
oneRow[i++] = Long.toString(mapMsg.getLong("numPktsOut"));
oneRow[i++] = Long.toString(mapMsg.getLong("pktBytesIn"));
oneRow[i++] = Long.toString(mapMsg.getLong("pktBytesOut"));
...
} catch (Exception e) {
System.err.println("onMessage: Exception caught: " + e);
}
}
Notice how the metrics type is extracted, using the getStringProperty() method, and
is checked. If you use the onMessage() method to process metrics messages of
different types, you can use the type property to distinguish between different
incoming metrics messages.
Also notice how various pieces of information on the broker are extracted, using the
getLong() method of mapMsg.
Run this example monitoring client with the following command:
java BrokerMetrics
5-9
metricTopicName = "mq.metrics.destination_list";
metricTopic = metricSession.createTopic(metricTopicName);
metricSubscriber = metricSession.createSubscriber(metricTopic);
metricSubscriber.setMessageListener(this);
Notice how the metrics type is extracted and checked, and how the list of destinations
is extracted. By iterating through the map names in mapMsg and extracting the
corresponding value (a hashtable), you can construct a list of all the destinations and
their related information.
As discussed in Format of Metrics Messages, these map names are metrics topic names
having one of two forms:
mq.metrics.destination.queue.monitored_destination_name
5-10 Open Message Queue 4.5.2 Developer's Guide for Java Clients
mq.metrics.destination.topic.monitored_destination_name
(The map names can also be used to monitor a destination, but that is not done in this
particular example.)
Notice that from each extracted hashtable, the information on each destination is
extracted using the keys name, type, and isTemporary. The extraction code from the
previous code example is reiterated here for your convenience.
Example 55 Example of Extracting Destination Information From a Hash Table
String metricDestName = (String)e.nextElement();
Hashtable destValues = (Hashtable)mapMsg.getObject(metricDestName);
int i = 0;
oneRow[i++] = (destValues.get("name")).toString();
oneRow[i++] = (destValues.get("type")).toString();
oneRow[i++] = (destValues.get("isTemporary")).toString();
} else if (args[i].equals("-t"))
destType = args[i+1];
}
}
metricConnectionFactory = new com.sun.messaging.TopicConnectionFactory();
metricConnection = metricConnectionFactory.createTopicConnection();
metricConnection.start();
metricSession = metricConnection.createTopicSession(false,
Session.AUTO_ACKNOWLEDGE);
if (destType.equals("q")) {
metricTopicName = "mq.metrics.destination.queue." + destName;
} else {
metricTopicName = "mq.metrics.destination.topic." + destName;
}
metricTopic = metricSession.createTopic(metricTopicName);
metricSubscriber = metricSession.createSubscriber(metricTopic);
metricSubscriber.setMessageListener(this);
5-12 Open Message Queue 4.5.2 Developer's Guide for Java Clients
}
} catch (Exception e) {
System.err.println("onMessage: Exception caught: " + e);
}
}
Notice how the metrics type is extracted, using the getStringProperty() method as in
the previous examples, and is checked. Also notice how various destination data are
extracted, using the getLong() method of mapMsg.
You can run this example monitoring client with one of the following commands:
java DestMetrics -t t -n topic_name
java DestMetrics -t q -n queue_name
-----------------------------------------------------------------------------Msgs
Msg
Bytes Msg Count
Tot Msg Bytes(k)
Largest Msg
In
Out
In
Out
Curr Peak Avg Curr Peak Avg
(k)
-----------------------------------------------------------------------------500
0
318000 0
500
500
250 310
310
155
0
5-14 Open Message Queue 4.5.2 Developer's Guide for Java Clients
6
Working with SOAP Messages
SOAP is a protocol that allows for the exchange of data whose structure is defined by
an XML scheme. Using Message Queue, you can send JMS messages that contain a
SOAP payload. This allows you to transport SOAP messages reliably and to publish
SOAP messages to JMS subscribers. This chapter covers the following topics:
What is SOAP?
If you are familiar with the SOAP specification, you can skip the introductory section
and start by reading SOAP Messaging in JAVA.
What is SOAP?
SOAP, the Simple Object Access Protocol, is a protocol that allows the exchange of
structured data between peers in a decentralized, distributed environment. The
structure of the data being exchanged is specified by an XML scheme.
The fact that SOAP messages are encoded in XML makes SOAP messages portable,
because XML is a portable, system-independent way of representing data. By
representing data using XML, you can access data from legacy systems as well as share
your data with other enterprises. The data integration offered by XML also makes this
technology a natural for Web-based computing such as Web services. Firewalls can
recognize SOAP packets based on their content type (text/xml-SOAP) and can filter
messages based on information exposed in the SOAP message header.
The SOAP specification describes a set of conventions for exchanging XML messages.
As such, it forms a natural foundation for Web services that also need to exchange
information encoded in XML. Although any two partners could define their own
protocol for carrying on this exchange, having a standard such as SOAP allows
developers to build the generic pieces that support this exchange. These pieces might
be software that adds functionality to the basic SOAP exchange, or might be tools that
administer SOAP messaging, or might even comprise parts of an operating system
that supports SOAP processing. Once this support is put in place, other developers can
focus on creating the Web services themselves.
The SOAP protocol is fully described at http://www.w3.org/TR/SOAP. This section
restricts itself to discussing the reasons why you would use SOAP and to describing
basic concepts that will make it easier to work with SOAP messages.
6-1
What is SOAP?
Profile
(Messaging and Delivery Semantics)
Language Implementation
SOAP with Attachments Encoding
Wire Transport Protocol
The sections that follow describe each layer shown in the preceding figure in greater
detail. The rest of this chapter focuses on the SOAP and language implementation
layers.
6-2 Open Message Queue 4.5.2 Developer's Guide for Java Clients
What is SOAP?
The wire transport and SOAP layers are actually sufficient to do SOAP messaging. You
could create an XML document that defines the message you want to send, and you
could write HTTP commands to send the message from one side and to receive it on
the other. In this case, the client is limited to sending synchronous messages to a
specified URL. Unfortunately, the scope and reliability of this kind of messaging is
severely restricted. To overcome these limitations, the provider and profile layers are
added to SOAP messaging.
Interoperability
Because SOAP providers must all construct and deconstruct messages as defined by
the SOAP specification, clients and services using SOAP are interoperable. That is, as
shown in Figure 62, the client and the service doing SOAP messaging do not need to
be written in the same language nor do they need to use the same SOAP provider. It is
only the packaging of the message that must be standard.
Figure 62 SOAP Interoperability
SOAP
Messaging
Client
SOAP Service
SAAJ
SOAP
Implementation
SOAP
Implementation
HTTP
HTTP
SOAP
Msg
6-3
What is SOAP?
In order for a SAAJ client or service to interoperate with a service or client using a
different implementation, the parties must agree on two things:
They must use the same transport bindings--that is, the same wire protocol.
They must use the same profile in constructing the SOAP message being sent.
The envelope is the root element of the XML document representing the message. It
defines the framework for how the message should be handled and by whom.
Once it encounters the Envelope element, the SOAP processor knows that the
XML is a SOAP message and can then look for the individual parts of the message.
The header is a generic mechanism for adding features to a SOAP message. It can
contain any number of child elements that define extensions to the base protocol.
For example, header child elements might define authentication information,
transaction information, locale information, and so on. The actors, the software that
handle the message may, without prior agreement, use this mechanism to define
who should deal with a feature and whether the feature is mandatory or optional.
The body is a container for mandatory information intended for the ultimate
recipient of the message.
A SOAP message may also contain an attachment, which does not have to be in XML.
For more information, see SOAP Packaging Models next.
A SOAP message is constructed like a nested matrioshka doll. When you use SAAJ to
assemble or disassemble a message, you need to make the API calls in the appropriate
order to get to the message part that interests you. For example, in order to add
content to the message, you need to get to the body part of the message. To do this you
need to work through the nested layers: SOAP part, SOAP envelope, SOAP body, until
you get to the SOAP body element that you will use to specify your data. For more
information, see The SOAP Message Object.
6-4 Open Message Queue 4.5.2 Developer's Guide for Java Clients
What is SOAP?
MIME Envelope
SOAP 1.1
Message Package
Envelope
Header
Body
When you construct a SOAP message using SAAJ, you do not have to specify which
model you're following. If you add an attachment, a message like that shown in
Figure 64 is constructed; if you don't, a message like that shown in Figure 63 is
constructed.
Figure 63 shows a SOAP Message with attachments. The attachment part can contain
any kind of content: image files, plain text, and so on. The sender of a message can
choose whether to create a SOAP message with attachments. The message receiver can
also choose whether to consume an attachment.
A message that contains one or more attachments is enclosed in a MIME envelope that
contains all the parts of the message. In SAAJ, the MIME envelope is automatically
produced whenever the client creates an attachment part. If you add an attachment to
a message, you are responsible for specifying (in the MIME header) the type of data in
the attachment.
Figure 64 SOAP Message with Attachments
MIME Envelope
SOAP Part
Envelope
Header
Body
Attachment Part
SOAP Attachment
(XML or non-XML)
6-5
javax.xml.soap: you use the objects in this package to define the parts of a SOAP
message and to assemble and disassemble SOAP messages. You can also use this
package to send a SOAP message without the support of a provider.
javax.xml.messaging: you use the objects in this package to send a SOAP
message using a provider and to receive SOAP messages.
Beginning with SAAJ 1.3, you must put the file mail.jar
explicitly in CLASSPATH.
Note:
This chapter focuses on the javax.xml.soap package and how you use the objects and
methods it defines
It also explains how you can use the JMS API and Message Queue to send and receive
JMS messages that carry SOAP message payloads.
6-6 Open Message Queue 4.5.2 Developer's Guide for Java Clients
SOAP Message
Attachment
Part
SOAP
Part
MIME
Headers
SOAP
Envelope
SOAP
Header
MIME
Header
SOAP
Body
SOAP
Header
Element
Attachment
SOAP
Fault
SOAP Body
Element
Detail
Detail
Entry
As shown in the figure, the SOAPMessage object is a collection of objects divided in two
parts: a SOAP part and an attachment part. The main thing to remember is that the
attachment part can contain non-xml data.
The SOAP part of the message contains an envelope that contains a body (which can
contain data or fault information) and an optional header. When you use SAAJ to
create a SOAP message, the SOAP part, envelope, and body are created for you: you
need only create the body elements. To do that you need to get to the parent of the
body element, the SOAP body.
In order to reach any object in the SOAPMessage tree, you must traverse the tree
starting from the root, as shown in the following lines of code. For example, assuming
the SOAPMessage is MyMsg, here are the calls you would have to make in order to get
the SOAP body:
SOAPPart MyPart = MyMsg.getSOAPPart();
SOAPEnvelope MyEnv = MyPart.getEnvelope();
SOAPBody MyBody = envelope.getBody();
At this point, you can create a name for a body element (as described in Namespaces)
and add the body element to the SOAPMessage.
For example, the following code line creates a name (a representation of an XML tag)
for a body element:
Name bodyName = envelope.createName("Temperature");
The next code line adds the body element to the body:
SOAPBodyElement myTemp = MyBody.addBodyElement(bodyName);
6-7
Finally, this code line defines some data for the body element bodyName :
myTemp.addTextNode("98.6");
Inherited Methods
The elements of a SOAP message form a tree. Each node in that tree implements the
Node interface and, starting at the envelope level, each node implements the
SOAPElement interface as well. The resulting shared methods are described in
Table 61.
Table 61
Inherited
From
Inherited Methods
Method Name
Purpose
Add an attribute with the specified Name
object and string value
addChildElement(Name)
addChildElement(String,
String)
addChildElement
(String, String, String)
addNameSpaceDeclaration
(String, String)
addTextnode(String)
getAllAttributes()
getAttributeValue(Name)
getChildElements()
getChildElements(Name)
getElementName()
getEncodingStyle()
getNameSpacePrefixes()
getNamespaceURI(String)
removeAttribute(Name)
6-8 Open Message Queue 4.5.2 Developer's Guide for Java Clients
Node
Method Name
Purpose
removeNamespaceDeclaration
(String)
setEncodingStyle(String)
detachNode()
getParentElement()
getValue
recycleNode()
Namespaces
An XML namespace is a means of qualifying element and attribute names to
disambiguate them from other names in the same document. This section provides a
brief description of XML namespaces and how they are used in SOAP. For complete
information, see http://www.w3.org/TR/REC-xml-names/
An explicit XML namespace declaration takes the following form:
<prefix:myElement
xmlns:prefix ="URI">
The declaration defines prefix as an alias for the specified URI. In the element
myElement, you can use prefix with any element or attribute to specify that the element
or attribute name belongs to the namespace specified by the URI.
The following is an example of a namespace declaration:
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
After defining the alias, you can use it as a prefix to any attribute or element in the
Envelope element. In Example 61, the elements <Envelope> and <Body> and the
attribute encodingStyle all belong to the SOAP namespace specified by the
http://schemas.sxmlsoap.org/soap/envelope/URI .
Example 61 Explicit Namespace Declarations
<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
SOAP-ENV:encodingStyle=
"http://schemas.xmlsoap.org/soap/encoding/">
6-9
<SOAP-ENV:Header>
<HeaderA
xmlns="HeaderURI"
SOAP-ENV:mustUnderstand="0">
The text of the header
</HeaderA>
</SOAP-ENV:Header>
<SOAP-ENV:Body>
.
.
.
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Note that the URI that defines the namespace does not have to point to an actual
location; its purpose is to disambiguate attribute and element names.
Pre-defined SOAP Namespaces SOAP defines two namespaces:
The SOAP envelope, the root element of a SOAP message, has the following
namespace identifier:
"http://schemas.xmlsoap.org/soap/envelope"
The SOAP serialization, the URI defining SOAP's serialization rules, has the
following namespace identifier:
"http://schemas.xmlsoap.org/soap/encoding"
When you use SAAJ to construct or consume messages, you are responsible for setting
or processing namespaces correctly and for discarding messages that have incorrect
namespaces.
Using Namespaces when Creating a SOAP Name When you create the body elements or
header elements of a SOAP message, you must use the Name object to specify a
well-formed name for the element. You obtain a Name object by calling the method
SOAPEnvelope.createName.
When you call this method, you can pass a local name as a parameter or you can
specify a local name, prefix, and URI. For example, the following line of code defines a
name object bodyName.
Name bodyName = MyEnvelope.createName("TradePrice",
"GetLTP","http://foo.eztrade.com");
The following code shows how you create a name and associate it with a SOAPBody
element. Note the use and placement of the createName method.
SoapBody body = envelope.getBody();//get body from envelope
Name bodyName = envelope.createName("TradePrice", "GetLTP",
"http://foo.eztrade.com");
SOAPBodyElement gltp = body.addBodyElement(bodyName);
Parsing Name Objects For any given Name object, you can use the following Name
methods to parse the name:
6-10 Open Message Queue 4.5.2 Developer's Guide for Java Clients
getQualifiedName returns "prefix:LocalName ", for the given name, this would be
GetLTP:TradePrice.
Get a MessageFactory object from the provider connection and use it to create a
message.
The following three sections describe endpoint, message factory, and connection
objects in greater detail.
Endpoint
An endpoint identifies the final destination of a message. An endpoint is defined either
by the Endpoint class (if you use a provider) or by the URLEndpoint class (if you don't
use a provider).)
Constructing an Endpoint You can initialize an endpoint by calling its constructor. The
following code uses a constructor to create a URLEndpoint.
myEndpoint = new URLEndpoint("http://somehost/myServlet");
Using the Endpoint to Address a Message To address a message to an endpoint, specify the
endpoint as a parameter to the SOAPConnection.call method, which you use to send a
SOAP message.
Message Factory
You use a Message Factory to create a SOAP message.
To instantiate a message factory directly, use a statement like the following:
MessageFactory mf = MessageFactory.newInstance();
Connection
To send a SOAP message using SAAJ, you must obtain a SOAPConnection . You can
also transport a SOAP message using Message Queue; for more information, see
Integrating SOAP and Message Queue.
SOAP Connection
A SOAPConnection allows you to send messages directly to a remote party. You can
obtain a SOAPConnection object simply by calling the static method
SOAPConnectionFactory.newInstance(). Neither reliability nor security are
guaranteed over this type of connection.
SOAP
Endpoint
Sender
Sender
Blocks
SOAP
Message
Sender
Call
Returns
Receive
and
Process
Message
Creates an endpoint that specifies the URL that will be passed to the
SOAPConnection.call method that sends the message.
See Endpoint for a discussion of the different ways of creating an endpoint.
Creates a name for the content of the message and adds the content to the
message.
Uses the SOAPConnection.call method to send the message.
6-12 Open Message Queue 4.5.2 Developer's Guide for Java Clients
It is assumed that the client will ignore the SOAPMessage object returned by the call
method because the only reason this object is returned is to unblock the client.
The SOAP service listening for a request-reply message uses a ReqRespListener object
to receive messages.
For a detailed example of a client that does point-to-point messaging, see Writing a
SOAP Client.
Create a URL object and initialize it to contain the location of the file that you want
to attach to the SOAP message.
URL url = new URL("http://wombats.com/img.jpg");
2.
Create a data handler and initialize it with a default handler, passing the URL as
the location of the data source for the handler.
DataHandler dh = new DataHandler(url);
3.
Create an attachment part that is initialized with the data handler containing the
URL for the image.
AttachmentPart ap1 = message.createAttachmentPart(dh);
4.
After creating the attachment and adding it to the message, you can send the
message in the usual way.
If you are using JMS to send the message, you can use the
SOAPMessageIntoJMSMessage conversion utility to convert a SOAP message that
has an attachment into a JMS message that you can send to a JMS queue or topic
using Message Queue.
Use a SOAP exception to handle errors that occur on the client side during the
generation of the SOAP request or the unmarshalling of the response.
Use a SOAP fault to handle errors that occur on the server side when
unmarshalling the request, processing the message, or marshalling the response.
In response to such an error, server-side code should create a SOAP message that
contains a fault element, rather than a body element, and then it should send that
SOAP message back to the originator of the message. If the message receiver is not
the ultimate destination for the message, it should identify itself as the soapactor
so that the message sender knows where the error occurred. For additional
information, see Handling SOAP Faults.
2.
The myCon object that is returned will be used to send the message.
3.
4.
The message that is created has all the parts that are shown in Figure 67.
6-14 Open Message Queue 4.5.2 Developer's Guide for Java Clients
SOAP Message
SOAP Part
SOAP Envelope
SOAP Header
SOAP Body
At this point, the message has no content. To add content to the message, you need
to create a SOAP body element, define a name and content for it, and then add it
to the SOAP body.
Remember that to access any part of the message, you need to traverse the tree,
calling a get method on the parent element to obtain the child. For example, to
reach the SOAP body, you start by getting the SOAP part and SOAP envelope:
SOAPPart mySPart = message.getSOAPPart();
SOAPEnvelope myEnvp = mySPart.getEnvelope();
5.
Now, you can get the body element from the myEnvp object:
SOAPBody body = myEnvp.getBody();
The children that you will add to the body element define the content of the
message. (You can add content to the SOAP header in the same way.)
6.
When you add an element to a SOAP body (or header), you must first create a
name for it by calling the envelope.createName method. This method returns a
Name object, which you must then pass as a parameter to the method that creates
the body element (or the header element).
Name bodyName = envelope.createName("GetLastTradePrice", "m",
"http://eztrade.com")
SOAPBodyElement gltp = body.addBodyElement(bodyName);
7.
8.
And now you can define data for the body element mySymbol:
mySymbol.addTextNode("SUNW");
xmlns:SOAPENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Body>
<m:GetLastTradePrice xmlns:m="http://eztrade.com">
<symbol>SUNW</symbol>
</m:GetLastTradePrice>
</SOAP-ENV:Body>
</SOAP-ENV: Envelope>
9.
Every time you send a message or write to it, the message is automatically saved.
However if you change a message you have received or one that you have already
sent, this would be the point when you would need to update the message by
saving all your changes. For example:
message.saveChanges();
10. Before you send the message, you must create a URLEndpoint object with the URL
of the endpoint to which the message is to be sent. (If you use a profile that adds
addressing information to the message header, you do not need to do this.)
URLEndpoint endPt = new URLEndpoint("http://eztrade.com//quotes");
11. Now, you can send the message:
SOAPMessage reply = myCon.call(message, endPt);
6-16 Open Message Queue 4.5.2 Developer's Guide for Java Clients
Table 62 describes the methods that the JAXM servlet uses. If you were to write your
own servlet, you would need to provide methods that performed similar work. In
extending JAXMServlet , you may need to override the Init method and the
SetMessageFactory method; you must implement the onMessage method.
Table 62
JAXMServlet Methods
Method
Description
void setMessageFactory
(MessageFactory)
MimeHeaders getHeaders
(HTTPRequest)
void putHeaders
(mimeHeaders,
HTTPresponse)
onMessage
(SOAPMesssage)
Disassembling Messages
The onMessage method needs to disassemble the SOAP message that is passed to it by
the servlet and process its contents in an appropriate manner. If there are problems in
the processing of the message, the service needs to create a SOAP fault object and send
it back to the client as described in Handling SOAP Faults.
Processing the SOAP message may involve working with the headers as well as
locating the body elements and dealing with their contents. The following code sample
Working with SOAP Messages 6-17
shows how you might disassemble a SOAP message in the body of your onMessage
method. Basically, you need to use a Document Object Model (DOM) API to parse
through the SOAP message.
See http://xml.coverpages.org/dom.html for more information about the
DOM API.
Example 64 Processing a SOAP Message
{http://xml.coverpages.org/dom.html
SOAPEnvelope env = reply.getSOAPPart().getEnvelope();
SOAPBody sb = env.getBody();
// create Name object for XElement that we are searching for
Name ElName = env.createName("XElement");
//Get child elements with the name XElement
Iterator it = sb.getChildElements(ElName);
//Get the first matched child element.
//We know there is only one.
SOAPBodyElement sbe = (SOAPBodyElement) it.next();
//Get the value for XElement
MyValue =
sbe.getValue();
}
Handling Attachments
A SOAP message may have attachments. For sample code that shows you how to
create and add an attachment, see Code Samples. For sample code that shows you
how to receive and process an attachment, see Code Samples.
In handling attachments, you will need to use the Java Activation Framework API. See
http://java.sun.com/products/javabeans/glasgow/jaf.html for more information.
Replying to Messages
In replying to messages, you are simply taking on the client role, now from the server
side.
6-18 Open Message Queue 4.5.2 Developer's Guide for Java Clients
SOAP Message
SOAP Part
SOAP Envelope
SOAP Body
SOAP Fault
Detail
Detail Entry
faultcode
A code (qualified name) that identifies the error. The code is intended for use by
software to provide an algorithmic mechanism for identifying the fault.
Predefined fault codes are listed in Table 63. This element is required.
faultstring
A string that describes the fault identified by the fault code. This element is
intended to provide an explanation of the error that is understandable to a human.
This element is required.
faultactor
A URI specifying the source of the fault: the actor that caused the fault along the
message path. This element is not required if the message is sent to its final
destination without going through any intermediaries. If a fault occurs at an
intermediary, then that fault must include a faultactor element.
detail
This element carries specific information related to the Body element. It must be
present if the contents of the Body element could not be successfully processed.
Thus, if this element is missing, the client should infer that the body element was
Working with SOAP Messages 6-19
processed. While this element is not required for any error except a malformed
payload, you can use it in other cases to supply additional information to the
client.
Predefined Fault Codes The SOAP specification lists four predefined faultcode values.
The namespace identifier for these is http://schemas.xmlsoap.org/soap/envelope/.
Table 63
Faultcode Name
Meaning
VersionMismatch
The processing party found an invalid namespace for the SOAP envelope
element; that is, the namespace of the SOAP envelope element was not
http://schemas.xmlsoap.org/soap/envelope/ .
MustUnderstand
An immediate child element of the SOAP Header element was either not
understood or not appropriately processed by the recipient. This element's
mustUnderstand attribute was set to 1 (true).
Client
The message was incorrectly formed or did not contain the appropriate
information. For example, the message did not have the proper
authentication or payment information. The client should interpret this
code to mean that the message must be changed before it is sent again.
If this is the code returned, the SOAPFault object should probably include a
detailEntry object that provides additional information about the
malformed message.
Server
The message could not be processed for reasons that are not connected
with its content. For example, one of the message handlers could not
communicate with another message handler that was upstream and did
not respond. Or, the database that the server needed to access is down.
The client should interpret this error to mean that the transmission could
succeed at a later point in time.
These standard fault codes represent classes of faults. You can extend these by
appending a period to the code and adding an additional name. For example, you
could define a Server.OutOfMemory code, a Server.Down code, and so forth.
Defining a SOAP Fault Using SAAJ you can specify the value for faultcode,
faultstring, and faultactor using methods of the SOAPFault object. The following
code creates a SOAP fault object and sets the faultcode, faultstring, and
faultactor attributes:
SOAPFault fault;
reply = factory.createMessage();
envp = reply.getSOAPPart().getEnvelope(true);
someBody = envp.getBody();
fault = someBody.addFault():
fault.setFaultCode("Server");
fault.setFaultString("Some Server Error");
fault.setFaultActor(http://xxx.me.com/list/endpoint.esp/)
reply.saveChanges();
The server can return this object in its reply to an incoming SOAP message in case of a
server error.
The next code sample shows how to define a detail and detail entry object. Note that
you must create a name for the detail entry object.
SOAPFault fault = someBody.addFault();
fault.setFaultCode("Server");
6-20 Open Message Queue 4.5.2 Developer's Guide for Java Clients
fault.setFaultActor("http://foo.com/uri");
fault.setFaultString ("Unkown error");
Detail myDetail = fault.addDetail();
detail.addDetailEntry(envelope.createName("125detail", "m",
"Someuri")).addTextNode("the message cannot contain
the string //");
reply.saveChanges();
The Session argument specifies the session to be used in producing the Message.
On the receiving side, you get the JMS message containing the SOAP payload as
you would a normal JMS message. You then call the
MessageTransformer.SOAPMessageFromJMSMessage utility to extract the SOAP
message, and then use SAAJ to disassemble the SOAP message and do any further
processing. For example, to obtain the SOAPMessage make a call like the
following:
SOAPMessage myMsg= MessageTransformer.SOAPMessageFromJMSMessage
(Message, MessageFactory);
The MessageFactory argument specifies a message factory that the utility should
use to construct the SOAPMessage from the given JMS Message.
The following sections offer several use cases and code examples to illustrate this
process.
MyServlet
SOAPMessageIntoJMSMessage
(mySOAP, mySession)
SOAPMsg
JMSMsg
Message
Queue
Broker
JMSMsg
SOAPMessageFromJMSMessage
(myJMS, myFactory)
//process SOAP message here
MyListener
To Transform the SOAP Message into a JMS Message and Send the JMS Message
1.
Instantiate a ConnectionFactory object and set its attribute values, for example:
QueueConnectionFactory myQConnFact =
new com.sun.messaging.QueueConnectionFactory();
2.
3.
4.
5.
6.
6-22 Open Message Queue 4.5.2 Developer's Guide for Java Clients
To Receive the JMS Message, Transform it into a SOAP Message, and Process It
1.
2.
3.
4.
5.
6.
7.
8.
9.
Use the Message Transformer to convert the JMS message back to a SOAP
message.
SOAPMessage MySoap =
MessageTransformer.SOAPMessageFromJMSMessage
(myJMS, MyMsgFactory);
If you specify null for the MessageFactory argument, the default Message Factory
is used to construct the SOAP Message.
10. Disassemble the SOAP message in preparation for further processing. See The
MyServlet
SOAPMessageIntoJMSMessage
(mySOAP, mySession)
SOAPMsg
JMSMsg
Message
Queue
Broker
JMSMsg
SOAPMessageFromJMSMessage
(myJMS, myFactory)
SOAPMessageFromJMSMessage
(myJMS, myFactory)
SOAPMessageFromJMSMessage
(myJMS, myFactory)
MyListener1
MyListener2
MyListener3
The code that accomplishes this is exactly the same as in the previous example, except
that instead of sending the JMS message to a queue, you send it to a topic. For an
example of publishing a SOAP message using Message Queue, see Example 65.
Code Samples
This section includes and describes two code samples: one that sends a JMS message
with a SOAP payload, and another that receives the JMS/SOAP message and
processes the SOAP message.
Example 65 illustrates the use of the JMS API, the SAAJ API, and the JAF API to send
a SOAP message with attachments as the payload to a JMS message. The code shown
for the SendSOAPMessageWithJMS includes the following methods:
A constructor that calls the init method to initialize all the JMS objects required to
publish a message
A send method that creates the SOAP message and an attachment, converts the
SOAP message into a JMS message, and publishes the JMS message
6-24 Open Message Queue 4.5.2 Developer's Guide for Java Clients
Example 66 illustrates the use of the JMS API, SAAJ, and the DOM API to receive a
SOAP message with attachments as the payload to a JMS message. The code shown
for the ReceiveSOAPMessageWithJMS includes the following methods:
A constructor that calls the init method to initialize all the JMS objects needed to
receive a message.
An onMessage method that delivers the message and which is called by the
listener. The onMessage method also calls the message transformer utility to
convert the JMS message into a SOAP message and then uses SAAJ to process the
SOAP body and uses SAAJ and the DOM API to process the message attachments.
6-26 Open Message Queue 4.5.2 Developer's Guide for Java Clients
6-28 Open Message Queue 4.5.2 Developer's Guide for Java Clients
7
Embedding a Message Queue Broker in a
Java Client
Message Queue supports running a broker from within a Java client. Such a broker,
called an embedded broker, runs in the same JVM as the Java client that creates and starts
it.
Beyond operating like a normal standalone broker, an embedded broker offers the
application in which it is embedded access to a special kind of connection called a
direct mode connection. Direct mode connections are used just like ordinary connections,
but they are much higher performing because they use in-memory transport instead of
TCP. To specify a direct mode connection, the client specifies mq://localhost/direct
as the broker address in the connection factory from which it subsequently creates the
connection.
The following sections provide more information about creating and managing
embedded brokers:
2.
3.
4.
5.
7-1
import com.sun.messaging.jmq.jmsservice.BrokerEventListener;
// Obtain the ClientRuntime singleton object
ClientRuntime clientRuntime = ClientRuntime.getRuntime();
// Create a broker instance
BrokerInstance brokerInstance = clientRuntime.createBrokerInstance();
// Create a broker event listener
BrokerEventListener listener = new EmbeddedBrokerEventListener();
// Convert the broker arguments into Properties. Note that parseArgs is
// a utility method that does not change the broker instance.
Properties props = brokerInstance.parseArgs(args);
// Initialize the broker instance using the specified properties and
// broker event listener
brokerInstance.init(props, listener);
// now start the embedded broker
brokerInstance.start();
7-2 Open Message Queue 4.5.2 Developer's Guide for Java Clients
The home directory of the Message Queue installation (see "Directory Variable
Conventions").
-libhome path
The port number for the broker's Port Mapper. This is port number on which the
broker listens for client connections.
7-3
package test.direct;
import java.util.Properties;
import
import
import
import
import
import
import
javax.jms.Connection;
javax.jms.Message;
javax.jms.MessageConsumer;
javax.jms.MessageProducer;
javax.jms.Queue;
javax.jms.Session;
javax.jms.TextMessage;
import
import
import
import
import
com.sun.messaging.ConnectionConfiguration;
com.sun.messaging.jmq.jmsclient.runtime.BrokerInstance;
com.sun.messaging.jmq.jmsclient.runtime.ClientRuntime;
com.sun.messaging.jmq.jmsservice.BrokerEvent;
com.sun.messaging.jmq.jmsservice.BrokerEventListener;
7-4 Open Message Queue 4.5.2 Developer's Guide for Java Clients
7-5
with "+thr);
// return value will be ignored
return true;
}
}
}
7-6 Open Message Queue 4.5.2 Developer's Guide for Java Clients
A
Warning Messages and Client Error Codes
This appendix provides reference information for warning messages and for error
codes returned by the Message Queue client runtime when it raises a JMS exception.
A warning message is a message output when the Message Queue Java client
runtime experiences a problem that should not occur under normal operating
conditions. The message is displayed where the application displays its output.
Usually, this is the window from which the application is started. Table A1 lists
Message Queue warning messages.
In general, a warning message does not cause message loss or affect reliability.
issues. But when warning messages appear constantly on the application's
console, the user should contact Message Queue technical support to diagnose the
cause of the warning messages.
Error codes and messages are returned by the client runtime when it raises an
exception. You can obtain the error code and its corresponding message using the
JMSException.getErrorCode() method and the JMSException.getMessage()
method. Table A2 lists Message Queue error codes.
Note that warning messages and error codes are not defined in the JMS specification,
but are specific to each JMS provider. Applications that rely on these error codes in
their programming logic are not portable across JMS providers.
W2003 Message Warning: Broker not responding X for Y seconds. Still trying....
Cause The Message Queue client runtime has not received a response from the broker
for more than 2 minutes (default). In the actual message, the X variable is replaced
with the Message Queue packet type that the client runtime is waiting for, and the Y
variable is replaced with the number of seconds that the client runtime has been
waiting for the packet.
Table A2 lists the error codes in numerical order. For each code listed, it supplies the
error message and a probable cause.
Each error message returned has the following format:
[Code]: "Message -cause Root-cause-exception-message
."
Message text provided for -cause is only appended to the message if there is an
exception linked to the JMS exception. For example, a JMS exception with error code
C4003 returns the following error message:
[C4003]: Error occurred on connection creation [localhost:7676]
- cause: java.net.ConnectException: Connection refused: connect
Table A2
Code
C4000
C4001
C4002
C4003
C4004
C4005
C4006
A-2 Open Message Queue 4.5.2 Developer's Guide for Java Clients
C4007
C4008
C4009
C4010
C4011
C4012
C4013
C4014
C4015
C4016
C4017
C4018
C4019
C4020
C4021
C4022
C4023
C4024
C4025
C4026
C4027
C4028
C4029
C4030
C4031
C4032
A-4 Open Message Queue 4.5.2 Developer's Guide for Java Clients
C4033
C4034
C4035
C4036
C4037
C4038
C4039
C4040
C4041
C4042
C4043
C4044
C4045
C4046
C4047
C4048
C4049
Message Can not call Connection.close(), stop(), etc from message listener.
Cause An attempt was made to call Connection.close(), ...stop(), etc from a
message listener.
C4050
C4051
C4052
C4053
C4054
C4055
C4056
C4057
C4058
C4059
A-6 Open Message Queue 4.5.2 Developer's Guide for Java Clients
C4060
C4061
C4062
C4063
C4064
C4065
C4066
C4067
C4068
C4069
C4070
C4071
C4072
C4073
Message A JMS destination limit was reached. Too many Subscribers/Receivers for
{0} : {1}
{0} is replaced with "Queue" or "Topic" {1} is replaced with the destination name.
Cause The client runtime was unable to create a message consumer for the specified
domain and destination due to a broker resource constraint.
C4074
C4075
C4076
Message Client does not have permission to create producer on destination: {0} {0} is
replaced with the destination name that caused the exception.
Cause The application client does not have permission to create a message producer
with the specified destination.
C4077
C4078
C4079
Message Client does not have permission to register a consumer on the destination:
{0}
{0} is replaced with the destination name that caused the exception.
Cause The application client does not have permission to create a message consumer
with the specified destination name.
C4080
C4081
C4082
C4083
A-8 Open Message Queue 4.5.2 Developer's Guide for Java Clients
C4084
C4085
C4086
C4087
C4088
Message A JMS destination limit was reached. Too many producers for {0} : {1}
{0} is replaced with Queue or Topic {1} is replaced with the destination name for which the
limit was reached.
Cause The client runtime was not able to create a message producer for the specified
domain and destination due to limited broker resources.
C4089
C4090
C4091
C4092
Message Broker does not support Session.NO_ACKNOWLEDGE mode, broker version: {0}
{0} is replaced with the version number of the broker to which the Message Queue application
is connected.
Cause The application attempts to create a NO_ACKNOWLEDGE session to a broker with
version # less than 3.6.
C4093
Message Received wrong packet type. Expected: {0}, but received: {1}
{0} is replaced with the packet type that the Message Queue client runtime expected to receive
from the broker. {1} is replaced with the packet type that the Message Queue client runtime
actually received from the broker.
Cause The Message Queue client runtime received an unexpected Message Queue
packet from broker.
C4094
Message The destination this message was sent to could not be found: {0}
{0} is replaced with the destination name that caused the exception.
Cause: A destination to which a message was sent could not be found.
C4095
Message: Message exceeds the single message size limit for the broker or destination:
{0}
{0} is replaced with the destination name that caused the exception.
Cause: A message exceeds the single message size limit for the broker or destination.
C4096
A-10 Open Message Queue 4.5.2 Developer's Guide for Java Clients