You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@servicemix.apache.org by Akhil Srinivasan <ak...@gmail.com> on 2006/01/24 15:28:38 UTC

Manually call the JmsSenderComponent

I wanted to use the JmsSenderComponent to send a TextMessage back to a
client.
Its mainly to a sample application on servicemix.

The use case is
1. Client sends Hello TextMessage to a queue.
2. JmsService pick its up and routes it to my servicemix component.
3. My component sends world to the JmsSerderComponent
4. JmsSenderComponents sends it to a topic.
5. Client receives on the topic "World"

It expects XML document as the content, and the JmsSenderComponent source
indicates that it runs a transform on the xml
and converts into text and puts it into the TextMessage.
Is there any helper calss which i can call and generate the XML that the
JmsMarshaler is looking for?

Any help would be appreciated.
Thanks

Here are the code and xml snippets

NormalizedMessage nMsg = exchange.getMessage("in");
InOnly inonly =
createInOnlyExchange(new QName(Constants.GENERIC_NS,
Constants.CLIENTSENDER_SERVICE), null, null);

NormalizedMessage msg = inonly.createMessage();
msg.setProperty("out",nMsg.getContent());  //just to see what happents
inonly.setInMessage(msg);
send(inonly);


the servicemix.xml snippet is

<sm:activationSpec componentName="client-sender"
service="smt:client-sender">
<sm:component>
<bean class="org.servicemix.components.jms.JmsSenderComponent"
depends-on="broker">
<property name="template">
<bean class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory" ref="jmsFactory" />
<property name="defaultDestinationName" value="
com.mastek.servicemix.test.result" />
<property name="pubSubDomain" value="true" />
</bean>

Re: Manually call the JmsSenderComponent

Posted by Guillaume Nodet <gu...@worldonline.fr>.
Non xml data should be either:
  * transformed on the binding component side to xml (maybe the way you 
pointed, or with a more advanced transformation)
  * conveyed as a property on the NormalizedMessage
  * conveyed as an attachment on the NormalizedMessage

You should consider writing a custom jms marshaler that does one of this 
to transfer your CSV file.
You just need to write a class inheriting from 
org.apache.servicemix.components.jms.JmsMarshaler and configure it on 
your sender component.
You could use servingxml (see 
http://jira.activemq.org/jira/browse/SM-275 or SM-165) which may prove 
usefull.

In terms of performance and memory, parsing the xml content to check its 
validity is not the best solution.
JBI uses jaxp Source and thus allows very good performances, allowing 
the uses of streams aso.
But i agree that using DOMSource would do the trick and it could be 
optional.
Could you raise a jira for that ? you can even contribute a patch ;)

Cheers,
Guillaume Nodet

Akhil Srinivasan wrote:

>Assuming i want to transfer say a CSV string from one component to another,
>ie
>The JMS TextMessage contains a CVS string which is given to one binding
>component the JmsReceiver. That string is dumped in to the content section
>of the NMR without checking is it a valid XML string(that i believe is odd
>behaviour). But while sending a changed CVS string back out to the same
>client I cannot use the content section of the NMR and the
>JmsSenderComponent, which means that i have to extend the JmsSender
>component to check if the getContent is XML if not then just create a
>TextMessage using the getContent without trying a transform or anything.
>
>Can this be added to the JmsSender component, if the Content is not valid
>XML just put whatever is in it into the TextMessage?
>
>Additionally would it make sense to check the TextMessage at the JmsReceiver
>and if the text is not XML throw an exception or convert it into an xml
>block like
>
><?xml?>
><jmsmessage>
><content>
>*<![CDATA[*"the TextMessage that was sent"*]]>*
></content>
></jmsmessage>
>
>which can be retransformed by the JmsSender component?
>
>Akhil Srinivasan
>
>  
>


Re: Manually call the JmsSenderComponent

Posted by Akhil Srinivasan <ak...@gmail.com>.
Assuming i want to transfer say a CSV string from one component to another,
ie
The JMS TextMessage contains a CVS string which is given to one binding
component the JmsReceiver. That string is dumped in to the content section
of the NMR without checking is it a valid XML string(that i believe is odd
behaviour). But while sending a changed CVS string back out to the same
client I cannot use the content section of the NMR and the
JmsSenderComponent, which means that i have to extend the JmsSender
component to check if the getContent is XML if not then just create a
TextMessage using the getContent without trying a transform or anything.

Can this be added to the JmsSender component, if the Content is not valid
XML just put whatever is in it into the TextMessage?

Additionally would it make sense to check the TextMessage at the JmsReceiver
and if the text is not XML throw an exception or convert it into an xml
block like

<?xml?>
<jmsmessage>
<content>
*<![CDATA[*"the TextMessage that was sent"*]]>*
</content>
</jmsmessage>

which can be retransformed by the JmsSender component?

Akhil Srinivasan

Re: Manually call the JmsSenderComponent

