Home > Articles > Web Services > XML

  • Print
  • + Share This
This chapter is from the book

Using the JMS Message Interface

A message is created using the Session interface (see Chapter 2), and the Session interface defines create methods for all the message types, including the root Message interface (Table 3-1).

Table 3-1. Accessor Methods for Session Interface

createBytesMessage()
createMapMessage()
createMessage()
createObjectMessage()
createObjectMessage(java.io.seriablizable object) //create with content
createStreamMessage()
createTextMessage()
createTextMessage(String value) // create with content

As shown, createObjectMessage and createTextMessage are overloaded so that they can be instantiated with data at the time of creation. Creation of a message takes the form

//create message
BytesMessage bMsg = session.createBytesMessage();

If a message is being received, then the MessageConsumer creates the message and returns it to an object variable:

//receive message
TextMessage replyMsg = (TextMessage)receiver.receive();

This assumes that the type of message being received is known. In our example, if the message retrieved was actually a BytesMessage, then an exception would be thrown. Another approach is to use the root interface to receive the object variable, and then test the object and cast to the allowed type:

//receive message
Message msg = receiver.receive();
if(msg instanceof TextMessage){
     TextMessage tMsg = (TextMessage)msg;
     ......
}

The root Message interface defines the accessor methods for the header fields and properties; the typed Message interfaces extend this to include accessor methods for manipulating the data they contain in their message body. We examine the methods and sample usage for each of the typed interfaces in turn.

BytesMessage

Table 3-2 details the accessor methods associated with BytesMessage.

Table 3-2. Accessor Methods for BytesMessage Interface

readBoolean()
readByte()
readBytes(byte[] value)
readBytes(byte[] value, int length)
readChar()
readDouble()
readFloat()
readInt()
readLong()
readUnsignedByte()
readUnsignedShort()
readUTF()
writeBoolean(boolean value)
writeByte(byte value)
writeBytes(byte[] value)
writeBytes(byte[] value, int length)
writeChar(char value)
writeDouble(double value)
writeFloat(float value)
writeInt(int value)
writeLong(long value)
writeObject(Object value) //works only for object primitive types
writeShort(short value)
writeUTF(String value)

Use of these methods follow a simple rule: If you build the message body by using write methods in a certain order, then you unpack the message body by using the corresponding read methods in the same order. Let's use our familiar John Doe example laid out in a record-oriented format to illustrate:

/*Sender*/
//create and send BytesMessage
String firstName = "JOHN";
String lastName = "DOE";
int age = 33;

BytesMessage bOutMsg = session.createBytesMessage();
bOutMsg.writeBytes(firstName.getBytes());
bOutMsg.writeBytes(lastName.getBytes());
bOutMsg.writeInt(age);
sender.send(bOutMsg);

/*Receiver*/
//receive and unpack BytesMessage
BytesMessage bInMsg = (BytesMessage)receiver.receive();
byte[] data = new byte[4];
bInMsg.readBytes(data, 4);
String firstName = new String(data);
bInMsg.readBytes(data, 3);
String lastName = new String(data, 0, 3);
int age = bInMsg.readInt();

If we want to retrieve the entire contents of BytesMessage using readBytes(byte [] value), we must determine the length of the message body so that we can appropriately initialize the byte array that will contain the read data. Unfortunately, JMS 1.0.2b does not provide any means for determining the length of the message body, and if the length of the incoming message is not known, we may be forced to adopt processing of the form

//receive and unpack BytesMessage
BytesMessage bInMsg = (BytesMessage)receiver.receive();
int msgLength = 0;
int BUF_SIZE = 50000; //some efficient maximum
byte[] data = new byte[BUF_SIZE];
while(true){
     int len = bInMsg.readBytes(data);
     if(len > 0){
     msgLength += len;
     }else{
     break;
     }
}
// now we know the message length
// so reset and read in one go.
byte[] message = new byte[msgLength];
//if msgLength <= BUF_SIZE, then we already
//have the contents
if (msgLength <= BUF_SIZE) {
          System.arraycopy(data, 0, message, 0, msgLength);
} else {
       bInMsg.reset();//reset cursor to beginning
       bInMsg.readBytes(message);
}

Notice that we introduce the utility method reset(), which repositions the stream of bytes to the beginning and allows us to read in the entire byte array. JMS 1.1 addresses this issue by specifying a getBodyLength() method in the BytesMessage interface, which allows us to greatly simplify the process of dynamically sizing our byte array as follows:

//receive and unpack BytesMessage
BytesMessage bInMsg = (BytesMessage)receiver.receive();
int msgLength = bInMsg.getBodyLength();
byte[] message = new byte[msgLength];
bInMsg.readBytes(message);

