You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@cxf.apache.org by Scott Parkerson <Sc...@ateb.com> on 2009/09/09 22:56:29 UTC

How to send a JMS message from a webservice

I have a JAX-RS webservice deployed on Apache CXF inside of Apache  
ServiceMix 4 that, upon validating the incoming object, will need to  
send the message to a JMS queue (e.g. ActiveMQ). What is the easiest  
way to do this from inside of Apache CXF?

I've Googled a bit, and there are a lot of examples for setting up a  
webservice that goes *straight* into JMS, but I'm looking to sending  
the message after doing some processing. Here's a code snippet:

     @POST
     @Path("/sendfoo")
     public Response sendfoo(sendfooRequest sendfooRequest)
     {
         logger.debug("[rest] sendfoo called");

         logger.debug("[rest] sendfooRequest campaignId " +  
sendfooRequest.getCampaignId());
         logger.debug("[rest] sendfooRequest fooNumber " +  
sendfooRequest.getFooNumber());
         logger.debug("[rest] sendfooRequest messageType " +  
sendfooRequest.getMessageType());

         // TODO: Figure out why this doesn't seem to work the way I'd  
expect it to.
         //       This is probably something weird with jettison's  
JSON marshalling that
         //       I don't understand.
         HashMap<String, String> tagHash = sendfooRequest.getTags();
         if (tagHash != null)
         {
             for (String tag : tagHash.keySet())
             {
                 logger.debug("[rest] sendfooREquest tag " + tag + ",  
value " + tagHash.get(tag));
             }
         }

         // TODO: validate a sendfooRequest. Perhaps have the request  
object validate itself?
         //if (!sendfooRequest.isValid())
         //{
         //    return Response.status(400).build();
         //}

         // TODO: if the sendfooRequest validates, then send it along  
to the next endpoint;
         //       otherwise, return an HTTP error 400 (Bad Request)  
and an error response.

         // Return HTTP response 202 Accepted
         return Response.status(202).build();

     }


Basically, I need to know how to send my sendfooRequest object along  
to JMS/ActiveMQ.


Thanks!
Scott

Re: How to send a JMS message from a webservice

Posted by Christian Schneider <ch...@die-schneider.net>.
Hi Scott,

I have not yet used the @Produce style myself. Perhaps there is 
something special to configure here. I guess you could ask on the Camel 
User list why your one Example worked and the other did not.
I guess cxfrs could really be worth a try.

Btw. Is there any reason why you use seda: instead of direct:? I guess 
direct endpoints could be more efficient.

Perhaps there is even a way to avoid CXF at all. You could try to use a 
jetty http endpoint and parse the request with jaxb.
At least if jaxb unmarshalling is all you need of rest it could work:

<route>
    <from uri="jetty:http://myurl"/>
    <unmarshal ref="myJaxb"/>
    <to uri="activemq:myqueue"/>
</route>

The following page explains jaxb in Camel:
http://camel.apache.org/jaxb.html

Greetings

Christian


Scott Parkerson schrieb:
> On Fri, 2009-09-11 at 15:31 -0400, Scott Parkerson wrote:
>   
>
> Ok, now had I tried your actual suggestion using @EndpointInject things
> would have gone more smoothly for me. I changed my code to:
>
>    @EndpointInject(uri = "seda:webrequestqueue")
>    private ProducerTemplate<Exchange>  webRequestProducer;
>
>    .
>    .
>    .
>
>    webRequestProducer.sendBody(sendFooRequest);
>
> and all is well.
>
> I guess my only complaint is that this doesn't "hide middleware" as
> suggested in the docs. Then again, perhaps I'll eventually come around
> to binding a cxfrs: URI to my routes. :D
>
> Any further suggestions?
>
> --sgp
>
>   
>> I'm beginning to think I've got the wrong approach to this, but humor me
>> and tell me how I can just send the Foo object.
>>
>> --sgp
>>
>>     
>
>   


Re: How to send a JMS message from a webservice

Posted by Scott Parkerson <Sc...@ateb.com>.
On Fri, 2009-09-11 at 15:31 -0400, Scott Parkerson wrote:
> On Thu, 2009-09-10 at 10:10 +0200, Christian Schneider wrote:
> 
> > Ok .. now I understand. You want to send the pojo to ActiveMQ not the 
> > xml. In this case you build the service with CXF and can then use
> > Camel to simply send the pojo to ActiveMQ. You can do this by:
> > 
> > public class MyJsonServiceImpl implements MyJsonService {
> >   @EndpointInject(uri="activemq:myqueue")
> >   ProducerTemplate producer;
> > 
> >   public void doSomething(MyObject o) {
> >     producer.sendBody(o);
> >   }
> > }
> 
> Ok, this is closer to what I want, but not quite there. I'm using the
> example from the pojo-producing page, and sending the result to a seda
> queue which is then picked up by a content-based router. Here's the
> code:
> 
> (the interface code)
> 
> @InOnly
>     public interface WebRequestProducer
>     {
>         public void sendToWebRouter(Object o);
>     }
> 
> (the webrouter configuration) 
> 
>     public void configure() throws Exception
>     {      
>         
>         getContext().addInterceptStrategy(new Tracer());
>         
>         from("seda:webrequestqueue")
>             .choice()
>                 .when(body().isInstanceOf(SendSMSRequest.class))
>                     .to("activemq:queue:send_sms_req")
>                 .when(body().isInstanceOf(IncomingSMSRequest.class))
>                     .to("activemq:queue:inc_sms_req")
>                 .otherwise().throwFault("Blah." +
> body().toString());        
>     }
> 
> (and finally, the CXF method that calls it)
> 
>     @Produce(uri = "seda:webrequestqueue")
>     private WebRequestProducer  webRequestProducer;
> 
>     @POST
>     @Path("/sendfoo")
>     public Response sendFoo(SendFooRequest sendFooRequest)
>     {        
>        
> 	// TODO: validation code, etc.
>         webRequestProducer.sendToWebRouter(sendFooRequest);
>         
>         // Return HTTP response 202 Accepted
>         return Response.status(202).build();
> 
>     }
> 
> 
> 
> Problem is, my message that is generated is a BeanInvocation message
> containing the abstract method invocation, not *just* the POJO. 

Ok, now had I tried your actual suggestion using @EndpointInject things
would have gone more smoothly for me. I changed my code to:

   @EndpointInject(uri = "seda:webrequestqueue")
   private ProducerTemplate<Exchange>  webRequestProducer;

   .
   .
   .

   webRequestProducer.sendBody(sendFooRequest);

and all is well.

I guess my only complaint is that this doesn't "hide middleware" as
suggested in the docs. Then again, perhaps I'll eventually come around
to binding a cxfrs: URI to my routes. :D

Any further suggestions?

--sgp

> 
> I'm beginning to think I've got the wrong approach to this, but humor me
> and tell me how I can just send the Foo object.
> 
> --sgp
> 

Re: How to send a JMS message from a webservice

Posted by Scott Parkerson <Sc...@ateb.com>.
On Thu, 2009-09-10 at 10:10 +0200, Christian Schneider wrote:

> Ok .. now I understand. You want to send the pojo to ActiveMQ not the 
> xml. In this case you build the service with CXF and can then use
> Camel to simply send the pojo to ActiveMQ. You can do this by:
> 
> public class MyJsonServiceImpl implements MyJsonService {
>   @EndpointInject(uri="activemq:myqueue")
>   ProducerTemplate producer;
> 
>   public void doSomething(MyObject o) {
>     producer.sendBody(o);
>   }
> }

Ok, this is closer to what I want, but not quite there. I'm using the
example from the pojo-producing page, and sending the result to a seda
queue which is then picked up by a content-based router. Here's the
code:

(the interface code)

@InOnly
    public interface WebRequestProducer
    {
        public void sendToWebRouter(Object o);
    }

(the webrouter configuration) 

    public void configure() throws Exception
    {      
        
        getContext().addInterceptStrategy(new Tracer());
        
        from("seda:webrequestqueue")
            .choice()
                .when(body().isInstanceOf(SendSMSRequest.class))
                    .to("activemq:queue:send_sms_req")
                .when(body().isInstanceOf(IncomingSMSRequest.class))
                    .to("activemq:queue:inc_sms_req")
                .otherwise().throwFault("Blah." +
body().toString());        
    }

(and finally, the CXF method that calls it)

    @Produce(uri = "seda:webrequestqueue")
    private WebRequestProducer  webRequestProducer;

    @POST
    @Path("/sendfoo")
    public Response sendFoo(SendFooRequest sendFooRequest)
    {        
       
	// TODO: validation code, etc.
        webRequestProducer.sendToWebRouter(sendFooRequest);
        
        // Return HTTP response 202 Accepted
        return Response.status(202).build();

    }



Problem is, my message that is generated is a BeanInvocation message
containing the abstract method invocation, not *just* the POJO. 

I'm beginning to think I've got the wrong approach to this, but humor me
and tell me how I can just send the Foo object.

--sgp


Re: How to send a JMS message from a webservice

Posted by Christian Schneider <ch...@die-schneider.net>.
Scott Parkerson schrieb:
>
> On Sep 9, 2009, at 5:36 PM, Christian Schneider wrote:
>
>> I think you could take a look at Apache Camel. If you simply want to 
>> send the soap message to jms you would set up a camel route like this:
>>
>> from("http://localhost:9000/MyServicePort").to("jms://myQeueName")
>>
>> Between the two you could insert some processing.
>
> In this case, it's more like:
>
> POST /api/sendfooRequest (JSON body) -> CXF (which validates, and 
> turns it into a POJO) -> ActiveMQ -> some other bean to process
Ok .. now I understand. You want to send the pojo to ActiveMQ not the 
xml. In this case you build the service with CXF and can then use
Camel to simply send the pojo to ActiveMQ. You can do this by:

public class MyJsonServiceImpl implements MyJsonService {
  @EndpointInject(uri="activemq:myqueue")
  ProducerTemplate producer;

  public void doSomething(MyObject o) {
    producer.sendBody(o);
  }
}

If you do not like to have the queue name in the annotation you can use 
a direct endpoint and define the destination in the camel context. I 
hope this is what you were searching for.

The full documentation can be found here:
http://camel.apache.org/pojo-producing.html
http://camel.apache.org/activemq.html
http://camel.apache.org/direct.html

Alternatively you can set up a CXF Endpoint in Camel. In this case you 
do not need to write the implementation class.
http://camel.apache.org/cxf.html

So your route would look like:

<route>
  <from uri="cxf:bean:routerEndpoint" />
  <to uri="activemq:myqueue" />
</route>

If you only want to forward the request this is probably easier.
Btw. Camel also supports request reply in a route like this. So your 
component that listens to jms can send a reply message back that is then 
returned in the body of the http reply.

Greetings

Christian

>
> I'd rather not have Camel manage the actual front-end response; I'd 
> rather have Camel process that after it's passed into the next phase.
>
>> If you only need a transparent bridge from http to jms you could take 
>> a look at a project I did:
>> http://www.liquid-reality.de:8080/display/liquid/HTTP2JMSBridge
>
> Good idea, but I still want CXF to do the processing before it gets to 
> JMS.
>
> --sgp
>
>


Re: How to send a JMS message from a webservice

Posted by Scott Parkerson <Sc...@ateb.com>.
On Sep 9, 2009, at 5:36 PM, Christian Schneider wrote:

> I think you could take a look at Apache Camel. If you simply want to  
> send the soap message to jms you would set up a camel route like this:
>
> from("http://localhost:9000/MyServicePort").to("jms://myQeueName")
>
> Between the two you could insert some processing.

In this case, it's more like:

POST /api/sendfooRequest (JSON body) -> CXF (which validates, and  
turns it into a POJO) -> ActiveMQ -> some other bean to process

I'd rather not have Camel manage the actual front-end response; I'd  
rather have Camel process that after it's passed into the next phase.

> If you only need a transparent bridge from http to jms you could  
> take a look at a project I did:
> http://www.liquid-reality.de:8080/display/liquid/HTTP2JMSBridge

Good idea, but I still want CXF to do the processing before it gets to  
JMS.

--sgp


Re: How to send a JMS message from a webservice

Posted by Christian Schneider <ch...@die-schneider.net>.
Hi Scott,

I think you could take a look at Apache Camel. If you simply want to 
send the soap message to jms you would set up a camel route like this:

from("http://localhost:9000/MyServicePort").to("jms://myQeueName")

Between the two you could insert some processing.

If you only need a transparent bridge from http to jms you could take a 
look at a project I did:
http://www.liquid-reality.de:8080/display/liquid/HTTP2JMSBridge

Greetings

Christian


Scott Parkerson schrieb:
> I have a JAX-RS webservice deployed on Apache CXF inside of Apache 
> ServiceMix 4 that, upon validating the incoming object, will need to 
> send the message to a JMS queue (e.g. ActiveMQ). What is the easiest 
> way to do this from inside of Apache CXF?
>
> I've Googled a bit, and there are a lot of examples for setting up a 
> webservice that goes *straight* into JMS, but I'm looking to sending 
> the message after doing some processing. Here's a code snippet:
>
>     @POST
>     @Path("/sendfoo")
>     public Response sendfoo(sendfooRequest sendfooRequest)
>     {
>         logger.debug("[rest] sendfoo called");
>
>         logger.debug("[rest] sendfooRequest campaignId " + 
> sendfooRequest.getCampaignId());
>         logger.debug("[rest] sendfooRequest fooNumber " + 
> sendfooRequest.getFooNumber());
>         logger.debug("[rest] sendfooRequest messageType " + 
> sendfooRequest.getMessageType());
>
>         // TODO: Figure out why this doesn't seem to work the way I'd 
> expect it to.
>         //       This is probably something weird with jettison's JSON 
> marshalling that
>         //       I don't understand.
>         HashMap<String, String> tagHash = sendfooRequest.getTags();
>         if (tagHash != null)
>         {
>             for (String tag : tagHash.keySet())
>             {
>                 logger.debug("[rest] sendfooREquest tag " + tag + ", 
> value " + tagHash.get(tag));
>             }
>         }
>
>         // TODO: validate a sendfooRequest. Perhaps have the request 
> object validate itself?
>         //if (!sendfooRequest.isValid())
>         //{
>         //    return Response.status(400).build();
>         //}
>
>         // TODO: if the sendfooRequest validates, then send it along 
> to the next endpoint;
>         //       otherwise, return an HTTP error 400 (Bad Request) and 
> an error response.
>
>         // Return HTTP response 202 Accepted
>         return Response.status(202).build();
>
>     }
>
>
> Basically, I need to know how to send my sendfooRequest object along 
> to JMS/ActiveMQ.
>
>
> Thanks!
> Scott
>