Posted by Guillaume Nodet <gu...@worldonline.fr>.
There is no real transformation of the xml content here.
The xml is transformed between jaxp Source : for example convert a 
stream (parse) into a Document, etc...
The "Content is not allowed in prolog" error means that the xml is 
malformed and the parser fails.
You do not need to follow a specific schema or DTD: as long as the xml 
is valid, it will be ok.

Cheers,
Guillaume Nodet


Akhil Srinivasan wrote:

>Initial I did use "msg.setContent(nMsg.getContent());" but i got an XML
>related error.
>
>[Fatal Error] :1:1: Content is not allowed in prolog.
>[ERROR] PojoSupport - Error processing exchange <
>javax.jbi.messaging.MessagingException:
>org.springframework.jms.UncategorizedJmsException: Uncategorized exception
>occured during JMS processing; nested exception is javax.jms.JMSException:
>Failed to create JMS Message: javax.xml.transform.TransformerException:
>org.xml.sax.SAXParseException: Content is not allowed in prolog.; nested
>exception is javax.xml.transform.TransformerException:
>org.xml.sax.SAXParseException: Content is not allowed in prolog.>
>javax.jbi.messaging.MessagingException:
>org.springframework.jms.UncategorizedJmsException: Uncategorized exception
>occured during JMS processing; nested exception is javax.jms.JMSException:
>Failed to create JMS Message: javax.xml.transform.TransformerException:
>org.xml.sax.SAXParseException: Content is not allowed in prolog.; nested
>exception is javax.xml.transform.TransformerException:
>org.xml.sax.SAXParseException: Content is not allowed in prolog.
>    at org.servicemix.components.jms.JmsSenderComponent.process(
>JmsSenderComponent.java:90)
>    at org.servicemix.components.util.OutBinding.onMessageExchange(
>OutBinding.java:51)
>    at org.servicemix.jbi.messaging.DeliveryChannelImpl.processInBound(
>DeliveryChannelImpl.java:588)
>    at org.servicemix.jbi.nmr.flow.AbstractFlow.doRouting(AbstractFlow.java
>:171)
>    at org.servicemix.jbi.nmr.flow.seda.SedaQueue$1.run(SedaQueue.java:225)
>    at org.apache.geronimo.connector.work.WorkerContext.run(
>WorkerContext.java:291)
>    at EDU.oswego.cs.dl.util.concurrent.PooledExecutor$Worker.run(Unknown
>Source)
>    at java.lang.Thread.run(Thread.java:595)
>
>Based on the source i checked, you only expect XML to be given in the
>content of an NMR message which will be converted to an TextMessage.
>The only problem is that the JmsReceiver does not check if it valid XML, so
>the "hello" string i send passes through without any problems. But the
>"world" string throws the above error. The Sender does put it through an
>XMLTransformer in
>
>JmsMarshaler.java
>    public Message createMessage(NormalizedMessage normalizedMessage,
>Session session) throws JMSException, TransformerException {
>        // lets create a text message
>        String xml = messageAsString(normalizedMessage);
>        TextMessage message = session.createTextMessage(xml);
>        addJmsProperties(message, normalizedMessage);
>        return message;
>    }
>
>SourceMarchaler.java
>    /**
>     * Converts the inbound message to a String that can be sent
>     */
>    protected String messageAsString(NormalizedMessage normalizedMessage)
>throws TransformerException {
>        return sourceMarshaler.asString(normalizedMessage.getContent());
>    }
>
>    public String asString(Source source) throws TransformerException {
>        StringWriter buffer = new StringWriter();
>        transformer.toResult(source, new StreamResult(buffer));
>        return buffer.toString();
>    }
>
>SourceTransformer.java
>    /**
>     * Converts the given input Source into the required result
>     */
>    public void toResult(Source source, Result result) throws
>TransformerException {
>        Transformer transformer = createTransfomer();
>        if (transformer == null) {
>            throw new TransformerException("Could not create a transformer -
>JAXP is misconfigured!");
>        }
>        if (source != null) {
>            transformer.transform(source, result);
>        }
>        else {
>            log.warn("No Source available");
>        }
>    }
>
>This is as far as i have traced the message. I was wondering was gets
>transformed in what? Is there a particular markup that i am supposed to
>follow, and if so where is the DTD for that markup?
>
>Thanks
>
>  
>


Re: Manually call the JmsSenderComponent

Posted by Akhil Srinivasan <ak...@gmail.com>.
Initial I did use "msg.setContent(nMsg.getContent());" but i got an XML
related error.

[Fatal Error] :1:1: Content is not allowed in prolog.
[ERROR] PojoSupport - Error processing exchange <
javax.jbi.messaging.MessagingException:
org.springframework.jms.UncategorizedJmsException: Uncategorized exception
occured during JMS processing; nested exception is javax.jms.JMSException:
Failed to create JMS Message: javax.xml.transform.TransformerException:
org.xml.sax.SAXParseException: Content is not allowed in prolog.; nested
exception is javax.xml.transform.TransformerException:
org.xml.sax.SAXParseException: Content is not allowed in prolog.>
javax.jbi.messaging.MessagingException:
org.springframework.jms.UncategorizedJmsException: Uncategorized exception
occured during JMS processing; nested exception is javax.jms.JMSException:
Failed to create JMS Message: javax.xml.transform.TransformerException:
org.xml.sax.SAXParseException: Content is not allowed in prolog.; nested
exception is javax.xml.transform.TransformerException:
org.xml.sax.SAXParseException: Content is not allowed in prolog.
    at org.servicemix.components.jms.JmsSenderComponent.process(
JmsSenderComponent.java:90)
    at org.servicemix.components.util.OutBinding.onMessageExchange(
OutBinding.java:51)
    at org.servicemix.jbi.messaging.DeliveryChannelImpl.processInBound(
DeliveryChannelImpl.java:588)
    at org.servicemix.jbi.nmr.flow.AbstractFlow.doRouting(AbstractFlow.java
:171)
    at org.servicemix.jbi.nmr.flow.seda.SedaQueue$1.run(SedaQueue.java:225)
    at org.apache.geronimo.connector.work.WorkerContext.run(
WorkerContext.java:291)
    at EDU.oswego.cs.dl.util.concurrent.PooledExecutor$Worker.run(Unknown
Source)
    at java.lang.Thread.run(Thread.java:595)

Based on the source i checked, you only expect XML to be given in the
content of an NMR message which will be converted to an TextMessage.
The only problem is that the JmsReceiver does not check if it valid XML, so
the "hello" string i send passes through without any problems. But the
"world" string throws the above error. The Sender does put it through an
XMLTransformer in

JmsMarshaler.java
    public Message createMessage(NormalizedMessage normalizedMessage,
Session session) throws JMSException, TransformerException {
        // lets create a text message
        String xml = messageAsString(normalizedMessage);
        TextMessage message = session.createTextMessage(xml);
        addJmsProperties(message, normalizedMessage);
        return message;
    }

SourceMarchaler.java
    /**
     * Converts the inbound message to a String that can be sent
     */
    protected String messageAsString(NormalizedMessage normalizedMessage)
throws TransformerException {
        return sourceMarshaler.asString(normalizedMessage.getContent());
    }

    public String asString(Source source) throws TransformerException {
        StringWriter buffer = new StringWriter();
        transformer.toResult(source, new StreamResult(buffer));
        return buffer.toString();
    }

SourceTransformer.java
    /**
     * Converts the given input Source into the required result
     */
    public void toResult(Source source, Result result) throws
TransformerException {
        Transformer transformer = createTransfomer();
        if (transformer == null) {
            throw new TransformerException("Could not create a transformer -
JAXP is misconfigured!");
        }
        if (source != null) {
            transformer.transform(source, result);
        }
        else {
            log.warn("No Source available");
        }
    }

This is as far as i have traced the message. I was wondering was gets
transformed in what? Is there a particular markup that i am supposed to
follow, and if so where is the DTD for that markup?

Thanks

Re: Manually call the JmsSenderComponent

Posted by Guillaume Nodet <gu...@worldonline.fr>.
In your code snippet, I do not see where you set the content of the 
message you send.
You should have something like that:
  msg.setContent(nMsg.getContent());

Did I miss something ?

Cheers,
Guillaume Nodet

Akhil Srinivasan wrote:

>I wanted to use the JmsSenderComponent to send a TextMessage back to a
>client.
>Its mainly to a sample application on servicemix.
>
>The use case is
>1. Client sends Hello TextMessage to a queue.
>2. JmsService pick its up and routes it to my servicemix component.
>3. My component sends world to the JmsSerderComponent
>4. JmsSenderComponents sends it to a topic.
>5. Client receives on the topic "World"
>
>It expects XML document as the content, and the JmsSenderComponent source
>indicates that it runs a transform on the xml
>and converts into text and puts it into the TextMessage.
>Is there any helper calss which i can call and generate the XML that the
>JmsMarshaler is looking for?
>
>Any help would be appreciated.
>Thanks
>
>Here are the code and xml snippets
>
>NormalizedMessage nMsg = exchange.getMessage("in");
>InOnly inonly =
>createInOnlyExchange(new QName(Constants.GENERIC_NS,
>Constants.CLIENTSENDER_SERVICE), null, null);
>
>NormalizedMessage msg = inonly.createMessage();
>msg.setProperty("out",nMsg.getContent());  //just to see what happents
>inonly.setInMessage(msg);
>send(inonly);
>
>
>the servicemix.xml snippet is
>
><sm:activationSpec componentName="client-sender"
>service="smt:client-sender">
><sm:component>
><bean class="org.servicemix.components.jms.JmsSenderComponent"
>depends-on="broker">
><property name="template">
><bean class="org.springframework.jms.core.JmsTemplate">
><property name="connectionFactory" ref="jmsFactory" />
><property name="defaultDestinationName" value="
>com.mastek.servicemix.test.result" />
><property name="pubSubDomain" value="true" />
></bean>
>
>  
>