1 2 Previous Next 19 Replies Latest reply: Jul 19, 2007 9:32 AM by Mark Little RSS

Calling MDB from JBOSSESB Service

Govinda Attal Newbie

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
    Govinda Attal Newbie

    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
    Daniel Bevenius Master

    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
    Govinda Attal Newbie

    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
    Daniel Bevenius Master

    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
    Govinda Attal Newbie

    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
    Daniel Bevenius Master

    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
    Mark Little Master

    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
    Daniel Bevenius Master

    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
    Mark Little Master

    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
    Daniel Bevenius Master

     

    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
    Mark Little Master

    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
    Govinda Attal Newbie

    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
    Daniel Bevenius Master

    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
    Govinda Attal Newbie

    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