In JMS you need 2 objects to collect the connection parameters with the
message broker: a ConnectionFactory
that knows where to connect,
and a Connection
object that knows how to authenticate for a
session (next step). In this example we assume that the broker is running on
the develement machine and the STOMP listener uses the default port number.
factory = NEW nl.flusso.stomp.ConnectionFactory('localhost':U, 61613). connection = factory:createConnection('username':U, 'password':U).
If your broker does not require authentication, you can supply the unknown value for both user name and password:
connection = factory:createConnection(?, ?).
A JMS session encapsulates all communication with the broker (using an ABL SOCKET object). After using the session object for exchanging messages with the broker, we need to release operating system resources and tell the broker we do not want to receive any more data. The broker uses this notification to clean up resources allocated for us.
jmsSession = connection:createSession(FALSE, {&CLIENT_ACKNOWLEDGE}). /* Exchange messages with the broker, see below. */ FINALLY: jmsSession:close(). END FINALLY.
In the example above we indicate that we do not want to group sent messages using explicit transactions, but we do want to acknowledge the successful receipt and processing of messages that the broker sent to us. If we would choose automatic acknowledgement, messages for us are considered done when they are sent by the STOMP subsystem of the broker, before we even know that there are bytes on their way over the network channel.
A JMS Destination
is an abstract concept that denotes the place
where we sent messages to or receive messages from. It could be either a
Queue
or a Topic
. We send messages to a
Destination
using a MessageProducer
and receive from
a Destination
using a MessageConsumer
.
destination = jmsSession:createQueue('SampleQ1':U). producer = jmsSession:createProducer(destination).
or
destination = jmsSession:createQueue('SampleQ1':U). consumer = jmsSession:createConsumer(destination).
After all the preparations above we are ready to create a message and send it.
messageToSend = jmsSession:createTextMessage('Hello world':U). producer:send(messageToSend).
Full example, now including all declarations:
USING javax.jms.*. ROUTINE-LEVEL ON ERROR UNDO, THROW. {javax/jms/Session.i} DEFINE VARIABLE factory AS ConnectionFactory NO-UNDO. DEFINE VARIABLE connection AS Connection NO-UNDO. DEFINE VARIABLE jmsSession AS Session NO-UNDO. DEFINE VARIABLE destination AS Queue NO-UNDO. DEFINE VARIABLE producer AS MessageProducer NO-UNDO. DEFINE VARIABLE messageToSend AS TextMessage NO-UNDO. factory = NEW nl.flusso.stomp.ConnectionFactory('localhost':U, 61613). connection = factory:createConnection('username':U, 'password':U). jmsSession = connection:createSession(FALSE, {&CLIENT_ACKNOWLEDGE}). destination = jmsSession:createQueue('SampleQ1':U). producer = jmsSession:createProducer(destination). messageToSend = jmsSession:createTextMessage('Hello world':U). producer:send(messageToSend). FINALLY: jmsSession:close(). END FINALLY.
Receiving a message is somewhat more complicated than sending one, because we need to find out what kind of message we received before we can process it. In ABL we do that by trying to cast the message to a type that we can handle. In the example below we ignore messages of other types, and in particular we do not acknowledge the receipt of those messages. That way those messages will remain available for other clients to process.
USING javax.jms.*. ROUTINE-LEVEL ON ERROR UNDO, THROW. {javax/jms/Session.i} DEFINE VARIABLE factory AS ConnectionFactory NO-UNDO. DEFINE VARIABLE connection AS Connection NO-UNDO. DEFINE VARIABLE jmsSession AS Session NO-UNDO. DEFINE VARIABLE destination AS Queue NO-UNDO. DEFINE VARIABLE consumer AS MessageConsumer NO-UNDO. DEFINE VARIABLE genericMessage AS Message NO-UNDO. DEFINE VARIABLE textMessage AS TextMessage NO-UNDO. DEFINE VARIABLE textBody AS LONGCHAR NO-UNDO. DEFINE VARIABLE textLength AS INTEGER NO-UNDO. factory = NEW nl.flusso.stomp.ConnectionFactory('localhost':U, 61613). connection = factory:createConnection('username':U, 'password':U). jmsSession = connection:createSession(FALSE, {&CLIENT_ACKNOWLEDGE}). destination = jmsSession:createQueue('SampleQ1':U). consumer = jmsSession:createConsumer(destination). genericMessage = consumer:receive(). textMessage = CAST(genericMessage, TextMessage) NO-ERROR. IF NOT ERROR-STATUS:ERROR THEN DO: textBody = textMessage:text. textLength = LENGTH(textBody). MESSAGE (IF textLength < 100 THEN STRING(textBody) ELSE 'long message') VIEW-AS ALERT-BOX. textMessage:acknowledge(). END. FINALLY: jmsSession:close(). END FINALLY.
In the examples above all class-based object variables are defined as having
an ABL interface type. That is is a recommended practice for general OO
programming, but in particular when using the OpenEdge Adapter for Fuse Message
Broker. Developers reserve the right to change all implementation classes in
package nl.flusso.stomp, except ConnectionFactory
. All operations
after obtaining a ConnectionFactory
instance can be accomplished
using only interface type variables and parameters.
The stompTests directory in the source distribution contains our general test cases. They show some more possible usage scenarios.
Note that those tests (and the adapter implementation itself) tend to delete all objects explicitly, instead of relying on the 10.2 garbage collector. That is not because we think it is better or we prefer to do unnecessary work, but it is part of the preparation for a planned backport to 10.1C.
The OpenEdge Adapter for Fuse Message Broker implements a pure subset of the standard JMS API. The part that is implemented, should follow the specification faithfully. There are no intended extensions of the specification (except as workarounds for OpenEdge™ limitations, see below).
In a separate document we describe what part of the JMS API is currently supported. All details of the API are described in the standard JMS 1.1 documentation (available online) and in several works available at your favorite book seller.
The following rules were applied for translating the JMS API specification to ABL definitions.