Invoke external REST API using Camel and Spring - java

The question may be generic but it's quite just what the title says.
I have an external API using HTTPS which I need to invoke within a Camel route to get some JSON response back however, I cannot seem to find a good way to do this.
I tried Camel's component 'restlet' to invoke the API but no luck. I tried to make use of CXFRS which requires a bean to be setup, which in turn requires a 'serviceClass' as far as I understand. Obviously with the API being a third-party external service there is no way to supply that.
Does anyone have any ideas or directions that they can point me in to merely invoke an external REST API which returns a JSON response?
Much appreciated.

Ok, it turns out I was utterly confused!
#Component
public class WeatherRESTRoute extends RouteBuilder {
#Override
public void configure() throws Exception {
from("timer:aTimer?fixedRate=true&period=10s")
.setHeader(Exchange.HTTP_METHOD, constant("GET"))
.to("ahc:https://restcountries.p.mashape.com/callingcode/90")
.routeId("TEST")
.log("${body}");
}
This is the working route as per my question and troubles I had the REST API URL in the .from which in Camel land means I want to expose that as a REST Endpoint rather than invoke it.
I was able to come to my sense while reading through the mailing list linked below.
http://camel.465427.n5.nabble.com/Making-Periodic-HTTP-Request-Using-Timer-td5749336.html
P.S.Thank you #6ton I have tried the solutions on that page before hand.

Using spring DSL with timer component
<?xml version="1.0" encoding="UTF-8"?>
<routes xmlns="http://camel.apache.org/schema/spring"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd">
<route id="fetchdata">
<from uri="timer:somename?period=24h"/>
<toD uri="https://some/api/xxx?httpMethod=GET"/>
<to uri="file://abcd?fileName=${exchangeId}&fileExist=Append"/>
</route>
</routes>
In above we are storing it in file, if you want you can you can send it to other route or queue
<to uri="activemq:queuename?jmsMessageType=Text&exchangePattern=InOnly"/>

Related

Execute #Handler method in multi-thread

Need to execute #Handler(import org.apache.camel.Handler) method in multi-threading environment. below is my current code and camelroute.xml file. Any Idea or suggestion would be appreciable.
#Component("messagehandler")
public class HandleMessages {
#Handler
public void handle(String body, Exchange exchange) throws Exception {
// do some business operation
}
}
<?xml version="1.0" encoding="UTF-8"?>
<routes xmlns="http://camel.apache.org/schema/spring"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd">
<route id="IncomingRoute">
<from uri="someSourceURL" />
<to uri="bean:messagehandler" />
<log message="Message Body - ${body}" />
</route>
</routes>
In general terms, thread safety is all about execution – that's all. A given method / routine / piece of code is thread-safe if it guarantees the manipulation of shared data (data structures, etc.) safely in a way that multiple threads don't corrupt that data.
So it really depends on how you structure the execution of a given workflow; and that's the same for any other piece of code you can think of.
Since you are using Apache Camel, take a look at their threading model. If I remember correctly, you would have to define your routes / workflows in such a way they run concurrently by using parallelProcessing (CC EIP), a custom thread pool, or using staged event-driven architecture (SEDA); at that point you would need to take care about what you do in the handlers (or any other "processor(s)" that handle shared data), otherwise you should be OK.
Another thing you need to think about is how Camel uses its routing engine to route messages synchronously or asynchronously; be aware that synchronicity and MEP affects the threading model.

How to modify a camel endpoint at runtime

The problem
I have a spring mvc application that uses apache camel. I am confused on the role that the RouteBuilder class plays and how it actually gets initialized. I know that the docs say that the configure() method is:
Called on initialization to build the routes using the fluent builder syntax.
but when does this initialization occur? Does it occur at application startup or some time later when the route is about to be used?
The purpose of this question is ultimately to ask how I can modify the route at runtime. I want to be able to build different routes as needed.
Examples
xml definitions:
<service name="myService" tier="3">
<requestType>my.package.RequestType</requestType>
<responseType>my.package.ResponseType</responseType>
<endpoint>
<httpEndpoint>
<url default="true" value="someUrl"/>
<timeout value="5000"/>
</httpEndpoint>
</endpoint>
</service>
Route Builder template:
public class myRouteBuilder extends RouteBuilder {
#Override
public void configure() throws Exception {
// When does this method get executed?
}
}
Questions
When does configure() execute?
How can I dynamically set the endpoint url?
You are able to use toD to dynamically change the endpoint at runtime based on an expression. See the documentation
If you want to change more of the route or add a completely new route then look at the API on the CamelContext. This Stackoverflow question has an example of adding a completely new route.
The lifecycle of the Camel service is documented here : https://camel.apache.org/lifecycle.html
Camel uses a simple lifecycle interface called Service which has a single start() and stop() method.
Various classes implement Service such as CamelContext along with a number of Component and Endpoint classes.
When you use Camel you typically have to start the CamelContext which will start all the various components and endpoints and activate the routing rules until the context is stopped again.
It is when the context starts that the various components start. Not sure i understand the dynamic url part. If it is to indicate a dynamic endpoint (if the data is this , then queue1 else queue2) you should be able to use something like the DynamicRouter EIP which is as explained here (https://camel.apache.org/dynamic-router.html)
You have several options.
Inject them as spring properties.
Inject them from external properties source.
Inject them from some bean method.
Then you can put the property value in a header and later put the value in the .toD("$header.routeEndpoint"). This can take care of dynamic endpoints.
Off course to rebuild the entire route you need to play with the API.

Create Camel endpoints in java to use in xml routes

I've been trying to create endpoints in java and have those endpoints referenced in my xml routes but have been unsuccessful. I can do this in xml:
<endpoint id="kafkatopic" uri="kafka:..."/>
and have the endpoint referenced in the routes:
<route id="eventflow">
<from ref="kafkatopic" ...>
What i want to do is replace the xml endpoint declaration using java. I've tried something like:
Endpoint kafkaep = camelCtx.getEndpoint(kafkaUri);
however i'm stumped on how i can create a key "kafkatopic" to refer to the endpoint such that the xml route is able to find it. I've checked the EndpointRegistry but doesn't allow me to provide a simple name for the endpoint.
Any help is appreciated. Thanks.
Here's my camelContext:
<camelContext xmlns="http://camel.apache.org/schema/blueprint"
trace="true" id="context">
<routeBuilder ref="myRouteBuilder" />
<route id="eventflow">
<from ref="kafkatopic" ...>
My simplified RouteBuilder.configure() has below. Here i was trying to put the endpoint in the endpointRegistry hoping that it will used by the xml route. There's not a lot of docs on EndpointRegistry so i was shooting in the dark with this.
// endpoint i have formatted to be "someKey=uri"
String endPoint = getConfigs("camel-endpoint");
String [] eptoks = ep.split("=", 2);
EndpointRegistry<String> endpointRegistry = camelContext.getEndpointRegistry();
Endpoint endpoint = camelContext.getEndpoint(eptoks[1]);
endpointRegistry.put(eptoks[0], endpoint);
You could try defining the endpoint in Spring, either explicitly:
<bean id="kafkaComponent" class="org.apache.camel.component.kafka.KafkaComponent"/>
<bean id="kafkaEndpoint" class="org.apache.camel.component.kafka.KafkaEndpoint">
<constructor-arg value="kafka:..."/>
<constructor-arg ref="kafkaComponent"/>
</bean>
or using Spring factory bean and method:
http://www.javabeat.net/create-spring-beans-using-factory-methods/
The easiest way to achieve this would be to create a class which implements the
org.apache.camel.Processor
interface and configure this in the spring xml file, e.g.
<bean id="sp" class="com.mycompany.SimpleProcessor"/>
In your route you can then reference this simply using the id you gave in the bean, e.g.
<to uri="sp" />
I would say that makes it a bit confusing to read although perhaps you have a good reason but when I look at the route I want to clearly know the endpoint details unless they are referenced above somewhere. To have to look up the endpoint in a java class can be cumbersome later on.
I recently found out that you can write your entire RouteBuilder logic in java and simply let the blueprint xml call it just like any other bean? That why your routes are in java and the startup mechanism in xml.
I know it's late but here's what i did to make this work. Basically i programmatically created the endpoints simply as "direct" endpoints based on configuration and reference those direct endpoints in my camel routes xml file. That way i avoided having environment specific values like hostnames, port numbers, etc., in my xml routes file and just have one version for all environments.

How do i use multiple CXF endpoints to call a webservice in Camel?

I have two endpoints:
CXF_FIRST_ENDPOINT="cxf:bean:cxfEndpoint?{address=first_address}&serviceClass=com.service.class.first"
CXF_SECOND_ENDPOINT="cxf:bean:cxfEndpoint?{address=second_address}&serviceClass=com.service.class.second"
How do I implement two separate web service call after defining the endpoints. If I use both, and consume the endpoints using the routes, one of the endpoints will override the other and I am able to use only one. If I comment the other endpoint, Its running successfully. However I need to use both. I am using messageContentList for both the web service response:
MessageContentsList result = (MessageContentsList) exchange.getIn().getBody();
Thanks, please let me know if you need more information
Here is the route-definition:
from("direct:paymentInfo").routeId("PaymentInfo")
.bean(billingServiceProcessor, "processBillingPaymentRequest")
.to(CXF_BILLINGSERVICE_ENDPOINT)
.bean(billingServiceProcessor, "processBillingPaymentResponse")
.end();
from("direct:Holidays").routeId("HolidayRetrieval")
.bean(entityProcessor, "processHolidaysRequest")
.to(CXF_ENTITYSERVICE_ENDPOINT)
.bean(entityProcessor, "processHolidaysResponse")
.end();
I solved the problem. I found out that both the endpoints were using the same beanid (cxfEndpoint) that was defined in the camel-config.xml.
I defined another id cxfEndpoint1 in camel-config.xml and used it to my endpoint and that solved the problem. Both the web-service calls are working fine without hassles.
<bean id="cxfEndpoint" class="org.apache.camel.component.cxf.CxfEndpoint" />
<bean id="cxfEndpoint1" class="org.apache.camel.component.cxf.CxfEndpoint"/>
and here are the respective endpoints:
CXF_FIRST_ENDPOINT="cxf:bean:cxfEndpoint?{address=first_address}&serviceClass=com.service.class.first"
CXF_SECOND_ENDPOINT="cxf:bean:cxfEndpoint1?{address=second_address}&serviceClass=com.service.class.second"
Thanks,

How can I invoke a RESTful service through Apache Camel?

I am currently using a HTTP method for invoking some URL which will create a JIRA issue.
Now I want to use Apache Camel, how can I use that?
I need to invoke the following link through Camel:
http://localhost:8080/rest/api/2/project/" + key + /components
As I'm new to Camel, please suggest some solutions and examples too.
Thanks
See also this FAQ about using dynamic to endpoints in Camel
http://camel.apache.org/how-do-i-use-dynamic-uri-in-to.html
Essentially the EIP pattern for this is the recipient list.
So in your case it could also be simplified to as one EIP
<recipientList>
<simple>http://localhost:8080/rest/api/2/project/${header.myKey}/components</simple>
</recipientList>
Mind the http component in Camel is fully synchronous. If you want to do request/reply over HTTP and avoid having the caller block while waiting for the reply message, then you can use some of the other HTTP components from Camel such as:
camel-ahc
camel-http4
camel-jetty
You could easily use the CXFRS Component; if you need to do it using the HTTP Component for some reason you could easily use that as well:
<setHeader headerName="CamelHttpUri">
<simple>http://localhost:8080/rest/api/2/project/${header.myKey}/components</simple>
</setHeader>
<inOut uri="http://doesnt.matter.we/override/it/anyways" />
And of course you will need to enrich your message with the myKey header before getting to this part of the route.
I am using apache camel jetty
CamelContext context = new DefaultCamelContext();
public void configure(){
context.addRoutes(new RouteBuilder(){
from("jetty:localhost:9000/offers")
.to("direct:getOffers")
.end();
}
});
so here when the user will hit http://localhost:9000/offers then the endpoint direct:getOffers will get invoked
so now defining the getOffers end point
context.addRoutes(new RouteBuilder(){
public void configure(){
from("direct:getOffers")
.to("jetty:http://localhost:9008/api/v2.0/offers?
bridgeEndpoint=true")
.end();
}
});
Here another service is running at 9008 having a rest resource of
http://localhost:9008/api/v2.0/offers and this is the resource that i am trying to consume.
so when camel instance starts it registers both the routes then it does the processing as described above
Note Its important to add the option of ?bridgeEndpoint=true for this to work
You can consume REST service from camel using CXFRS Component.Apache camel has enough information about this.
http://camel.apache.org/cxfrs.html

Categories