TextMessage

As shown in Table 3-3, TextMessage offers an interface that is quite simple to use.

Table 3-3. Accessor Methods for TextMessage Interface

getText()

setText(String value)

It provides a setText and a getText method, which enable the message body to be populated or content extracted:

/*Sender*/
//create and send TextMessage
String firstName = "JOHN";
String lastName = "DOE";
String age = "33";

TextMessage tOutMsg = session.createTextMessage();
String message = firstName + ";" + lastName + ";" + age;
tOutMsg.setText(message);
sender.send(tOutMsg);

/*Receiver*/
//receive and unpack TextMessage
TextMessage tInMsg = (TextMessage)receiver.receive();
String message = tInMsg.getText();

StreamMessage

StreamMessage represents a sequence of primitive types, as shown in Table 3-4.

Table 3-4. Accessor Methods for StreamMessage Interface

readBoolean()
readByte()
readBytes(byte[] value)
readChar()
readDouble()
readFloat()
readInt()
readLong()
readObject()
readShort()
readString()
writeBoolean(boolean value)
writeByte(byte value)
writeBytes(byte[] value)
writeBytes(byte[] value, int offset, int length)
writeChar(char value)
writeDouble(double value)
writeFloat(float value)
writeInt(int value)
writeLong(long value)
writeObject(Object value) //works only for object primitive types
writeShort(short value)
writeString(String value)

It provides methods that allow the various primitives to be written or read:

/*Sender*/
//create and send StreamMessage
String firstName = "JOHN";
String lastName = "DOE";
int age = 33;

StreamMessage sOutMsg = session.createStreamMessage();
sOutMsg.writeString(firstName);
sOutMsg.writeString(lastName);
sOutMsg.writeInt(age);
sender.send(sOutMsg);

/*Receiver*/
//receive and unpack StreamMessage
StreamMessage sInMsg = (StreamMessage)receiver.receive();
String firstName = sInMsg.readString();
String lastName = sInMsg.readString();
int age = sInMsg.readInt();

As with BytesMessage, StreamMessage also provides a reset method with which the stream can be repositioned to its beginning.

MapMessage

The MapMessage interface (Table 3-5) introduces a name variable that represents the key associated with the typed field. Because data is accessed based on the name (key), it does allow random access to data fields.

Table 3-5. Accessor Methods for MapMessage Interface

getBoolean(String name)
getByte(String name)
getBytes(String name)
getChar(String name)
getDouble(String name)
getFloat(String name)
getInt(String name)
getLong(String name)
getObject(String name)
getShort(String name)
getString(String name)
setBoolean(String name, boolean value)
setByte(String name, byte value)
setBytes(String name, byte[] value)
setBytes(String name, byte[] value, int offset, int length)
setChar(String name, char value)
setDouble(String name, double value)
setFloat(String name, float value)
setInt(String name, int value)
setLong(String name, long value)
setObject(String name, Object value)
setShort(String name, short value)
setString(String name, String value)

To facilitate key management, the MapMessage interface offers two utility methods: itemExists and getMapNames. itemExists(String Name) takes as argument a key name and checks for its existence, returning a Boolean. getMapNames() returns an Enumeration object containing all the key names defined in the message. The use of MapMessage follows the now familiar pattern:

/*Sender*/
//create and send MapMessage
String firstName = "JOHN";
String lastName = "DOE";
int age = 33;

MapMessage mOutMsg = session.createMapMessage();
mOutMsg.setString("first", firstName);
mOutMsg.setString("last", lastName);
mOutMsg.setInt("age", age);
sender.send(mOutMsg);

/*Receiver*/
//receive and unpack MapMessage
MapMessage mInMsg = (MapMessage)receiver.receive();
String firstName = mInMsg.getString("first");
String lastName = mInMsg.getString("last");
int age = mInMsg.getInt("age");

ObjectMessage

As with TextMessage, ObjectMessage (Table 3-6) offers a simple interface that supports the insertion or retrieval of objects from the message.

Table 3-6. Accessor Methods for ObjectMessage Interface

getObject()

setObject(Object value)

Objects passed must implement the java.io.Serializable interface:

/*Sender*/
//create and send ObjectMessage
String firstName = "JOHN";
String lastName = "DOE";
int age = 33;
Person pObj = new Person(firstName, lastName, age);

ObjectMessage objOutMsg = session.createObjectMessage();
objOutMsg.setObject(pObj);
sender.send(objOutMsg);

/*Receiver*/
//receive and unpack ObjectMessage
ObjectMessage objInMsg = (ObjectMessage)receiver.receive();
Person pObj = (Person)objInMsg.getObject();
  • + Share This
  • 🔖 Save To Your Account