Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why do we use <cxf:rsServer> as opposed to a plain <jaxrs:server> when using the CXF-RS component?

As a follow-up to this question, I'm still a bit confused about how to properly use the CXF-RS component.

I'm confused why we need the <cxf:rsServer> tag for specifying CXF-RS endpoints (or is there even such a concept?), when I can use the <jaxrs:server> tag perfectly fine.

Here's my configuration XML for both Camel and CXF:

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:jaxrs="http://cxf.apache.org/jaxrs"
    xmlns:camel="http://camel.apache.org/schema/spring"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd      
        http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd
        http://cxf.apache.org/transports/http/configuration http://cxf.apache.org/schemas/configuration/http-conf.xsd
        http://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/jaxrs.xsd
        http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd">

    <jaxrs:server id="userService" address="/users">
        <jaxrs:serviceBeans>
            <bean class="com.example.UserServiceNoop" />
        </jaxrs:serviceBeans>
        <jaxrs:providers>
            <bean class="org.codehaus.jackson.jaxrs.JacksonJaxbJsonProvider" />
        </jaxrs:providers>
    </jaxrs:server>
    
    <bean id="user" class="org.apache.camel.component.direct.DirectComponent" />
    
    <camel:camelContext id="someCamelContext">
        <camel:route id="userServiceRoute">
            <camel:from uri="cxfrs:bean:userService" />
            <camel:routingSlip>
                <camel:simple>user:${header.operationName}</camel:simple>
            </camel:routingSlip>
        </camel:route>

        <camel:route id="userServiceRetrieveUser">
            <from uri="user:retrieveUser" />
            <!-- Assume this is going to a useful Processor -->
        
        </camel:route>  
    </camel:camelContext>
</beans>

UserService.java:

package com.example;

/* a bunch of imports... */

public interface UserService {
    @GET
    @Path(value="/{user.id}")
    @Produces({MediaType.APPLICATION_JSON})
    public User retrieveUser(
        @PathParam("user.id") Integer id
    );
}

UserServiceNoop.java

package com.example;

/* a bunch of imports ... */

public class UserServiceNoop implements UserService 
{
    @Override
    public User retrieveUser(Integer id) {
        throw new RuntimeException();
    }
}

In this example, I'm not using any <cxf:rsServer> tag, yet it works fine. I know it goes through the CXF-RS component, because when I run the application, it doesn't throw any RuntimeExceptions, which is the expected behavior when using CXF-RS (the method implementation in the service class will not be called).

Am I missing something by not using this tag?

like image 416
Ivan Gozali Avatar asked Jan 29 '14 19:01

Ivan Gozali


People also ask

What is Cxf rsServer?

As the other answer says, the cxf:rsServer is mainly used to be processed by a Camel route as in the jaxrs:server the processing of the request is done by a classic controller.

What is Jaxrs Cxf?

CXF JAX-RS provides a number of advanced extensions such as the support for the JMS transport, one-way invocations (HTTP and JMS), suspended invocations (HTTP and JMS), making existing code REST-aware by applying external user models, etc. Please see the JAX-RS Advanced Features page for more information.

What is CXF endpoint?

In Apache Camel, the Camel CXF component is the key to integrating routes with Web services. You can use the Camel CXF component to create a CXF endpoint, which can be used in either of the following ways: Consumer — (at the start of a route) represents a Web service instance, which integrates with the route.


1 Answers

As the other answer says, the cxf:rsServer is mainly used to be processed by a Camel route as in the jaxrs:server the processing of the request is done by a classic controller.

For example:

  1. Classic JAXRS server:

You will declare a classic Bean Rest (Controller) and inject a Service inside.

Sample of an XML config (extract):

<jaxrs:server id="deviceServiceSvcV1" address="/device/v1">
    <jaxrs:serviceBeans>
        <ref component-id="deviceServiceRest" />
    </jaxrs:serviceBeans>
    <!-- and other providers, interceptors, etc... here --> 
</jaxrs:server>

<!-- Service bean -->
<bean id="deviceServiceRest" class="org.mycomp.device.rest.v1.ws.api.DeviceServiceRest">
    <property name="deviceService" ref="deviceService" />
</bean>

The Controller class will process the request / response in a classic way (e.g. calling an injected service).

  1. Camel route with cxf:rsServer

Sample of an XML config (extract):

<cxf:rsServer id="rsServer" address="/device/v1"
    serviceClass="org.mycomp.device.rest.v1.ws.api.DeviceServiceRest">
    <cxf:properties>
        <!-- whatever here -->
    </cxf:properties>
    <!-- and other interceptors, etc... here -->         
</cxf:rsServer>

and in the classes:

@Produces({ MediaType.APPLICATION_XML })
@Path("/")
public class DeviceServiceRest {

    @GET
    public Response listDevicess( 
            @QueryParam("model") String model,
            @QueryParam("sid") String sid,
    ) {
        return null; // never used
    }

    @GET
    @Path("{id}")
    public Response getDeviceById(
            @PathParam("id") String id,
            @QueryParam("model") String model,
            @QueryParam("sid") String sid
    ){               
        return null; // never used
    }
}

The REST Controller has empty methods (returning null) but I think the latest camel-cxf supports now an Interface which is more elegant than having methods returning null. Now, the request processing can be implemented by a Camel Route like this:

from("cxfrs:bean:rsServer?synchronous=true")
    .routeId("cxf-device-rest-v1")
    .process( new CheckAuthenticationProcessor())
    .choice()
        .when(header("operationName").isEqualTo("listDevice"))
            .setHeader("backenOperation").constant("list")
            .setHeader("backendResource").constant("device")
            
        .endChoice()
        .when(header("operationName").isEqualTo("getDeviceById"))
            .setHeader("backenOperation").constant("retrieve")
            .setHeader("backendResource").constant("device")
        .endChoice()
    .end()
    .bean("requestProcessor")
    .to(InOut, backendEndpoint)
    .process(checkResponseStatusCode())
    .bean(new HttpResponseProcessor())
;

And you can also control the request / response processing as you want from the route.

These are two different kind of implementing a REST API (server side) but in my opinion this is a bit old school as modern framework like spring-boot does not need any of these.

I found the second way a bit too much overkill as I like Camel for integration purpose but using it for a REST API could be subject to discussion. One use-case I can see is a HTTP REST Web-Service for asynchronous processing, the service responding 202 Accepted and the Camel Route making an integration of the request in asynchronous mode especially when a specific Camel Component can be easily used instead of a complex class (or any need of the EIP patterns).

like image 71
рüффп Avatar answered Oct 03 '22 06:10

рüффп