Sorry for a noise,

I think the route below is not exactly correct, should be something along these lines:

<route>
 <from uri="servlet:///HelloWorld?matchOnUriPrefix=true"/>
 <!-- this is invokes a jaxrs bean -->
 <to uri="direct:HelloWorldRestServerEndpoint"/>

 <!-- this method will just get the cached object back into Exchange -->
 <to uri="bean://jaxbProvider?method=restore"/>

 <!-- now do whatever is needed with the bean returned from the service -->

 <!-- finally write to the output stream -->
 <to uri="bean://jaxbProvider?method=complete"/>
 </route>

The 'bean:' parts of the routes can be most likely optimized with a custom Processor, and the object properties can be updated on the provider in case the intermediate parts of the roots somehow enrich or change the object properties.

The provider itself can be written to delegate to JAX-RS Providers to make sure it is not bound to XML/JAXB only....

Sergey



On 03/10/12 17:29, Sergey Beryozkin wrote:
Ralf,

I experimented a bit with the idea of using a two-stage JAX-RS message
body writer, that seems to work, here is a prototype.

Context:

<bean id="jaxbProvider" class="server.CachingJAXBProvider"/>

<jaxrs:server id="hello_rest"
address="camel://direct:HelloWorldRestServerEndpoint">
<jaxrs:serviceBeans>
<ref bean="hello-world-bean"/>
</jaxrs:serviceBeans>
<jaxrs:providers>
<ref bean="jaxbProvider"/>
</jaxrs:providers>
</jaxrs:server>

<bean id="hello-world-bean" class="server.HelloWorldImpl"/>

<camelContext id="camelContext"
xmlns="http://camel.apache.org/schema/spring"; trace="false">
<route>
<from uri="servlet:///HelloWorld?matchOnUriPrefix=true"/>
<!-- this is invokes a jaxrs bean -->
<to uri="direct:HelloWorldRestServerEndpoint"/>
<!-- do whatever is needed with the bean returned from the service -->

<!-- write to the output stream -->
<to uri="bean://jaxbProvider?method=complete"/>
</route>
</camelContext>

Provider:

public class CachingJAXBProvider<T> extends JAXBElementProvider<T> {

private T object;
private Class<?> cls;
private Type genericType;
private Annotation[] anns;
private MediaType m;
private MultivaluedMap<String, Object> headers;
private CacheAndWriteOutputStream os;

@Override
public void writeTo(T obj, Class<?> cls, Type genericType, Annotation[]
anns,
MediaType m, MultivaluedMap<String, Object> headers, OutputStream os) {
this.object = obj;
this.cls = cls;
this.genericType = genericType;
this.anns = anns;
this.m = m;
this.headers = headers;
this.os = new
CacheAndWriteOutputStream(((CacheAndWriteOutputStream)os).getFlowThroughStream());

}

public Object complete(Object obj) throws IOException {
super.writeTo(object, cls, genericType, anns, m, headers, os);
return os.getOut();
}

}


This actually works, I think it looks a bit hacky and I wonder if a
utility provider like this one can be utilized internally and hidden
somehow. However I'm quite positive about the fact the process can
definitely be controlled - I'd like play with JAX-RS 2.0 AsyncResponse
later on.

When we have oneway invocations, then it is a different scenario.
Also Christian wrote a demo showing how a custom listener is injected
into a JAX-RS service bean and then another route starts from this
listener being notified

Sergey


On 03/10/12 12:23, Sergey Beryozkin wrote:
Actually, here is the slightly updated code from one of the tests which
Willem did:

protected RouteBuilder createRouteBuilder() throws Exception {
return new RouteBuilder() {
public void configure() {
final ResponseBuilder builder = Response.ok();

from(CXF_RS_ENDPOINT_URI)
// should be able to convert to Customer
.convertBodyTo(Customer.class)
.to("mock:result")
// respond with OK
.transform(constant(builder.entity(***new Customer()***).build()));
};
};
}

Note the cxfrs server endpoint accepts the request, the response object
is run through the route and finally it can be set on the builder to do
the marshalling done and the response returned.

The only thing I could not figure out quickly enough was how to actually
get hold of this response object :-)

Cheers, Sergey


On 01/10/12 11:38, Sergey Beryozkin wrote:
Hi Ralf
On 01/10/12 07:50, Ralf Steppacher wrote:
Willam,

thanks for the hint. I shall look into camel-cxfrs.

Could you give me a usage example of the cxfbean component? What would
be a scenario where immediate marshalling to the client-requested
format
is desired? Is the idea that all work necessary to produce a meaningful
response is done in the resource class and the route only consists of
the cxfbean endpoint?


When you have a JAX-RS annotated bean with @Produces, it is not really
possible to 'delay' marshalling of the response object.

I think something interesting in this regard can also done with the new
JAX-RS 2.0 AsyncResponse: say at the top of the route the JAX-RS request
is accepted, suspended and resumed at some later stage (the end of the
route). This just a theory at the moment though, not sure how it will
can be coordinated with the Camel thread running the whole route

Perhaps one working option is to register a custom JAX-RS
MessageBodyReader which will simply cache the response object in its
writeTo method and then at the end of the route this provider will be
asked to 'flush' the response. Will it work for you ?

Sergey

Thanks!
Ralf

-----Original Message-----
From: Willem jiang<[email protected]>
Reply-to: [email protected]
To: [email protected]
Subject: Re: RESTful route with Apache CXF
Date: Thu, 27 Sep 2012 15:56:17 +0800

Hi Ralf,

I think you use misused the cxfbean component.
cxfbean component is trying to leverage the camel components to
provides different transports.

It will marshal and unmarshal the request and response out of box.

What's you need is camel-cxfrs[1] component, you should be able to get
the Java object of PriceReuqestMessage from the message body.

[1]http://camel.apache.org/cxfrs.html





--
Sergey Beryozkin

Talend Community Coders
http://coders.talend.com/

Blog: http://sberyozkin.blogspot.com

Reply via email to