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.
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:
BytesMessage
using the createBytesMessage
method BytesMessage
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
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.
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.
18.220.53.93