1 2 3 4 Previous Next 48 Replies Latest reply on Apr 10, 2011 1:28 PM by Bernard Labno

    JMS MessageListener in a web application

    Naresh Bhatia Newbie

      I am using JBoss Seam to create a web application, i.e. it is packaged as a war, not as an ear. Is it possible to receive JMS messages in such an application? Since I don't have access to message-driven beans, I have coded a MessageListener to receiver JMS messages:


      @Name("myListener")
      public class MyListener implements MessageListener {
      
          @Override
          public void onMessage(Message message) {
              ...
          }
      }
      



      But how do I tell JBoss to trigger this listener? I am using JBoss 4.2.3 plus JBossMQ.


      Thanks.


      Naresh

        • 1. Re: JMS MessageListener in a web application
          Orestes Dominguez Newbie

          Seam has POJO-based JMS support, you will not have any problem to use JMS in your war application

          • 2. Re: JMS MessageListener in a web application
            Nikolay Elenkov Master

            You will need to get a Session, create a QueueReceiver and call setMessageListener to register your bean.
            Btw, you probably want a listener with application scope for this to work.
            Something like:


            @In
            private QueueSession queueSession;
            @In
            private MyListener myListener;
            ...
            Queue queue = lookupQueue(); // get queue from JNDI
            QueueReceiver receiver = queueSession.createReceiver(queue);
            receiver.setMessageListener(myListener)
            
            

            • 3. Re: JMS MessageListener in a web application
              Naresh Bhatia Newbie

              Thanks Orestes and Nikolay. I will give it a try!

              • 4. Re: JMS MessageListener in a web application
                Angel Segarra Newbie

                So did you managed to get this going? if so could you give some details as to how you did it? There is nothing in the ref docs or the Seam in Action book on how to do this which is a major oversight.

                • 5. Re: JMS MessageListener in a web application
                  Naresh Bhatia Newbie

                  I have not been able to solve this yet. I did create a listener in Application scope (as per Nikolay's suggestion). However the bean is never created because no one really calls it. Is there any way to force instantiation of a bean during application startup? I have looked through the manual as well as the Seam examples - this topic is covered nowhere!


                  Here's my code:


                  @Name("myListener")
                  @Scope(ScopeType.APPLICATION)
                  public class MyListener implements MessageListener {
                  
                      @In(create=true) private QueueSession queueSession;
                      private QueueReceiver queueReceiver;
                  
                      @Create
                      public void init() {
                          try {
                              InitialContext ctx = new InitialContext();
                              Queue myQueue = (Queue)ctx.lookup("queue/myqueue");
                              QueueReceiver = queueSession.createReceiver(myQueue);
                              QueueReceiver.setMessageListener(this);
                          }
                          catch (NamingException e) {
                              throw new RuntimeException("MyListener initialization failed", e);
                          }
                          catch (JMSException e) {
                              throw new RuntimeException("MyListener initialization failed", e);
                          }
                      }
                      
                      @Override
                      public void onMessage(Message message) {
                          ...
                      }
                  }

                  • 6. Re: JMS MessageListener in a web application
                    Nikolay Elenkov Master

                    You can use @AutoCreate to create it automatically. Or you could observe the postInitialization event
                    and do your setup in the observer method:


                    @Name("startup)
                    public class Startup {
                    
                      @Observer("org.jboss.seam.postInitialization")
                      public void startup() {
                        // wire MessageListeners, etc
                      }
                    }
                    

                    • 7. Re: JMS MessageListener in a web application
                      Naresh Bhatia Newbie

                      Thanks Nikolay. I have tried your suggestions, but things aren't working yet.


                      It seems that @AutoCreate does not automatically create a bean - it creates the bean only if it needs to be injected in something else (which was not the case in my earlier code).


                      Well, I took out the initialization code from my listener and put it in a separate startup bean as you suggested. I also added the postInitialization observer. Now the postInitialization method is indeed being called by Seam, but this call does not seem to initialize the bean itself. Although I have @AutoCreate on my listener it is not injected into my startup bean. I must be missing something!!!


                      Here's my latest code:


                      @Name("myListenerInitializer")
                      @Scope(ScopeType.APPLICATION)
                      @AutoCreate
                      public class MyListenerInitializer {
                      
                          @In(create=true) private QueueSession queueSession;
                          @In(create=true) MyListener myListener;
                          private QueueReceiver queueReceiver;
                      
                          @Observer("org.jboss.seam.postInitialization")
                          public void init() {
                              try {
                                  InitialContext ctx = new InitialContext();
                                  Queue queue = (Queue)ctx.lookup("queue/myqueue");
                                  queueReceiver = queueSession.createReceiver(queue);
                                  queueReceiver.setMessageListener(myListener);
                              }
                              catch (NamingException e) {
                                  throw new RuntimeException("myListener initialization failed", e);
                              }
                              catch (JMSException e) {
                                  throw new RuntimeException("myListener initialization failed", e);
                              }
                          }
                      }
                      
                      @Name("myListener")
                      @Scope(ScopeType.APPLICATION)
                      @AutoCreate
                      public class MyListener implements MessageListener {
                      
                          @Override
                          public void onMessage(Message message) {
                              ...
                          }
                      }
                      



                      Here's the exception I am getting:


                      ERROR Exception sending context initialized event to listener instance of class org.jboss.seam.servlet.SeamListener
                      org.jboss.seam.RequiredException: @In attribute requires non-null value: myListenerInitializer.myListener
                      

                      • 8. Re: JMS MessageListener in a web application
                        Naresh Bhatia Newbie

                        Never mind :-). myListener IS being injected in MyListenerInitializer. I had made so many changes that the application was not built correctly somewhere along the line. I did a fresh build and this issue went away.


                        Still not done yet. It seems that as soon as the initializer sets the message listener, messages are being picked up from the queue, but after initialization is done and application is in steady state, the listener stops picking up any new messages. Bit puzzled by this. Any ideas?


                        • 9. Re: JMS MessageListener in a web application
                          Naresh Bhatia Newbie

                          Some more insight into the problem. It appears that the session is already closed when the listener is trying to use it. Here's the exception:


                          [MessageListenerThread - myqueue] [org.jboss.mq.SpyMessageConsumer] Message consumer closing due to error in listening thread.
                          javax.jms.IllegalStateException: The session is closed
                               at org.jboss.mq.SpySession.checkClosed(SpySession.java:1149)
                               at org.jboss.mq.SpySession.doAcknowledge(SpySession.java:175)
                               at org.jboss.mq.SpyMessage.doAcknowledge(SpyMessage.java:353)
                               at org.jboss.mq.SpyMessageConsumer.run(SpyMessageConsumer.java:719)
                               at java.lang.Thread.run(Thread.java:619)
                          



                          Any ideas?


                          (P.S. I request the Seam developers to provide an example of this use case - listening to JMS messages using POJO beans)

                          • 10. Re: JMS MessageListener in a web application
                            Naresh Bhatia Newbie

                            This is a pretty hard problem. Turns out that QueueSession is managed by seam and has event scope - it is being closed right after my init function returns. To solve this issue, I created my own QueueSession - this gets me past the problem, but now another problem shows up.


                            Since MessageListner is invoked on its own thread, seam knows nothing about it and hence no contexts are created. Hence I cannot call any Seam components from this thread. Any attempt to get a component using Component.getInstance() throws this exception:


                            java.lang.IllegalStateException: No application context active
                                 at org.jboss.seam.Component.forName(Component.java:1902)
                                 at org.jboss.seam.Component.getInstance(Component.java:1962)
                                 at org.jboss.seam.Component.getInstance(Component.java:1940)
                                 at org.jboss.seam.Component.getInstance(Component.java:1934)
                                 at org.jboss.seam.Component.getInstance(Component.java:1929)
                                 at MyListener.getMyMessageProcessor(MyListener.java:118)
                                 at MyListener.onMessage(MyListener.java:94)
                                 at org.jboss.mq.SpyMessageConsumer.run(SpyMessageConsumer.java:697)
                                 at java.lang.Thread.run(Thread.java:619)
                            



                            Is there any way to initialize the Seam container when my message listener is called?


                            I suppose that other people have also run into this problem (see here), but no solution has been proposed.


                            Please help.


                            Thanks.


                            Naresh

                            • 11. Re: JMS MessageListener in a web application
                              Leo van den berg Master

                              I have a similar problem. We have created an application which presents an overview of (traffic) incidents, which is viewed by different users. Whenever somebody updatss an attribute or creeates a new incident a Notification is created is and send to a JMS topic.


                              Incidents are created through the user-interface or come in through a RestService. This service also creates  a notification.


                              We want to raise an event after receiving such a notification. However we don't have access to the Seam context within the OnMessage method.


                              Trying to get an instance with the getInstance doesn' work either. Can anybody help on this issue on how to get access the Seam context within a MesageListener. We tried it with MDB and POJO, both no-go.


                              Thanks


                              Leo


                              P.S. I can share the JMS Listener code if you want.

                              • 12. Re: JMS MessageListener in a web application
                                Nikolay Elenkov Master

                                Naresh Bhatia wrote on Jun 03, 2009 22:19:


                                This is a pretty hard problem. Turns out that QueueSession is managed by seam and has event scope - it is being closed right after my init function returns. To solve this issue, I created my own QueueSession - this gets me past the problem, but now another problem shows up.


                                Looking at my code, that's what I ended up doing. Should have mentioned it earlier though.




                                Since MessageListner is invoked on its own thread, seam knows nothing about it and hence no contexts are created. Hence I cannot call any Seam components from this thread. Any attempt to get a component using Component.getInstance() throws this exception:



                                My onMessage is pretty simple, so didn't run in this problem. You could try starting up the application context using Lifecycle.beginCall(), but I haven't actually tried this.


                                • 13. Re: JMS MessageListener in a web application
                                  Naresh Bhatia Newbie

                                  Nikolay, thanks for the clarification. Unfortunately, my message listener needs to access the database and hence I totally need the beans.


                                  I was earlier under the impression that this would work if I switched to MDBs (and hence to an EAR), but Leo's post suggested to the contrary. So I converted my app to an EAR and switched to MDBs but I am still getting a NullPointerException, meaning no injection is taking place. Again, I could be missing something, but at this point I would rather wait for a word from Seam developers than to put more time into this issue.

                                  • 14. Re: JMS MessageListener in a web application
                                    Nikolay Elenkov Master

                                    If you have an MDB, things should be easy. You can inject the persistence context, or SLSB's (J2EE injection, not Seam injection).
                                    You could look up stuff via JNDI as well, so you don't need to call Seam API's at all.


                                    Say:


                                    @MessageDriven
                                    public class MyListener implements MessageListener {
                                    
                                      @PersistenceContext
                                      private EntityManager em;
                                    
                                      @EJB
                                      private MyProcessor procesor;
                                    
                                      public void onMessage(Message message) {
                                       // do your DB stuff
                                     }
                                    }
                                    

                                    1 2 3 4 Previous Next