1 2 Previous Next 19 Replies Latest reply on Jul 19, 2007 9:32 AM by marklittle

    Calling MDB from JBOSSESB Service

    govindaattal

      Hello,

      I have some MDBs developed using 2.1 Spec running on
      JBOSS 4.0.5 AS along with JBOSSESB 4.2MR2.

      I wish to call them in JBOSSESB services.
      Please correct me if I am wrong...
      I thought that it can be acheived in two ways,

      1. calling MDB using initialContext/connection/session/queue inside an Action in the pipeline

      2. Using JMSrouter and passing jndiName of queue of the MDB as property....

      For first method:-

      
       Body msgBody = actualInutMessage.getBody();
       String strContents = new String(msgBody.getContents());
      
      InitialContext initCtx = new InitialContext();
       Object tmp = initCtx.lookup("QueueConnectionFactory");
       QueueConnectionFactory qConFactory = (QueueConnectionFactory)tmp;
      
       mdbQueue = (Queue)initCtx.lookup("queue/TrialTextService");
       conn = qConFactory.createQueueConnection();
       session = conn.createQueueSession(false, QueueSession.AUTO_ACKNOWLEDGE);
       conn.start();
      
      QueueSender sender = session.createSender(mdbQueue);
      
       TextMessage txtMessage = session.createTextMessage();
       txtMessage.setText(strContents);
       sender.send(txtMessage);
      
       conn.stop();
       session.close();
       conn.close();
      
       return actualInutMessage;
      
      


      But for this method I cannot call conn.stop()/conn.close()/session.close() ... as against J2EE Specs 1.4 Section 6.6 {---- JBOSS AS gave me error messages on the console -----}

      At the same time I cannot have innumerable jms connections without closing them. So for the time I have made connections and sessions as static variables.

      I am not happy with this solution. One reason I keep connections open for may be life time.....


      Now the second soltion using JMSRouter...

      
      <action name="callMDB" class="org.jboss.soa.esb.actions.routing.JMSRouter">
       <property name="jndiName" value="queue/TrialTextService"/>
       <property name="unwrap" value="true"></property>
       </action>
      
      
      
      


      here jndiname=queue/TrialTextService

      is jndi value for queue of the message driven bean. I think unwrapping the message will send [JBOSS ESB Aware message] minus [jboss esb specific headers/properties] ie., [message body only ]to queue of the MDB....

      Now I have a problem....

      My MDB is configured to receive TextMessage; Client sends a text Message.

      But when this action JMSRouter is applied it sends Bytes Message to MDB....

      My question is,

      What ways an ESB service to send
      TextMessage, ObjectMessage, MapMessage, XMLMessage to Actual JMS services (business services.... I prefer to call esb services as proxy services.....) ?



        • 1. Re: Calling MDB from JBOSSESB Service
          govindaattal

          Hello ALL,

          Please help me, I am stuck with this usecase...

          How can I call existing MDBs, JMSServices from JBOSS ESB action processing pipeline, passing them messages of types like text, object, bytes, xml, map which they are expecting?


          Regards,
          Govinda Attal.


          • 2. Re: Calling MDB from JBOSSESB Service
            beve

            Hi Govinda,

            I'll try to answer what I can.

            The JMSRouter's property "unwrap". when set to true. will tell the ESB to extract what is in the ESB Message object's body.

            What this means is that if the Object in the ESB Messages body is of type String, then the JMSRouter will send a TextMessage.
            If the body object is of type byte[] then a ByteMessage will be sent. And if none of the above an ObjectMessage will be sent.

            Setting "unwrap" to false will serialize the whole ESB Message object and send it as an ObjectMessage.

            Let me know if you have any other questions about the JMSRouter and I'll try to answer them.

            Regards,

            Daniel

            • 3. Re: Calling MDB from JBOSSESB Service
              govindaattal

              Hello Daniel,

              I checked source code of JMSRouter.java, which is confirms exactly what you are saying.

              
              if (oCurr instanceof String) {
               TextMessage oMsg = queueSetup.jmsSession.createTextMessage();
              
               if(logger.isDebugEnabled()) {
               logger.debug("Sending Text message: [" + oCurr + "] to destination [" + queueSetup.queueName + "].");
               }
               oMsg.setText((String)oCurr);
               setStringProperties(oMsg);
               queueSetup.jmsProducer.send(oMsg);
               } else {
               ObjectMessage oMsg = queueSetup.jmsSession.createObjectMessage();
              
               if(logger.isDebugEnabled()) {
               logger.debug("Sending Object message: [" + oCurr + "] to destination [" + queueSetup.queueName + "].");
               }
               oMsg.setObject((Serializable) oCurr);
               setStringProperties(oMsg);
               queueSetup.jmsProducer.send(oMsg);
               }
              
              


              But MDB that I have developed is getting only one type of message that is BytesMessage..

              In jboss-esb.xml, my action processing pipeline has only one action 'JMSRouter' with unwrap set true.


              I changed my JMSClient to send the following three types of JMSMessages: text,byte and object

              But yet in MDB when I check
              inputMsg instanceof TextMessage/ObjectMessage/BytesMessage
              ....
              for all three input messages only 'if condition of BytesMessage' is hit.




              Regards,
              Govinda.




              • 4. Re: Calling MDB from JBOSSESB Service
                beve

                Hi Govinda,

                could you show me how you are setting the object on the ESB Message Object?
                Are you doing it like this:

                ActionUtils.setTaskObject( message , object);
                


                Regards,

                Daniel

                • 5. Re: Calling MDB from JBOSSESB Service
                  govindaattal

                  Hello Daniel,

                  I am not setting any object on the ESB message object. The code that I added in earlier reply was part of
                  JMSRouter.java 's public Message process(Message) method.

                  I am sorry if I confused you.

                  My jbossesb service ".ESB" package has only only jboss-queue-service.xml and jboss-esb.xml

                  Contents of jobss-esb.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"
                   jndi-URL="jnp://127.0.0.1:1099" jndi-context-factory="org.jnp.interfaces.NamingContextFactory"
                   jndi-pkg-prefix="org.jboss.naming:org.jnp.interfaces">
                  
                   <jms-bus busid="trialESBServiceGWChannel">
                   <jms-message-filter dest-type="QUEUE"
                   dest-name="queue/trialESBServiceGW" />
                   </jms-bus>
                  
                   </jms-provider>
                   </providers>
                   <services>
                  
                   <service category="TrialESBServices"
                   name="TrialESBServiceListener"
                   description="Trial ESB serivce calls TrialTextMDB business service">
                   <listeners>
                   <jms-listener name="JMS-Gateway" busidref="trialESBServiceGWChannel" maxThreads="1" is-gateway="true" />
                   </listeners>
                  
                   <actions>
                   <action name="callMDB" class="org.jboss.soa.esb.actions.routing.JMSRouter">
                   <property name="jndiName" value="queue/TrialTextService" ></property>
                   <property name="unwrap" value="true"></property>
                   </action>
                   </actions>
                  
                   </service>
                   </services>
                  </jbossesb>
                  
                  
                  




                  And my JMS Client Application does something like this

                  
                  TextMessage txtMessage = session.createTextMessage();
                   txtMessage.setText("40082" + ": " + "Text");
                   sender.send(txtMessage);
                  
                   ObjectMessage objMsg = session.createObjectMessage();
                   objMsg.setObject("40082: " + "Object");
                   sender.send(objMsg);
                  
                  



                  Regards,

                  Govinda

                  • 6. Re: Calling MDB from JBOSSESB Service
                    beve

                    Hi Govinda,

                    ok, I see what's happening now. The JMSGateway is packaging the JMS Message contents as a byte[]. This can be found in PackageJMSMessage:

                    public Message process (Object obj) throws JMSException, IOException
                     {
                     if (!(obj instanceof javax.jms.Message))
                     throw new IllegalArgumentException(
                     "Object must be instance of javax.jms.Message");
                    
                     byte[] bytes = getMessageContent((javax.jms.Message) obj);
                     if (null == bytes) return null;
                    
                     javax.jms.Message jmsMsg = (javax.jms.Message) obj;
                     Message message = MessageFactory.getInstance().getMessage();
                     message.getBody().setByteArray(getMessageContent(jmsMsg));
                    
                     if (jmsMsg instanceof ObjectMessage) {
                     ObjectMessage msg = (ObjectMessage) jmsMsg;
                     message.getBody().add(msg.getObject());
                     }
                    
                     Enumeration<String> EE = jmsMsg.getPropertyNames();
                     if (null != EE)
                     {
                     while (EE.hasMoreElements())
                     {
                     String name = EE.nextElement();
                     Object value = jmsMsg.getObjectProperty(name);
                     if (null != value)
                     message.getProperties().setProperty(name, value);
                     }
                     }
                     return message;
                     }
                    
                     private byte[] getMessageContent (javax.jms.Message jMess) throws JMSException, IOException
                     {
                     if (jMess instanceof TextMessage)
                     return ((TextMessage) jMess).getText().getBytes();
                    
                     if (jMess instanceof BytesMessage)
                     {
                     BytesMessage jBytes = (BytesMessage) jMess;
                     ByteArrayOutputStream out = new ByteArrayOutputStream();
                     byte[] ba = new byte[1000];
                     int iQread;
                     while (-1 != (iQread = jBytes.readBytes(ba)))
                     if (iQread > 0) out.write(ba, 0, iQread);
                     out.close();
                     return out.toByteArray();
                     }
                    
                     if (jMess instanceof ObjectMessage)
                     return ((ObjectMessage) jMess).getObject().toString()
                     .getBytes();
                     JmsGatewayListener._logger
                     .warn("Message type " + jMess.getClass().getSimpleName() + " not supported - Message is ignored");
                     return null;
                     }
                    

                    I think that it should really be setting the Message's body to the type of JMSMessage.
                    So, if the incoming was a JMS Message of type TextMessage then it should be something like this:
                    ActionUtils.setTaskObject( message , jmsMessage.getText());
                    


                    Let see if we can get some comments from the other in the ESB team and if they agree I'll create a JIRA for this.

                    Regards,

                    Daniel

                    • 7. Re: Calling MDB from JBOSSESB Service
                      marklittle

                      Couldn't you just augment:

                      if (jmsMsg instanceof ObjectMessage) {
                       ObjectMessage msg = (ObjectMessage) jmsMsg;
                       message.getBody().add(msg.getObject());
                       }
                      


                      to also cope with the other types?

                      • 8. Re: Calling MDB from JBOSSESB Service
                        beve

                        You could also specify your own packer to handle this. The default packer can be overridde in the listener configuration like this:

                        <jms-listener
                         is-gateway="true"
                         name="JMS-Gateway"
                         busidref="RequestGW"
                         maxThreads="1">
                         <property name="composer-class" value="se.xxx..CorrelationPacker"/>
                         <property name="composer-process" value="process"/>
                        </jms-listener>


                        Example of a Packer:
                        public class CorrelationPacker
                        {
                         @SuppressWarnings( "unused")
                         private final ConfigTree configTree;
                        
                         public CorrelationPacker(ConfigTree configTree)
                         {
                         this.configTree = configTree;
                         }
                        
                         public Message process( Object obj ) throws JMSException, IOException
                         {
                         return // create ESB MessageObject here...
                         }
                        




                        • 9. Re: Calling MDB from JBOSSESB Service
                          marklittle

                          Yes, that'd work too.

                          The problem about changing it so it removes the byte pack is that it may affect existing users. Augmenting so we either have a superset of the capability, or allow developers to customize for their own deployments, makes more sense at this stage of the release cycle.

                          • 10. Re: Calling MDB from JBOSSESB Service
                            beve

                             

                            Couldn't you just augment:

                            Yeah, you could do that but I think that as long as getMessageContent() is getting called, which is checking the type of JMSMessage and then returning a byte[], it would less efficient.

                            How about a changing getMessageContent() to return a JMSMessage object and hide all this there and saving checking the type of JMSMessage twice?

                            /Daniel

                            • 11. Re: Calling MDB from JBOSSESB Service
                              marklittle

                              Well at the moment we're potentially putting the JMS message into an ESB message twice as far as I can see:

                              javax.jms.Message jmsMsg = (javax.jms.Message) obj;
                               Message message = MessageFactory.getInstance().getMessage();
                               message.getBody().setByteArray(getMessageContent(jmsMsg));
                              
                               if (jmsMsg instanceof ObjectMessage) {
                               ObjectMessage msg = (ObjectMessage) jmsMsg;
                               message.getBody().add(msg.getObject());
                               }
                              


                              once (and always at least once) as the byte array and once as the ObjectMessage. Although we'd like to change that, it may affect existing users. Hence my suggestion to leave it as is, but also add the jmsMsg if it's another recognized type.



                              • 12. Re: Calling MDB from JBOSSESB Service
                                govindaattal

                                Hello Daniel, Mark


                                I did following changes and it seems to be working.

                                jboss-esb.xml

                                
                                ...
                                ...
                                <listeners>
                                
                                 <jms-listener name="JMS-Gateway"
                                 busidref="trialESBServiceGWChannel" maxThreads="1"
                                 is-gateway="true" >
                                
                                 <property name="composer-class" value="myjms.examples.packers.MyCorrelationPacker"/>
                                 <property name="composer-process" value="process"/>
                                
                                 </jms-listener>
                                
                                </listeners>
                                ...
                                ...
                                <actions>
                                 <action name="callMDB"
                                 class="org.jboss.soa.esb.actions.routing.JMSRouter">
                                 <property name="jndiName"
                                 value="queue/TrialTextService" />
                                 <property name="unwrap" value="true"></property>
                                 </action>
                                </actions>
                                ...
                                ...
                                
                                



                                MyCorrelationPacker.java
                                
                                public class MyCorrelationPacker
                                {
                                 @SuppressWarnings( "unused")
                                 private final ConfigTree configTree;
                                
                                 public MyCorrelationPacker(ConfigTree configTree)
                                 {
                                 this.configTree = configTree;
                                 }
                                
                                 public Message process( Object obj ) throws JMSException, IOException
                                 {
                                 if (!(obj instanceof javax.jms.Message))
                                 throw new IllegalArgumentException(
                                 "Object must be instance of javax.jms.Message");
                                
                                 byte[] bytes = getMessageContent((javax.jms.Message) obj);
                                 if (null == bytes) return null;
                                
                                 javax.jms.Message jmsMsg = (javax.jms.Message) obj;
                                
                                 Message message = MessageFactory.getInstance().getMessage();
                                
                                 /////////// message.getBody().setByteArray(getMessageContent(jmsMsg)); ///////////
                                 /////////// I am afraid org.jboss.soa.esb.message.Body doesnot have this symbol [setByteArray]
                                 /////////// message.getBody().setContents(getMessageContent(jmsMsg)); ///////////
                                
                                 if (jmsMsg instanceof ObjectMessage)
                                 {
                                 System.out.println("SYSTEM Object: Packer detected Object Message");
                                 ObjectMessage objMsg = (ObjectMessage) jmsMsg;
                                 /////////// message.getBody().add(msg.getObject()); ///////////
                                
                                 ActionUtils.setTaskObject( message , objMsg.getObject());
                                
                                 System.out.println("SYSTEM Object: " + objMsg.getObject());
                                 }
                                 else if(jmsMsg instanceof TextMessage)
                                 {
                                 System.out.println("SYSTEM Text: Packer detected Text Message");
                                 TextMessage txtMsg = (TextMessage) jmsMsg;
                                 /////////// message.getBody().add(txtMsg.getText()); ///////////
                                
                                 ActionUtils.setTaskObject( message , txtMsg.getText());
                                
                                 System.out.println("SYSTEM Text: " + txtMsg.getText());
                                 }
                                
                                
                                 Enumeration<String> EE = jmsMsg.getPropertyNames();
                                 if (null != EE)
                                 {
                                 while (EE.hasMoreElements())
                                 {
                                 String name = EE.nextElement();
                                 Object value = jmsMsg.getObjectProperty(name);
                                 if (null != value)
                                 message.getProperties().setProperty(name, value);
                                 }
                                 }
                                 return message;
                                 }
                                
                                 private byte[] getMessageContent (javax.jms.Message jMess) throws JMSException, IOException
                                 {
                                
                                 if (jMess instanceof TextMessage)
                                 return ((TextMessage) jMess).getText().getBytes();
                                
                                 if (jMess instanceof BytesMessage)
                                 {
                                 BytesMessage jBytes = (BytesMessage) jMess;
                                 ByteArrayOutputStream out = new ByteArrayOutputStream();
                                 byte[] ba = new byte[1000];
                                 int iQread;
                                 while (-1 != (iQread = jBytes.readBytes(ba)))
                                 if (iQread > 0) out.write(ba, 0, iQread);
                                 out.close();
                                 return out.toByteArray();
                                 }
                                
                                 if (jMess instanceof ObjectMessage)
                                 return ((ObjectMessage) jMess).getObject().toString()
                                 .getBytes();
                                 /*
                                 //// JmsGatewayListener._logger.warn("Message type " + jMess.getClass().getSimpleName() + " not supported - Message is ignored");
                                 */
                                 return null;
                                 }
                                
                                }
                                
                                


                                Well, I have got results that I was expecting after I did these changes but I do fear that it may cause some unforeseen troubles. Please let me know whether the above changes are correct or need some tweaking or I have not understood it at all....


                                Regards,
                                Govinda.



                                • 13. Re: Calling MDB from JBOSSESB Service
                                  beve

                                  Hi Govinda,

                                  I've create this jira http://jira.jboss.com/jira/browse/JBESB-724.

                                  This will should give the same results for you as you are seing now. I'll post to this thread when it's completed incase you would like to switch later on (will make your esb config a little cleaner if nothing else :) ).

                                  Thanks,

                                  Daniel

                                  • 14. Re: Calling MDB from JBOSSESB Service
                                    govindaattal

                                    Hello Daniel,

                                    Thanks for creating JIRA... And yes I will surely like to see my esb-configuration files look cleaner :).
                                    I look forward for the solution.

                                    I am glad for time and inputs you gave.

                                    Thanks & Regards,
                                    Govinda

                                    1 2 Previous Next