Handling a byte-based message

Sometimes it is necessary to send an unformatted stream of bytes as a message. This recipe illustrates this process using the BytesMessage interface. However, when possible, other message types such as string and objects should be used.

The advantages of using an unformatted stream of bytes include ease of read and write operations and a fixed size message. When data is written or read using the BytesMessage methods, it is stored using the appropriate primitive data format. For example, when an integer is written, it will be stored as a 32-bit two's complement number. The size of the number will always be four bytes regardless of the number of digits comprising the number.

Getting ready

The essential structure of a servlet used to generate a message was introduced in the introduction. Here we will address the unique elements of creating and using a BytesMessage which include:

  1. Creating a BytesMessage using the createBytesMessage method
  2. Writing values to the BytesMessage
  3. Sending the message

How to do it...

Create a Queue named jms/PartsQueue and a QueueConnectionFactory named jms/PartsFactory as described in the introduction. Next, create a Java EE application called BytesMessageApplication. In the EJB module add a package called packt and then an MDB called PartsBean. In the WAR module create a package called servlet with a servlet called PartsServlet.

Create the PartsServlet as follows. The doGet and doPost methods are not listed here.

public class PartsServlet extends HttpServlet { @Resource(mappedName="jms/PartsFactory")
private QueueConnectionFactory queueConnectionFactory;
@Resource(mappedName="jms/PartsQueue")
private Queue queue;
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
try {
Connection connection;
try {
connection = queueConnectionFactory.createConnection();
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
MessageProducer messageProducer = (MessageProducer) session.createProducer(queue);
BytesMessage bytesMessage = session.createBytesMessage();
bytesMessage.writeInt(12345); // part number
bytesMessage.writeFloat(12.5f); // weight
bytesMessage.writeInt(50); // quantity
messageProducer.send(bytesMessage);
System.out.println("---> comment sent");
} catch (JMSException ex) {
Logger.getLogger(PartsServlet.class.getName()). log(Level.SEVERE, null, ex);
}
out.println("<html>");
out.println("<head>");
out.println("<title>Servlet PartsServlet</title>");
out.println("</head>");
out.println("<body>");
out.println("<h1>Servlet PartsServlet at " + request.getContextPath () + "</h1>");
out.println("</body>");
out.println("</html>");
} finally {
out.close();
}
}

The PartsBean starts with the @MessageDriven annotation where we specify we want to listen to the jms/PartsQueue. The onMessage method receives a BytesMessage and is displayed.

@MessageDriven(mappedName = "jms/PartsQueue", activationConfig = { @ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge"), @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue")
})
public class PartsBean implements MessageListener {
public PartsBean() {
}
public void onMessage(Message message) {
BytesMessage bytesMessage = (BytesMessage) message;
try {
System.out.println("Part Numer: " + bytesMessage.readInt());
System.out.println("Weight: " + bytesMessage.readFloat());
System.out.println("Quantity: " + bytesMessage.readInt());
} catch (JMSException ex) {
Logger.getLogger(PartsBean.class.getName()).log(Level.SEVERE, null, ex);
}
System.out.println("---> parts received");
}
}

Execute the PartsServlet. The output will appear as follows:

INFO: ---> comment sent

INFO: Part Numer: 12345

INFO: Weight: 12.5

INFO: Quantity: 50

INFO: ---> parts received

How it works...

In the PartsServlet, the @Resource annotation injected a QueueConnectionFactory and a Queue. This chapter's introduction details the process for establishing a connection to a queue. In this application we use the jms/PartsQueue.

The interesting part is the creation and use of the BytesMessage. The Session object's createByteMessage method returns a BytesMessage object. The methods available to this object are similar to those used by the java.io.DataOutputStream. In this example, we wrote the order's parts ID number, weight, and quantity to the BytesMessage object using the writeInt and writeFloat methods. As the method's names imply, one writes out an integer and the other a float. Once all needed information was written, the message was sent to the jms/PartsQueue using the send method.

The PartsBean started with the @MessageDriven annotation and used the mappedName attribute to specify the queue used. Two @ActivationConfigProperty elements were used to specify the acknowledgement mode and that the destination was a queue.

The Message received in the onMessage method was cast to a BytesMessage. The BytesMessage object's methods are similar to that of the java.io.DataInputStream. Using the readInt and readFloat methods, the elements of the message were easily extracted and displayed.

There's more...

Note that it is possible to write data out as one data type and read it in using a different type. For example, an integer is written out as a four byte two's complement number. On the receiving end, the same four byte quantity can be read as two short values. While this is possible, it does not make sense to interpret the data using different data types in most situations.

When the BytesMessage object is first created it is placed in a write-only mode. The client is able to write to it. Once the message is received, the message is in a read-only mode.

The Message object's clearBody method has the effect of clearing out the contents of the message and placing the message in a write-only mode. It is possible for the client to send the message and then continue writing to the BytesMessage object. However, subsequent writing does not affect the message previously sent. The BytesMessage object can be sent multiple times if necessary.

There are several methods of the BytesMessage object that permit the writing and reading of Java's primitive data types and strings along with the writing of an unsigned byte and short value. In addition, the getBodyLength returns the length of the message body. This method is only available when the message is in the read-only mode.

See also

The StreamMessage, as described in the next recipe, is similar to the BytesMessage interface. However, it requires that for each write operation of a specific data type, the corresponding read data type operation be performed on the receiving end.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.220.53.93