Camel, CXF REST endpoints, and route builders; Am I doing it right?
dazbert42 Apr 11, 2013 7:06 AMHi,
I'm attempting to use Camel as an endpoint for a RESTful interface, and while I've managed to get the behaviour I want; I'm wondering whether I've missed something in the way my components are wired together as the mechanism I have used seems overly error prone.
In this instance I've used the Camel-Spring archetype within the Fuse IDE as the basis for my project. I'm running fuse-esb-full-7.1.0.fuse-047.
Apologies in advance for the formatting. I couldn't find markup for a "code block".
My camel-context.xml file contains the following configuration information:
-
-
The GetThingInterface is an empty class with a bunch of annotations as follows:
-
@Path("/getthing/")
public class GetThingInterface {
@GET @Path("/one")
public String getSingleThingByQuery(@QueryParam("machineId") String machineId) {
return null;
}
@GET @Path("/many")
public String getManyThingByQuery(@QueryParam("machineId") String machineId) {
return null;
}
}
-
The GetThingImplementation is equally exciting. There's no annotations here because they are not used by anything.
-
public class GetThingImplementation {
public String getSingleThingByQuery(String machineId) {
return "You got 1 " + machineId;
}
public String getManyThingByQuery(String machineId) {
return "You got MANY " + machineId + "s";
}
}
-
The route builder is where things get really interesting.
If I use the route:
from("cxfrs://bean://thingServer")
.to("bean:rsThingService");
I will always get an Ambiguous Method Exception as Camel doesn't know which method (getSingleThingByQuery or getManyThingByQuery) on my bean to invoke.
I did try the following to see if I could get the method invocation to occur automagically; but the header value isn't expanded.
.to("bean:rsThingService?method=${header.operationname}")
However, if I use the following route:
from("cxfrs://bean://thingServer")
.choice()
.when(header("operationname").isEqualTo("getSingleThingByQuery"))
.to("bean:rsThingService?method=getSingleThingByQuery")
.otherwise()
.to("bean:rsThingService?method=getManyThingByQuery");
I get the behaviour I expect. Camel is smart enough to pass the "machineId" parameter within the REST request into the method.
My question is, is there a better way? Having to explicitly reference methods by name seems overly error prone and fragile.
-
A secondary question is about the
Where double bean A and B were individual route builders, one for the /bin/getthing/one path and the other for the /bin/getthing/many path. Weirdly although I didn't see any errors, the second route builder simply replaced the first. So rather than having both routes available only the last one defined would work.
-
As an aside I did discover that if you attempt to define multiple cxf:rsServer elements with id values that use numbers, when the package is loaded into Fuse you get a duplicate ID error. e.g. When I defined the following I got a duplicate ID "thingServer" error.
<cxf:rsServer id="thingServer1" address="http://localhost:8111/cxf/bin"
serviceClass="com.oink.CXFEndPointTests.singlebean.GetThingInterface1"/>
<cxf:rsServer id="thingServer2" address="http://localhost:8111/cxf/bin"
serviceClass="com.oink.CXFEndPointTests.singlebean.GetThingInterface2"/>
Changing the id values to thingServerA and thingServerB works around this behaviour.
All thoughts gratefully received.