Results 1 to 8 of 8

Thread: To what extent does JMS unification work?

  1. #1
    Join Date
    Sep 2004
    Posts
    4

    Default To what extent does JMS unification work?

    Hello,

    In org.springframework.jms.support.converter.SimpleMe ssageConvertor.java, I see that the fromMessage() method uses the BytesMessage.getBodyLength() method. This method is not available in JMS 1.0.2 so I was wondering if this code actually works with JMS 1.0.2, and if yes, how?

    Best regards,

    Robin Boerdijk

  2. #2
    Join Date
    Aug 2004
    Location
    New York, NY
    Posts
    74

    Default

    Hi,

    Good catch. Some of the 1.1 isms have snuck in there. It won't work in 1.0.2...I'll look around for a workaround, such as using readBytes(byte[] value), but it might be best just to issue a warning if using 1.0.2 or remove it completely.

    Cheers,
    Mark

  3. #3
    Join Date
    Sep 2004
    Posts
    4

    Default

    Hi Mark,

    Some time ago, I solved this problem myself by writing a JMS 1.1 adapter framework for JMS 1.0.2 using dynamic proxies. This solution allows programmers to use the full JMS 1.1 API, even if the underlying JMS message provider only supports JMS 1.0.2. I can donate this solution to the Spring framework if you're interested.

    Cheers,
    Robin

  4. #4
    Join Date
    Aug 2004
    Location
    New York, NY
    Posts
    74

    Default

    Hi,

    We did think of writing a 1.1 wrapper for 1.0.2 but felt it was too complex an approach given the relatively limited 'send' functionality in JmsTemplate. I'd be interested to see it nevertheless. How did you address the specific issue of getBodyLength()?

    - Mark

  5. #5
    Join Date
    Sep 2004
    Posts
    4

    Default

    The getBodyLength() implementation of my BytesMessageAdapter class looks like this:

    Code:
    private long getBodyLength() throws JMSException
    {
        // It is the responsibility of the caller to make sure that the
        // BytesMessage is in read-only mode when this method is called
        // as dictated by the JMS 1.1 API.
    
        // The implementation of this method is very tricky because we
        // need to make sure that the position of the stream is not
        // affected by the invocation of this method. Since there is
        // no way to find out what the current position of the stream
        // is, we actually need to read through the whole message twice.
    
        byte[] buffer = new byte[256 * 1024];
    	
        // First we read from the current position to the end of the
        // message. This gives us lenMinusPosition and leaves the position
        // at the end of the stream.
    
        long lenMinusPosition = 0;
        while (true) {
            int read = message.readBytes(buffer);
            if (read == -1) {
                break;
            }
            lenMinusPosition = lenMinusPosition + read;
        }
    
        // Then we reset the message and read through the entire message.
        // This gives us len.
    
        message.reset();
    
        long len = 0;
        while (true) {
            int read = message.readBytes(buffer);
            if (read == -1) {
                break;
            }
            len = len + read;
        }
    
        // From len and lenMinusPosition we can determine the original
        // postion. We then reset the message again and read until the
        // position.
    
        long position = len - lenMinusPosition;
    
        message.reset();
    
        while (position > buffer.length) {
            message.readBytes(buffer);
            position = position - buffer.length;
        }
        if (position > 0) {
            message.readBytes(buffer, (int) position);
        }
    
        // The message is now in the same state as before the method
        // was invoked.
    
        return len;
    }
    The whole adapter framework consists of 26 more Adapter and reverse Adapter classes so you were right in your observation that it is quite complex.

    A simpler solution would be to wrap the current getBodyLength() call in a try/catch block, but this is really a clutch.

    Code:
    long len;
    try {
        len = bytesMessage.getBodyLength();
    } catch (NoSuchMethodError eNoSuchMethod) {
        len = getJMS102BodyLength(bytesMessage);
    }
    where the getJMS102BodyLength() method would be implemented as above.

    Cheers,
    Robin.

  6. #6
    Join Date
    Aug 2004
    Location
    Linz, Austria
    Posts
    391

    Default

    Actually, we don't need to determine the body length of a BytesMessage per se; in particular, we don't need to care about resetting the message to its original position. All we need to achieve in SimpleMessageConverter is to convert the contents to a byte array.

    So on JMS 1.0.2, we could simply call readBytes with an array buffer as long as there is content available (checking the return value of readBytes), copying everything into a single byte array as result (possibly via ByteArrayOutputStream).

    Of course, the above is not too efficient, so we should keep using getBodyLength() on JMS 1.1. Thus, I guess it's appropriate to add a SimpleMessageConverter102 subclass with buffer-based copying of BytesMessage contents, used by JmsTemplate102 as default.

    I'll give such a SimpleMessageConverter102 subclass a try this weekend.

    Juergen

  7. #7
    Join Date
    Aug 2004
    Location
    Linz, Austria
    Posts
    391

    Default

    I've just added a corresponding SimpleMessageConverter102, used as default for JmsTemplate102.

    Juergen

  8. #8
    Join Date
    Sep 2004
    Posts
    4

    Default

    Hi Juergen,

    Is this solution transparent for developers using the Spring JMS framework? In other words, can they keep on using the SimpleMessageConvertor or do they need to explicitly instantiate a SimpleMessageConvertor102 somewhere? In the latter case, the code they write becomes dependent on a specific JMS version.

    And how about any future classes that want to use the JMS 1.1 BytesMessage.getBodyLength() method? Wouldn't you need to provide 102 versions for each of them as well?

    The reason why I wrote a JMS unification framework (of which the BytesMessageAdapter.getBodyLength() method shown in my previous post is just a part) is that I wanted to iron out the differences between JMS 1.0.2 and JMS 1.1 at the lowest possible level (i.e. at the JMS API level itself). Using this JMS unification framework, you never need to write any JMS version specific code, except for the code that creates the initial ConnectionFactory.

    Wouldn't this be a valuable addition to the Spring framework as well? Such a framework could sit underneath the current Spring JMS framework which can then be written entirely in terms of the JMS 1.1 API, removing the need for any JMS 1.0.2 specific code.

    Cheers,
    Robin.

Similar Threads

  1. Replies: 1
    Last Post: Jul 7th, 2005, 03:49 PM
  2. Channel and message transformation question
    By Alarmnummer in forum Architecture
    Replies: 12
    Last Post: May 11th, 2005, 05:06 PM
  3. Ripping out the application server: will it work?
    By ctassoni in forum Architecture
    Replies: 7
    Last Post: Feb 17th, 2005, 05:09 AM
  4. Replies: 3
    Last Post: Dec 22nd, 2004, 02:30 PM
  5. Spring can't work on Eclipse
    By ryanhowai in forum Architecture
    Replies: 1
    Last Post: Nov 9th, 2004, 06:50 AM

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •