JavaFX - JMS Unexpected Null Pointer Exception.

In the book, JavaFX - Developing Rich Internet Applications, I wrote a Code Recipe on how to include a JMS feed into a JavaFX application. The basic premise is that when the JMS onMessage method is called on the javax.jms.MessageListener interface, the calling thread will be from the JMS framework, so this message needs to be pushed over to the main JavaFX thread using com.sun.javafx.runtime.Entry.deferAction( Runnable ). Here is the example from the book from Subscriber.java:

@Override
public void onMessage(final Message msg) {
    try {
            // must run this on the JavaFX Main thread
            // If you don't you will eventually get exceptions
            // in the JavaFX code.
            Entry.deferAction( new Runnable() {
                @Override
                public void run() {
                    fxListener.onMessage(msg);
                }
            } );

    } catch (Exception ex) {
            Logger.getLogger(Subscriber.class.getName()).log(Level.SEVERE, null, ex);
    }
}

This all runs fine on my machine when I spit out messages, 1 per millisecond. However, I was working with a colleague here at Sun who was using this code pattern with a real live log server, and when he cranked it up, he started to get Null Pointer Exceptions when he fetched from  the Message object within the JavaFX main thread.

This perplexed us for a while, and on the intuition that the JMS framework may have been reusing the Message object on subsequent messages, we inserted logic in the Java onMessage() code block to fetch the message contents before pushing them into the JavaFX main thread. Voila, the Null Pointer Exceptions stopped. Evidently, we were encountering a race condition where the JMS Framework was reusing or clearing the Message object faster than the JavaFX thread could consume it.  This behavior from the JMS framework was unexpected, but I guess it is an optimization for performance.

To overcome this race condition, it is necessary to make a copy of the message data prior to the javax.jms.MessageListener.onMessage() method returning. As a result, I have now modified the example to look like this:

    if(msg instanceof TextMessage ) {
        final Message copy = topicSession.createTextMessage(((TextMessage)msg).getText());⁞
        Entry.deferAction( new Runnable() {
            @Override
            public void run() {
                fxListener.onMessage(copy);
            }
        } );
    }

I will be updating the example from the book. But the lesson learned from this is to be wary when using frameworks that you have no control over.



Comments:

Post a Comment:
  • HTML Syntax: NOT allowed
About

jimclarke

Search

Categories
Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today