Saturday, August 14, 2010

Using Compressed JMS Messages

If you are publishing large XML messages onto a JMS topic or queue, compression will give you much better performance because less data is sent over the network. Also, your JMS server can hold more messages and there is less risk of running out of memory. XML messages are great candidates for compression, due to the repetitive nature of XML.

Compressing JMS messages
The following code shows how you can create a compressed BytesMessage and publish it onto a topic:

InputStream in = null;
GZIPOutputStream out = null;
try {
  ByteArrayOutputStream bos = new
                            ByteArrayOutputStream(1024 * 64);
  out = new GZIPOutputStream(bos);

  String filename = "input.xml";
  in = new BufferedInputStream(new FileInputStream(filename));

  byte[] buf = new byte[1024 * 4];
  int len;
  while ((len = in.read(buf)) > 0) {
      out.write(buf, 0, len);
  }
  out.finish();

  //publish it
  BytesMessage msg = session.createBytesMessage();
  msg.writeBytes(bos.toByteArray());
  publisher.publish(msg);
}
catch (IOException e) {
  e.printStackTrace();
}
finally {
  if (in != null) {
    try {
        in.close();
    }
    catch (IOException ignore) {
    }
  }
  if (out != null) {
    try {
        out.close();
    }
    catch (IOException ignore) {
    }
  }
}
Decompressing JMS messages
The following code shows how you can decompress a JMS BytesMessage when your subscriber receives it and write it to file:
if (mesg instanceof BytesMessage) {
 final BytesMessage bMesg = (BytesMessage) mesg;

 byte[] sourceBytes;
 try {
    sourceBytes = new byte[(int) bMesg.getBodyLength()];
    bMesg.readBytes(sourceBytes);
    System.out.println("Read " + sourceBytes.length + " bytes");
 }
 catch (JMSException e1) {
    throw new RuntimeException(e1);
 }
 GZIPInputStream in = null;
 OutputStream out = null;
 try {
    in = new GZIPInputStream(
         new ByteArrayInputStream(sourceBytes));
    String filename = "message.xml";
    out = new FileOutputStream(filename);
    byte[] buf = new byte[1024 * 4];
    int len;
    while ((len = in.read(buf)) > 0) {
        out.write(buf, 0, len);
    }
    System.out.println("Wrote to " + filename);
 }
 catch (IOException e) {
    e.printStackTrace();
 }
 finally {
    if (in != null)
        try {
            in.close();
        }
        catch (IOException ignore) {
        }
    if (out != null)
        try {
            out.close();
        }
        catch (IOException ignore) {
        }
 }
}

4 comments:

  1. Anonymous1:33 PM

    Hi, we've used similar solution for some time. But if you use TIBCO EMS there is automatic compression/decompression by TIBCO libraries on the client side. Just set this porperty on the outgoing message:
    msg.setBooleanProperty("JMS_TIBCO_COMPRESS",true);

    ReplyDelete
    Replies
    1. hi ,

      can u please tell me where we will set this property and give me a small example for this.


      Thanks
      Sumalatha


      Delete
  2. Anonymous12:32 PM

    Hi,
    I using Deflater for both compression and decompression. When i am trying to receive the message iam getting an exception
    [JMSClientExceptions:055128]Read attempted in WRITE mode.

    ReplyDelete
  3. Anonymous12:57 PM

    Thanks,
    The above was solved by calling msg.reset() after the call to msg.writeBytes(bos.toByteArray());

    ReplyDelete