Expose an OSGi Service as Camel Endpoint - apache-camel

I don't even know if I formulated the question the right way around ;-)
What I basically want to achieve is something like this:
<route >
<from uri="osgi:serviceName"/>
<!-- do some processing ->
<to uri="activemq:queue:inbox"/>
</route>
So I'd like to have an OSGi Service as starting point of my route. This service can be referenced by some other bundles and fed with input data, that will be later on processed by the Route.
How would I do this?

Simply create an OSGi service outside of camel and a route that starts with direct:anyname. Then you can inject a ProducerTemplate into your service an call the route from there.

If you have really simple method signature, or typeConverter for the parameters you want to pass, you can use CamelProxy to link the service to your route in a simple XML configuration file.
To extends the example of the doc, you would have something like :
<osgi:service id="service" ref="myProxySender" (4)
interface="org.apache.camel.spring.config.MyProxySender" />
<camelContext xmlns="http://camel.apache.org/schema/spring">
<!-- create a proxy that will route to the direct:start endpoint when invoked -->
<proxy id="myProxySender"
serviceInterface="org.apache.camel.spring.config.MyProxySender"
serviceUrl="direct:start"/>
<!-- this is the route that our proxy will routed when invoked
and the output from this route is returned as reply on the proxy -->
<route>
<from uri="direct:start"/>
<transform>
<simple>Bye ${body}</simple>
</transform>
</route>
</camelContext>

To use "osgi" as the URI scheme in a Camel route, you would need to create a custom Camel component to handle invoking the relevant OSGi commands. For more information, please see http://camel.apache.org/creating-a-new-camel-component.html
A simpler alternative would be to write custom OSGi commands that used a ProducerTemplate to send messages to a Camel route. An example for Karaf can be found here: https://github.com/apache/karaf/tree/master/demos/command
Injecting a ProducerTemplate can be done via standard Spring configuration.

Related

Apache Camel: can a direct endpoint run routes in parallel?

In my Camel application there are 2 CXF endpoints that are handled by the same processing route, and AFAIK each endpoint may produce Exchanges in parallel depending on incoming HTTP requests.
Both endpoints forward the request through the same route using direct: component, which is sometimes described as the Camel equivalent of calling a method.
The direct: component provides direct, synchronous invocation of any consumers when a producer sends a message exchange.
My questions:
Does direct: component run different requests in parallel? (each request has its own Exchange and is executed by a different java Thread)
If not, how do I handle CXF requests in parallel?
This is my situation:
<route id="CxfRoute1">
<from uri="cxf:bean:endpoint1" />
<to uri="direct:handle" />
</route>
<route id="CxfRoute2">
<from uri="cxf:bean:endpoint2" />
<to uri="direct:handle" />
</route>
<route id="HandleStuffRoute" />
<from uri="direct:handle" />
<to uri="bean:stuffHandler" />
</route>
It works like a direct method call, eg Foo foo = ... ; foo.callSomeMethod() which uses the current thread to call. So you get parallel from the consumer in this example CXF, so if 2+ clients call CXF at the same time, each calls runs in its own thread, and each of them call direct as a direct method invocation and all that can run in parallel.
In your case yes it should run the different requests in parallel.
You can probably create a Camel unit test that tests this. In your route test class you can create a new route that is timer based and then create some dummy body and call your route endpoints like this:
.parallelProcessing().to("cxf1", "cxf2", "cxf3")
and then observe the results.
I guess another way is to use JMeter and create a test against your cxf endpoints and observe.
For handling parallel requests in the same way as using direct you can use "seda" instead. Details at http://camel.apache.org/seda

httpClientConfigurerRef for Apache Camel for specific routes

Lets say that I want to communicate to a rest service with SSL with Camel, and I'm creating a custom HttpClientConfigurer which will set that stuff:
<bean id="myHttpClientConfigurer"
class="my.https.HttpClientConfigurer">
</bean>
<to uri="https://myhostname.com:443/myURL?httpClientConfigurerRef=myHttpClientConfigurer"/>
And the HttpClientConfigurer implements org.apache.camel.component.http.HttpClientConfigurer.
So my question is, will this custom HttpClientConfigurer will be active for only that route (where I specify it with httpClientConfigurerRef)? Or will it affect other Camel routes that use the http component?
Just for that route. Always test and verify! Fire up a second route without it and you should observe that the second route does not handle the SSL handshake.

