Create Camel endpoints in java to use in xml routes - java

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.

Related

Spring Integration SFTP - Getting configurations from XML

Let say I have these configurations in my xml,
<int-sftp:outbound-channel-adapter id="sftpOutbound"
channel="sftpChannel"
auto-create-directory="true"
remote-directory="/path/to/remote/directory/"
session-factory="cachingSessionFactory">
<int-sftp:request-handler-advice-chain>
<int:retry-advice />
</int-sftp:request-handler-advice-chain>
</int-sftp:outbound-channel-adapter>
How can I retrieve the attributes i.e, remote-directory in Java class ?
I tried to use context.getBean('sftpOutbound') but it returns EventDrivenConsumer class which doesn't have methods to get the configurations.
I'm using spring-integration-sftp v 4.0.0.
I am actually more concerned with why you wan to access it. I mean the remote directory and other attributes will come with the headers of each message, so you will have access to it at the Message level, but not at the level of Event Driven Consumer and that is by design, hence my question.

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.

How to Inject String property to javax.jms.TextMessage in Spring Integration

I wanted to know is there any way to add properties to JMS text Message in Spring Integration.
For example if we use normal JMS code we can always set properties to it using the below code.
message.setStringProperty( "AuctionType", "Reverse" );
Edit
I tried to add the header as given in Spring document but now i am getting same message Id for each message, but as i am intended to use it as ID, so i need it to be different for each message.
Below is my snapshot of Spring configuration.
<bean class="com.learn.util.RandomMsgId" id="randomMsgId" factory-method="getRndMsgId" scope="prototype"/>
<int:header-enricher input-channel="xmlToJMS"
output-channel="xmltoJMSwithId">
<int:header name="MsgId" ref="randomMsgId"/>
</int:header-enricher>
Use a <header-enricher/> to add custom headers to the spring integration message and they will be mapped to JMS headers.
See the documentation and here.

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,

Invoke external REST API using Camel and Spring

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"/>

Categories