tags:

views:

700

answers:

2

I'd like to write a MessageConverter class that can wrap another MessageConverter. This MessageConverter would call the child converter, which is assumed to generate a TextMessage. It would take the payload and GZIP compress it, creating a BytesMessage which is ultimately returned to the sender.

The problem is in writing fromMessage(). I can convert the payload back into the string, but then I want to create a "dummy" TextMessage to stuff the string into to then pass to the child MessageConverter's fromMessage() method. There I'm hitting a brick wall because I can't create a TextMessage without a JMS session object, and it appears that there is no way at all to get a session in this context.

I could create additional properties to wire up more stuff to this class, but it doesn't look like I can easily even obtain a session from a JMSTemplate object, and I can't imagine what else I'd need to have.

I am on the verge of creating a private TextMessage implementation within this code just for the purpose of wrapping a string for the child MessageConverter. That class will require tons of dummy methods to flesh out the Interface, and all of that typing makes baby Jesus cry.

Can anyone suggest a better way?

A: 

So I did, in fact, make one of these:

    private static class FakeTextMessage implements TextMessage {
            public FakeTextMessage(Message m) { this.childMessage = m; }
            private String text;
            private Message childMessage;
            public void setText(String t) { this.text = t; }
            public String getText() { return this.text; }

            // All the rest of the methods are simply pass-through
            // implementations of the rest of the interface, handing off to the child message.
            public void acknowledge() throws JMSException { this.childMessage.acknowledge(); }
            public void clearBody() throws JMSException { this.childMessage.clearBody(); }
            public void clearProperties() throws JMSException { this.childMessage.clearProperties(); }
            public Enumeration getPropertyNames() throws JMSException { return this.childMessage.getPropertyNames(); }
            public boolean propertyExists(String pn) throws JMSException { return this.childMessage.propertyExists(pn); }

            // and so on and so on
    }

Makes me long for Objective C. How is THAT possible? :)

nsayer
+2  A: 

Do you really wanna wrap MessageConverter instances inside other MessageConverter instances? The whole point of a MessageConverter is to turn a Message into something else (that is not a JMS Message). Its not really designed to chain them (each step making a fake JMS message).

Why not just introduce your own interface

interface MessageBodyConverter {
  /** return a converted body of the original message */
  Object convert(Object body, Message originalMessage);
}

You then can create a MessageConverter invoking one of these (which can then nest as deep as you like)

class MyMessageConverter implements MessageConverter {
  private final MessageBodyConverter converter;

  public Object fromMessage(Message message) {
    if (message instanceof ObjectMessage) {
       return converter.convert(objectMessage.getObject(), message);
    ...
  }
}

You can then chain those MessageBodyConverter objects as deep as you like - plus you have access to the original JMS message (to get headers and so forth) without having to try create pseudo (probably not JMS compliant) implementations of Message?

James Strachan
I could do that, but the point is to make GZIP compressing the JMS message bodies optional at run time simply by wiring the GZIP compression MessageConverter into place. This saves me having to write if/then/else code in the existing MessageConverter.
nsayer
Oh, and if I implement the JMS TextMessage interface, and if all of the methods except setText() and getText() pass through to something that really is a JMS message, how could it *not* be JMS compliant?
nsayer
So long as you delegate pretty much all the Message APIs to the real JMS message you should be OK; but it sounds like loads of work for little in the way of value. e.g. why not just add your own API that supports chaining without having to wrap each Message?
James Strachan
How do you plan on implementing the TextMessage API while using gzip underneath? Wouldn't you then have to facade a TextMessage onto an ObjectMessage?BTW gzip compression is something that usually a JMS provider does for you under the covers - its certainly the case with ActiveMQ
James Strachan
This converter takes a TextMessage from the child, gzip's the body and sends out a BytesMessage in its place. On the way back in, it takes the BytesMessage, extracts and uncompresses the body, wraps the original message in a FakeTextMessage with the uncompressed stuff and gives to the child.
nsayer
The nice thing about this approach is that using gzip compression is a decision made at the applicationContext.xml level. Compress? chain in one of these. No compress? Just use the child MessageConverter directly. You could do this with a custom API, but then that's extra code for uncompressed.
nsayer