On 06/11/12 17:42, Martin Stiborský wrote:
Hello guys!
I need a help, again…This time about REST and CXF. I've moved from restlet
component to CXF and it raised quite a lot of questions, it was easier with
Restlet, but now I have to deal with CXF.

At least, I have a working "proof of concept" of the REST API with CXF in
Camel, that works, but, it's not looking "nice and clean" for me, so I have
few questions, if all this is really ok and that is the "recommended" or
something like this :)

First, I have declared a "face" of the REST API:

public class DemoServer {

     @GET
     @Path("/hellodemo/{hello}")
     @Produces("text/plain")
     public Response demoHello(@PathParam("hello") String hello) {
         return null;
     }

     @GET
     @Path("/{foo}/bar")
     @Produces("text/plain")
     public Response fooHello(@PathParam("foo") String foo) {
         return null;
     }
}

Then, I've registered this "DemoServer" as "cxf:rsServer" in blueprint.xml:

<camel-cxf:rsServer id="demoServer" address="${server.cxfrest.base}/demo/"
                         serviceClass="com.my.example.DemoServer"/>

And then, finally, the Camel route:

from("cxfrs:bean:demoServer")
                 .choice()

.when(header(CxfConstants.OPERATION_NAME).isEqualTo("demoHello"))
                         .to("bean:demoBean")

.when(header(CxfConstants.OPERATION_NAME).isEqualTo("fooHello"))
                         .to("bean:fooBean")
                     .otherwise()
                         .to("bean:anotherBean");

Now, questions :)

First of all, is that really correct? It should be like that? Well, I'm
fine with that, but few things looks weird to me.

My intention is to have REST API on the consumer endpoint side, in the
middle is some processing, based on inputs from the REST requests, and on
the produce endpoint side, there is almost all the time HTTP reponse with
some content back to browser (JSON data, usually).

So, for example, the implementation of "DemoServer" looks weird, I don't
like the "return null" there. Yes it works like it should, like I need, but
this looks odd.

Agreed. I was writing some test few weeks ago and it took me awhile before I understood how it worked, and I'll need to refresh my memory again next time again I'm sure :-).

As far as I recall, this 'face' is only used to get the JAX-RS runtime prepare all the parameters as per the specific signature.

I've experimented a bit with using jaxrs:endpoint as a consumer directly. It worked quite well. All you have to do is to create a custom MessageBodyWriter which will cache the response object in its writeTo(..., OutputStream os), if any,

and then at the end of the route, will be asked to finally write it into the output stream using the references saved at the time writeTo is called.

Thus you can have DemoService implemented as a regular JAX-RS endpoint and get the response object manipulated further in the route and finally serialized as needed, with custom MBR taking care of it. It may look like this:

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 OutputStream 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 = os;
        }
        
        public Object complete(Object obj) throws IOException {
                super.writeTo(object, cls, genericType, anns, m, headers, os);
                return os;
        }
        
}


You can also have the in parameters made available to other camel routes, example. Christian wrote a demo where an interface like

public interface BookListener {

    void onBook(Book book);

}

is injected, the service implementation calls BookListener.onBook() which triggers another route

HTH, Sergey


Then, in the route definition, there is the content based router, this
choice()/when() things, because I need to differentiate each actions from
"DemoServer" - correct?
What I'd like to see, is ability to define a separate route for each method
in the "DemoServer". Again, it works, but I'm not sure about pros/cons too
much here :)
With Restlet, I've had there separate route for each kind of REST requests,
it was easy to have like that.

So, maybe it's just wrong, maybe not, that's why I'm asking :)

Thank you guys, for any hint.


Reply via email to