The cxfrs: component provides integration with Apache CXF for connecting to JAX-RS services hosted in CXF.
Maven users will need to add the following dependency to their pom.xml
for this component:
<dependency> <groupId>org.apache.camel</groupId> <artifactId>camel-cxf</artifactId> <version>x.x.x</version> <!-- use the same version as your Camel core version --> </dependency>
Note | |
---|---|
When using CXF as a consumer, the CAMEL:CXF Bean Component allows you to factor out how message payloads are received from their processing as a RESTful or SOAP web service. This has the potential of using a multitude of transports to consume web services. The bean component's configuration is also simpler and provides the fastest method to implement web services using Camel and CXF. |
cxfrs://address?options
Where address represents the CXF endpoint's address
cxfrs:bean:rsEndpoint
Where rsEndpoint represents the Spring bean's name which represents the CXFRS client or server
For either style above, you can append options to the URI as follows:
cxfrs:bean:cxfEndpoint?resourceClasses=org.apache.camel.rs.Example
Name | Description | Example | Required? | default value |
---|---|---|---|---|
resourceClasses
|
The resource classes which you want to export as REST service | resourceClasses=org.apache.camel.rs.Example1,org.apache.camel.rs.Exchange2 | No | None |
httpClientAPI
|
New to Fuse Mediation Router 2.1 If it is true, the CxfRsProducer will use the HttpClientAPI to invoke the service | httpClientAPI=true
|
No | true
|
synchronous |
New in 2.5, this option will let CxfRsConsumer decide to use sync or async API to do the underlying work. The default value is false which means it will try to use async API by default. |
synchronous=true |
No |
false |
throwExceptionOnFailure |
New in 2.6, this option tells the CxfRsProducer to inspect return codes and will generate an Exception if the return code is larger than 207. | throwExceptionOnFailure=true
|
No |
true |
maxClientCacheSize
|
New in 2.6, you can set the In message header,
CamelDestinationOverrideUrl , to dynamically override the target
destination Web Service or REST Service defined in your routes. The
implementation caches CXF clients or ClientFactoryBean in
CxfProvider and CxfRsProvider . This option allows
you to configure the maximum size of the cache. |
maxClientCacheSize=5 |
No | 10 |
You can also configure the CXF REST endpoint through the Spring configuration. Since there are lots of difference between the CXF REST client and CXF REST Server, we provide different configuration for them. Please check out the schema file and CXF REST user guide for more information.
In camel-cxf schema file, there are two elements for the REST endpoint definition. cxf:rsServer for REST consumer, cxf:rsClient for REST producer. You can find a Fuse Mediation Router REST service route configuration example here.
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:cxf="http://camel.apache.org/schema/cxf" xmlns:jaxrs="http://cxf.apache.org/jaxrs" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://camel.apache.org/schema/cxf http://camel.apache.org/schema/cxf/camel-cxf.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 "> <!-- Defined the real JAXRS back end service --> <jaxrs:server id="restService" address="http://localhost:9002/rest" staticSubresourceResolution="true"> <jaxrs:serviceBeans> <ref bean="customerService"/> </jaxrs:serviceBeans> </jaxrs:server> <!--bean id="jsonProvider" class="org.apache.cxf.jaxrs.provider.JSONProvider"/--> <bean id="customerService" class="org.apache.camel.component.cxf.jaxrs.testbean.CustomerService" /> <!-- Defined the server endpoint to create the cxf-rs consumer --> <cxf:rsServer id="rsServer" address="http://localhost:9000/route" serviceClass="org.apache.camel.component.cxf.jaxrs.testbean.CustomerService" /> <!-- Defined the client endpoint to create the cxf-rs consumer --> <cxf:rsClient id="rsClient" address="http://localhost:9002/rest" serviceClass="org.apache.camel.component.cxf.jaxrs.testbean.CustomerService"/> <!-- The camel route context --> <camelContext id="camel" xmlns="http://camel.apache.org/schema/spring"> <route> <from uri="cxfrs://bean://rsServer"/> <!-- We can remove this configure as the CXFRS producer is using the HttpAPI by default --> <setHeader headerName="CamelCxfRsUsingHttpAPI"> <constant>True</constant> </setHeader> <to uri="cxfrs://bean://rsClient"/> </route> </camelContext> </beans>
CXF JAXRS front end
implements the JAXRS(JSR311) API, so
we can export the resources classes as a REST service. And we leverage the CXF Invoker
API to turn a REST request into a normal Java object method invocation.
Unlike the camel-restlet
, you don't need to specify the URI template
within your restlet endpoint, CXF take care of the REST request URI to resource class
method mapping according to the JSR311 specification. All you need to do in Fuse Mediation Router is
delegate this method request to a right processor or endpoint.
Here is an example of a CXFRS route:
private static final String CXF_RS_ENDPOINT_URI = "cxfrs://http://localhost:" + CXT + "/rest?resourceClasses=org.apache.camel.component.cxf.jaxrs.testbean.CustomerServiceResource"; protected RouteBuilder createRouteBuilder() throws Exception { return new RouteBuilder() { public void configure() { errorHandler(new NoErrorHandlerBuilder()); from(CXF_RS_ENDPOINT_URI).process(new Processor() { public void process(Exchange exchange) throws Exception { Message inMessage = exchange.getIn(); // Get the operation name from in message String operationName = inMessage.getHeader(CxfConstants.OPERATION_NAME, String.class); if ("getCustomer".equals(operationName)) { String httpMethod = inMessage.getHeader(Exchange.HTTP_METHOD, String.class); assertEquals("Get a wrong http method", "GET", httpMethod); String path = inMessage.getHeader(Exchange.HTTP_PATH, String.class); // The parameter of the invocation is stored in the body of in message String id = (String) inMessage.getBody(String.class); if ("/customerservice/customers/126".equals(path)) { Customer customer = new Customer(); customer.setId(Long.parseLong(id)); customer.setName("Willem"); // We just put the response Object into the out message body exchange.getOut().setBody(customer); } else { if ("/customerservice/customers/123".equals(path)) { // send a customer response back Response r = Response.status(200).entity("customer response back!").build(); exchange.getOut().setBody(r); return; } if ("/customerservice/customers/456".equals(path)) { Response r = Response.status(404).entity("Can't found the customer with uri " + path).build(); throw new WebApplicationException(r); } else { throw new RuntimeCamelException("Can't found the customer with uri " + path); } } } if ("updateCustomer".equals(operationName)) { assertEquals("Get a wrong customer message header", "header1;header2", inMessage.getHeader("test")); String httpMethod = inMessage.getHeader(Exchange.HTTP_METHOD, String.class); assertEquals("Get a wrong http method", "PUT", httpMethod); Customer customer = inMessage.getBody(Customer.class); assertNotNull("The customer should not be null.", customer); // Now you can do what you want on the customer object assertEquals("Get a wrong customer name.", "Mary", customer.getName()); // set the response back exchange.getOut().setBody(Response.ok().build()); } } }); } }; }
And the corresponding resource class used to configure the endpoint:
@Path("/customerservice/") public class CustomerServiceResource { public CustomerServiceResource() { } @GET @Path("/customers/{id}/") public Customer getCustomer(@PathParam("id") String id) { return null; } @PUT @Path("/customers/") public Response updateCustomer(Customer customer) { return null; } }
Important | |
---|---|
The resource class is used to configure the JAXRS properties only. The methods will not be executed during the routing of messages to the endpoint, the route itself is responsible for all processing instead. |
CXF JAXRS front end
implements a proxy
based client API, with this API you can invoke the remote REST service
through a proxy. camel-cxfrs
producer is based on this proxy
API. So, you just need to specify the operation name in the message header
and prepare the parameter in the message body, camel-cxfrs
producer will
generate right REST request for you.
Here is an example
Exchange exchange = template.send("direct://proxy", new Processor() { public void process(Exchange exchange) throws Exception { exchange.setPattern(ExchangePattern.InOut); Message inMessage = exchange.getIn(); setupDestinationURL(inMessage); // set the operation name inMessage.setHeader(CxfConstants.OPERATION_NAME, "getCustomer"); // using the proxy client API inMessage.setHeader(CxfConstants.CAMEL_CXF_RS_USING_HTTP_API, Boolean.FALSE); // set the parameters , if you just have one parameter // camel will put this object into an Object[] itself inMessage.setBody("123"); } }); // get the response message Customer response = (Customer) exchange.getOut().getBody(); assertNotNull("The response should not be null ", response); assertEquals("Get a wrong customer id ", String.valueOf(response.getId()), "123"); assertEquals("Get a wrong customer name", response.getName(), "John"); assertEquals("Get a wrong response code", 200, exchange.getOut().getHeader(Exchange.HTTP_RESPONSE_CODE));
CXF JAXRS front end
also provides a http
centric client API, You can also invoke this API from
camel-cxfrs
producer. You need to specify the HTTP_PATH and Http
method and let the the producer know to use the HTTP centric client by using the URI
option httpClientAPI or set the message header with
CxfConstants.CAMEL_CXF_RS_USING_HTTP_API
. You can turn the response
object to the type class that you specify with
CxfConstants.CAMEL_CXF_RS_RESPONSE_CLASS
.
Exchange exchange = template.send("direct://http", new Processor() { public void process(Exchange exchange) throws Exception { exchange.setPattern(ExchangePattern.InOut); Message inMessage = exchange.getIn(); setupDestinationURL(inMessage); // using the http central client API inMessage.setHeader(CxfConstants.CAMEL_CXF_RS_USING_HTTP_API, Boolean.TRUE); // set the Http method inMessage.setHeader(Exchange.HTTP_METHOD, "GET"); // set the relative path inMessage.setHeader(Exchange.HTTP_PATH, "/customerservice/customers/123"); // Specify the response class , cxfrs will use InputStream as the response object type inMessage.setHeader(CxfConstants.CAMEL_CXF_RS_RESPONSE_CLASS, Customer.class); // since we use the Get method, so we don't need to set the message body inMessage.setBody(null); } }); // get the response message Customer response = (Customer) exchange.getOut().getBody(); assertNotNull("The response should not be null ", response); assertEquals("Get a wrong customer id ", String.valueOf(response.getId()), "123"); assertEquals("Get a wrong customer name", response.getName(), "John"); assertEquals("Get a wrong response code", 200, exchange.getOut().getHeader(Exchange.HTTP_RESPONSE_CODE));
From Fuse Mediation Router 2.1, we also support to specify the query parameters from CXFRS URI for the CXFRS HTTP centric client.
Exchange exchange = template.send("cxfrs://http://localhost:" + getPort2() + "/" + getClass().getSimpleName() + "/testQuery?httpClientAPI=true&q1=12&q2=13"
To support the Dynamical routing, you can override the URI's query parameters by
using the CxfConstants.CAMEL_CXF_RS_QUERY_MAP
header to set the parameter
map for it.To support the Dynamical routing, you can override the URI's query parameters
by using the CxfConstants.CAMEL_CXF_RS_QUERY_MAP
header to set the
parameter map for it.
Map<String, String> queryMap = new LinkedHashMap<String, String>(); queryMap.put("q1", "new"); queryMap.put("q2", "world"); inMessage.setHeader(CxfConstants.CAMEL_CXF_RS_QUERY_MAP, queryMap);