6 Replies Latest reply on May 25, 2009 11:39 PM by ezanih

    Message Driven Bean onMessage() unable to detect JMS Message

    ezanih

      Hi there

      I created a RichFaces/Facelets + Seam + JMSQueue + JPAEntity JEE5 project in my Eclipse 3.4 using JBoss AS 4.2.2.GA and JBossESB 4.4.

      Workflow for the project is a simple CRUD operation as follows :- I have a Bidder JPA entity with properties BidderId (long) and BidderName(String). My RF/Facelets UI opens up a blank Create Bidder form and accepts the user input when the Save button is pressed. The bidder details which the user just entered is then sent in a queue across JBossESB ("queue/quickstart_jms_router_Request_gw") using a QueueSender initiated by a ConnectionFactory of type ObjectMessage ("I made the Bidder JPA entity serializable) from my SendJMSMessage.java class.

      A message-driven bean (TestMDB.java) listens to the "queue/quickstart_jms_router_Request_gw" queue and when the bidder entity gets on the queue, is supposed to activate the MDB's onMessage(msg) method. Within this method, I have just put in some System.out.println because I want to see the MDB receiving the bidder message sent. My ultimate aim is to persist the bidder to the db (to be done later).

      My problem : TestMDB.java doesn't appear to be receiving/detecting the bidder message sent through the allocated queue as none of my System.out.println in its onMessage(msg) is being called. What's wrong?

      Here's my SendJMSMessage.java which is correctly getting the bidder entity from the RichFaces/Facelets UI:

      package org.domain.testseam.jms;
      
      
      import java.util.Properties;
      import javax.jms.JMSException;
      import javax.jms.ObjectMessage;
      import javax.jms.Queue;
      import javax.jms.QueueConnection;
      import javax.jms.QueueConnectionFactory;
      import javax.jms.QueueSender;
      import javax.jms.QueueSession;
      import javax.naming.Context;
      import javax.naming.InitialContext;
      import javax.naming.NamingException;
      import org.domain.testseam.entity.Bidder;
      import org.jboss.seam.annotations.Name;
      
      
      
      @Name("messageSender")
      public class SendJMSMessage {
      
      
       public final String SENDING_QUEUE = "queue/quickstart_helloworld_Request_gw";
      
      
       QueueConnection conn;
       QueueSession session;
       Queue que;
      
      
      
       public void setupConnection() throws JMSException, NamingException
       {
       Properties properties1 = new Properties();
       properties1.put(Context.INITIAL_CONTEXT_FACTORY,
       "org.jnp.interfaces.NamingContextFactory");
       properties1.put(Context.URL_PKG_PREFIXES,
       "org.jboss.naming:org.jnp.interfaces");
       properties1.put(Context.PROVIDER_URL, "jnp://127.0.0.1:1099");
       InitialContext iniCtx = new InitialContext(properties1);
      
       Object tmp = iniCtx.lookup("ConnectionFactory");
       QueueConnectionFactory qcf = (QueueConnectionFactory) tmp;
       conn = qcf.createQueueConnection();
       que = (Queue) iniCtx.lookup(SENDING_QUEUE);
       session = conn.createQueueSession(false, QueueSession.AUTO_ACKNOWLEDGE);
       conn.start();
       System.out.println("[SendJMSMessage.java]: Connection Started");
       }
      
      
      
       public void stop() throws JMSException
       {
       conn.stop();
       session.close();
       conn.close();
       }
      
       public void sendAMessage(Bidder msg) throws JMSException {
      
       QueueSender send = session.createSender(que);
       ObjectMessage tm = session.createObjectMessage(msg);
       System.out.println("[SendJMSMessage.java] : sendAMessage() - Bidder.getBidderId(): " + msg.getId());
       System.out.println("[SendJMSMessage.java] : sendAMessage() - Bidder.getBidderName(): " + msg.getName());
       System.out.println("[SendJMSMessage.java] : sendAMessage() - sending Bidder through the JMS gateway...");
       send.send(tm);
       send.close();
       }
      
      
       public boolean sendMsg(Bidder bidder) {
       try {
       SendJMSMessage sm = new SendJMSMessage();
       sm.setupConnection();
       //sm.sendAMessage(args[0]);
       sm.sendAMessage(bidder);
       System.out.println("[SendJMSMessage.java] : MESSAGE SENT !");
       sm.stop();
       return true;
       }
       catch (Exception e) {
      
       System.out.println(e.getMessage());
       return false;
      
       }
      
       }
      }
      
      



      Here's my MDB whose onMessage(msg) method doesn't seem to be called:

      package org.domain.testseam.mdb;
      
      
      import javax.jms.Destination;
      import javax.jms.JMSException;
      import javax.jms.Message;
      import javax.jms.MessageListener;
      import javax.jms.TextMessage;
      import javax.jms.ObjectMessage;
      import javax.ejb.EJBException;
      import javax.ejb.MessageDriven;
      import javax.ejb.MessageDrivenBean;
      import javax.ejb.MessageDrivenContext;
      
      import org.jboss.seam.annotations.Name;
      import org.domain.testseam.entity.Bidder;
      
      
      @MessageDriven
      public class TestMDB implements MessageDrivenBean, MessageListener {
      
      
       private transient MessageDrivenContext mdbContext;
      
      
       //public empty constructor
       public TestMDB() { }
      
      
      
       // required for implements MessageListener
       public void onMessage(Message msg) {
      
       try {
      
       System.out.println("Hi there!");
      
       // check for message type: text or object message
       if (msg instanceof TextMessage) {
       TextMessage testMsg = (TextMessage) msg;
       System.out.println("TestMDB.java: TextMessage received in onMessage() method : " + testMsg.getText());
       }
      
       if (msg instanceof ObjectMessage) {
       ObjectMessage objectMessage = (ObjectMessage) msg;
       Object obj = (Object) objectMessage.getObject();
       System.out.print("TestMDB.java - in onMessage() method : ObjectMessage received (toString() - ) : " + obj.toString());
       System.out.print("[Now I, mdbBean, am going to convert intoa JPA entity and persist it with an EntityManager]");
       }
       }
      
       catch (JMSException e) {
       e.printStackTrace();
       }
      
       }
      
      
       public void ejbCreate ()
       {
       System.out.println("TestMDB.java: ejbCreate() - Message driven bean created.");
       }
      
      
      
       public void ejbDestroy ()
       {
       System.out.println("TestMDB.java: ejbDestroy() - Message driven bean destroyed.");
       }
      
      
       // required for implements MessageDrivenBean
       public void ejbRemove() throws EJBException {
      
      
       }
      
       // required for implements MessageDrivenBean
       public void setMessageDrivenContext(MessageDrivenContext ctx) throws EJBException {
       mdbContext = ctx;
       }
      
      }
      



      My jboss-ejb.xml :

      <?xml version = "1.0" encoding = "UTF-8"?>
      <jbossesb xmlns="http://anonsvn.labs.jboss.com/labs/jbossesb/trunk/product/etc/schemas/xml/jbossesb-1.0.1.xsd" parameterReloadSecs="5">
      
       <providers>
       <jms-provider name="JBossMQ" connection-factory="ConnectionFactory">
       <jms-bus busid="quickstartGwChannel">
       <jms-message-filter
       dest-type="QUEUE"
       dest-name="queue/quickstart_jms_router_Request_gw"
       />
       </jms-bus>
       <jms-bus busid="quickstartEsbChannel">
       <jms-message-filter
       dest-type="QUEUE"
       dest-name="queue/quickstart_jms_router_Request_esb"
       />
       </jms-bus>
      
       </jms-provider>
       </providers>
      
       <services>
       <service
       category="FirstServiceESB"
       name="SimpleListener"
       description="Hello World">
       <listeners>
       <jms-listener name="JMS-Gateway"
       busidref="quickstartGwChannel"
       is-gateway="true"
       />
       <jms-listener name="helloWorld"
       busidref="quickstartEsbChannel"
       />
       </listeners>
       <actions mep="OneWay">
       <action name="action1"
       class="org.jboss.soa.esb.samples.quickstart.helloworld.MyJMSListenerAction"
       process="displayMessage"
       />
       <action name="action2" class="org.jboss.soa.esb.actions.SystemPrintln">
       <property name="printfull" value="true"/>
       </action>
       <!-- The next action is for Continuous Integration testing -->
       <action name="testStore" class="org.jboss.soa.esb.actions.TestMessageStore"/>
       </actions>
       </service>
       </services>
      
      </jbossesb>
      


      and my ejb-jar.xml:

      <?xml version="1.0" encoding="UTF-8"?>
      
      
      <ejb-jar xmlns="http://java.sun.com/xml/ns/javaee"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/ejb-jar_3_0.xsd"
       version="3.0">
      
      
      <display-name>testSeam-ejb JAR</display-name>
      
      
      <enterprise-beans>
      
       <message-driven>
      
       <display-name>TestMDB</display-name>
      
       <ejb-name>TestMDB</ejb-name>
      
       <ejb-class>TestMDB</ejb-class>
      
       <messaging-type>javax.jms.MessageListener</messaging-type>
      
       <transaction-type>Container</transaction-type>
      
       <message-destination-type>javax.jms.Queue</message-destination-type>
      
       </message-driven>
      
      
      </enterprise-beans>
      
      
      
      <interceptors>
       <interceptor>
       <interceptor-class>org.jboss.seam.ejb.SeamInterceptor</interceptor-class>
       </interceptor>
      </interceptors>
      
      </ejb-jar>
      


      My console output is :

      16:47:11,312 INFO [STDOUT] [SendJMSMessage.java]: Connection Started
      16:47:11,343 INFO [STDOUT] [SendJMSMessage.java] : sendAMessage() - Bidder.getBidderId(): 1
      16:47:11,343 INFO [STDOUT] [SendJMSMessage.java] : sendAMessage() - Bidder.getBidderName(): Allan
      16:47:11,343 INFO [STDOUT] [SendJMSMessage.java] : sendAMessage() - sending Bidder through the JMS gateway...
      16:47:11,359 INFO [STDOUT] [SendJMSMessage.java] : MESSAGE SENT !
      16:47:11,375 ERROR [JmsGatewayListener] Problems invoking method <process>
      java.lang.reflect.InvocationTargetException
       at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
       at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
       at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
       at java.lang.reflect.Method.invoke(Method.java:585)
       at org.jboss.soa.esb.listeners.gateway.JmsGatewayListener.doRun(JmsGatewayListener.java:156)
       at org.jboss.soa.esb.listeners.lifecycle.AbstractThreadedManagedLifecycle.run(AbstractThreadedManagedLifecycle.java:115)
       at java.lang.Thread.run(Thread.java:595)
      Caused by: javax.jms.MessageFormatException: ClassNotFoundException: No ClassLoaders found for: org.domain.testseam.entity.Bidder
       at org.jboss.mq.SpyObjectMessage.getObject(SpyObjectMessage.java:154)
       at org.jboss.soa.esb.listeners.gateway.PackageJmsMessageContents.setESBMessageBody(PackageJmsMessageContents.java:160)
       at org.jboss.soa.esb.listeners.gateway.PackageJmsMessageContents.process(PackageJmsMessageContents.java:84)
       ... 7 more
      


      What seems to be going wrong?

        • 1. Re: Message Driven Bean onMessage() unable to detect JMS Mes
          beve

          Hi,

          Caused by: javax.jms.MessageFormatException: ClassNotFoundException: No ClassLoaders found for: org.domain.testseam.entity.Bidder

          Does this class exist in you .esb achive?

          My problem : TestMDB.java doesn't appear to be receiving/detecting the bidder message sent through the allocated queue as none of my System.out.println in its onMessage(msg) is being called. What's wrong?

          Where are you specifying that your MDB should listen to "queue/quickstart_jms_router_Request_gw"?
          Also note that this is the same queue that the esb jms gateway is configured to listen to. Perhaps you meant for this to be a topic?

          Regards,

          /Daniel




          • 2. Re: Message Driven Bean onMessage() unable to detect JMS Mes
            ezanih

            Hi there

            Bidder is a JPA entity implementing Serializable as follows :-

            package org.domain.testseam.entity;
            
            import java.io.Serializable;
            import javax.persistence.Entity;
            import javax.persistence.Id;
            import javax.persistence.GeneratedValue;
            import javax.persistence.Version;
            import org.hibernate.validator.Length;
            import org.jboss.seam.annotations.Name;
            
            @Entity
            @Name("bidder")
            public class Bidder implements Serializable {
            
             /**
             *
             */
             private static final long serialVersionUID = 1L;
             // seam-gen attributes (you should probably edit these)
             private Long id;
             private Integer version;
             private String name;
            
             // add additional entity attributes
            
             // seam-gen attribute getters/setters with annotations (you probably should edit)
            
             @Id @GeneratedValue
             public Long getId() {
             return id;
             }
            
             public void setId(Long id) {
             this.id = id;
             }
            
             @Version
             public Integer getVersion() {
             return version;
             }
            
             private void setVersion(Integer version) {
             this.version = version;
             }
            
             @Length(max = 20)
             public String getName() {
             return name;
             }
            
             public void setName(String name) {
             this.name = name;
             }
            }
            



            [Where are you specifying that your MDB should listen to "queue/quickstart_jms_router_Request_gw"?]

            I am specfying it in my ejb-jar.xml as follows:-

            <?xml version="1.0" encoding="UTF-8"?>
            
            
            <ejb-jar xmlns="http://java.sun.com/xml/ns/javaee"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/ejb-jar_3_0.xsd"
             version="3.0">
            
            
            <display-name>testSeam-ejb JAR</display-name>
            
            <enterprise-beans>
            
             <message-driven>
            
             <display-name>TestMDB</display-name>
             <ejb-name>TestMDB</ejb-name>
             <ejb-class>org.domain.testseam.mdb.TestMDB</ejb-class>
             <messaging-type>javax.jms.MessageListener</messaging-type>
             <transaction-type>Container</transaction-type>
             <message-destination-type>javax.jms.Queue</message-destination-type>
             <activation-config>
             <activation-config-property>
             <activation-config-property-name>destinationType</activation-config-property-name>
             <activation-config-property-value>javax.jms.Queue</activation-config-property-value>
             </activation-config-property>
             <activation-config-property>
             <activation-config-property-name>destination</activation-config-property-name>
             <activation-config-property-value>queue/quickstart_helloworld_Request_gw</activation-config-property-value>
             </activation-config-property>
             </activation-config>
            
             </message-driven>
            
            </enterprise-beans>
            
            
            <interceptors>
             <interceptor>
             <interceptor-class>org.jboss.seam.ejb.SeamInterceptor</interceptor-class>
             </interceptor>
            </interceptors>
            
            </ejb-jar>
            



            As stated earlier, I have defined the 2 queues (the Gateway queue and the ESB queue) in jboss-esb.xml.


            [Also note that this is the same queue that the esb jms gateway is configured to listen to]

            This was taken from the helloworld example of JBossESB. Actually, the JMS client initially sends an ESB-unaware message to the queue which gets converted to ESB-aware message and re-submitted.

            There seems to be a registry lookup process in between the conversion from ESB-unaware to ESB-aware. I did some surfing and found this:

            "...You need to make sure the SDO types are correctly registered before the
            deserialization of the SDO data objects. For generated SDO classes, you can
            call the XXXFactory.INSTANCE.register(...) method."

            Could this be the cause and how would I "register" my Bidder JPA entity class?

            • 3. Re: Message Driven Bean onMessage() unable to detect JMS Mes
              ezanih

              ...OK, before anybody says the queue names don't match up (I've used "queue/quickstart_helloworld_Request_gw" and "queue/quickstart_jms_router_Request_gw" in my posts), let me inform you that I have already changed all the names of the queues following that post to:-

              "queue/quickstart_helloworld_Request_gw"

              and

              "queue/quickstart_helloworld_Request_ESB"

              and cross-checked my code. It is still giving me that classpath error. I'm quite convinced it has something to do with that registration issue. Any ideas anyone ???

              • 4. Re: Message Driven Bean onMessage() unable to detect JMS Mes
                beve

                 

                Bidder is a JPA entity implementing Serializable as follows

                Does this mean that the answer is yes to my question? Does that class exist in the .esb archive?

                Does you MDB work without the esb? Try to deploy and test it separately first.



                • 5. Re: Message Driven Bean onMessage() unable to detect JMS Mes
                  ezanih


                  Hi Beve (and thanks for still being with me on this one!)

                  [Does this mean that the answer is yes to my question? Does that class exist in the .esb archive?]

                  I don't know, Beve...I don't know. My project is created in Eclipse Ganymede using the Seam Web Project Wizard which originally created the following project structure:-

                  testSeam-ear
                  |
                  ----testSeam\WebContents
                  |
                  ----testSeam-ejb

                  The project originally persisted the Bidder entity when the user inputs data for a blank Bidder form and clicks the Save button ( action="#{bidderHome.create}").

                  To test an MDB and JBossESB-integrated version of the above testSeam project, I added a SendJMSMessage.java and also the necessary config files (jboss-esb.xml, ejb-jar.xml, deployment.xml, jbmq-queue-service.xml, jbm-queue-service.xml, jboss-esb-properties.xml, jndi.properties, juddi.properties) and also created a message-driven bean to listen to the queue.

                  My queues seem to have been configured correctly as Eclipse doesn't complain about the queues and logs 'Message sent!', the problem is only the classloader problem for my Bidder entity. You are right...somehow I have to include it in my Eclipse project but I don't know how and where.

                  My testSeam-ejb project structure is as follows:-


                  testSeam-ejb
                  |
                  ---- org.domain.testseam.entity
                  |
                  ---- Bidder.java (the JPA Bidder entity)
                  |
                  ---- org.domain.testseam.jms
                  |
                  ---- SendJMSMessage.java (JMS client)
                  |
                  ---- org.domain.testseam.mdb
                  |
                  ---- MyMDBBean.java (MDB bean listening to a JMS queue)



                  So to answer your question is the Bidder.class included in the esb file, I would have to say that there doesn't seem to be any esb file because the project compiles to an ear file (testSeam-ear.ear) which comprises of testSeam.war and testSeam-ejb.jar.

                  So now how do I proceed ?

                  • 6. Re: Message Driven Bean onMessage() unable to detect JMS Mes
                    ezanih

                    Uhm...this is quite...strange, but I switched on my Eclipse today and...thank God...my Message Driven Bean decided to start listening today. The project now works (!) and looking back, I hardly made any changes except:-

                    1. Removing the @MessageDriven annotation just before the MDB class declaration.

                    2. Changed my local variable declaration from this:

                    private transient MessageDrivenContext mdbContext;
                    .
                    .
                    .
                    public void setMessageDrivenContext(MessageDrivenContext ctx) throws EJBException
                    {
                    mdbContext = ctx;
                    }
                    


                    to this:

                    public void setMessageDrivenContext(MessageDrivenContext ctx) throws EJBException
                    {
                    MessageDrivenContext mdbContext = ctx;
                    }
                    



                    Can anyone tell me how this made my project work ?