Clarification about Camel direct component

I can see that many Camel route examples are initiated with a "direct" component. For example:
<camelContext xmlns="http://camel.apache.org/schema/spring">
<route id="myroute">
<from uri="direct:start"/>
<setBody>
<simple>Hello World!</simple>
</setBody>
<log message="${body}"/>
<to uri="mock:result"/>
</route>
</camelContext>
However, by running a route like this (mvn camel:run) the route is not started and Camel keeps hanging forever. Is it not meant to be used directly this kind the direct component?
Thanks
Its not hanging. You need to send a message to the direct endpoint before its routed. eg like in java code to do a direct method invocation from a client by calling a java method.
Instead of direct you can use a timer if you want to route a message automatic every X time etc.
To send a message to the direct endpoint (or any other Camel endpoint) then read about the producer template. For example from the getting started guide: http://camel.apache.org/walk-through-an-example.html

Routing Issue with camel-restlet

I am using camel and camel-restlet component for routing RESTFul web services. My route configuration looks like:
<from uri="restlet:/camel/my/path/{param1}/{param2}?restletMethods=PUT&throwExceptionOnFailure=false" />
<loadBalance inheritErrorHandler="false">
<failover roundRobin="true" maximumFailoverAttempts="2">
<exception>java.io.IOException</exception>
</failover>
<to uri="http://server1:8080/my/path/${header.param1}/${header.param2}?bridgeEndpoint=true&throwExceptionOnFailure=false" />
<to uri="http://server2:8080/my/path/${header.param1}/${header.param2}?bridgeEndpoint=true&throwExceptionOnFailure=false" />
</loadBalance>
I have some input route configurations like:
restlet:/camel/my/path/{param1}/{param2}?restletMethods=PUT
restlet:/camel/my/path/param1/{param2}?restletMethods=GET
When a call comes as GET: /my/path/param1/foo, Restlet is routing this request to the first router and the request is failing with 404. I am expecting restlet to route this request to second router. I went the post restlet-routing-nightmare, but in my case, I cannot change the URIs as I am just doing the routing part with camel and I have no control on the URIs of the underlying services. Underlying services are on Jersey framework and they don't have issues with these type of URL patterns.
Can anyone suggest a solution for this in restlet/camel.
You need to have throwExceptionOnFailure=true on the uris in the load balancer so the failover load balancer can react on the exception. Otherwise it assumes the process was successful.

Apache Camel VM queue between servlets

I'm trying to setup simple VM queue test between two servlets without success. The problem is that the request always timeouts as there is no response, OUT message, within expected timeframe.
"org.apache.camel.ExchangeTimedOutException: The OUT message was not received within: 30000 millis."
The servlets are running in Tomcat and are both deploying Apache Camel. Both apps are defining camel context and simple routes. The basic setup should be fine as simple routes like following are working:
<route>
<from uri="servlet:///hello?servletName=app1" />
<transform>
<simple>Hello world</simple>
</transform>
</route>
<route>
<from uri="servlet:///hello?servletName=app2" />
<transform>
<simple>Hello world</simple>
</transform>
</route>
First of all I'm not sure if the message ever reaches the app2 as the same timout happens even if the requested route wouldn't be even defined (the app2 would be missing the VM route). So the problem could be in how to define the route between two servlets using VM queue.
If the route between the servlets is fine then the problem should be in the missing/incorrect reply. I do understand that the receiving end should return the reply as the incoming requst from web server is inOut type, but I don't know how to achieve that.
The route in app1 receiving the web request:
<route>
<from uri="servlet:///test?servletName=app1" />
<to uri="vm:test">
</route>
and the other end in servlet app2:
<route>
<from uri="vm:test" />
// Tested here: output with <simple>, 'To', 'inOut'... the result is always timeout
</route>
As I'm new with Apache Camel the root cause is most likely very simple. Any help would be highly appreciated.
The question is simply, how to setup VM queue between two servlet apps?
The vm component works in the same classloader, eg kinda what we say on the vm documentation page: http://camel.apache.org/vm.html
This component differs from the SEDA component in that VM supports
communication across CamelContext instances - so you can use this
mechanism to communicate across web applications (provided that
camel-core.jar is on the system/boot classpath).
So if you use Apache Tomcat, you need to have camel-core JAR as shared JAR. Such as in the boot classpath somewhere.

Resources