I am working on a project where I am using Apache Camel to establish a connection to a URL using Java code in a method:
public void establishConnection()
{
final CamelContext context = new DefaultCamelContext();
camelContext.addRoutes(new RouteBuilder(){//logic});
camelContext.start();
Thread.sleep(7500);
camelContext.stop();
}
The issue is that it is necessary to pause the thread, otherwise the following code executes, so to wait for the response as it takes camel time to start.
Now the issue is if this method gets called many times and I want the camel context to be initialized once only with the route so that we dont have to use the sleep here for subsequent calls.
What context are you in? You don't need to do the work to start/stop by yourself (as Adam also commented), Camel does it for you.
When you are building a Spring Boot application, check out how to use Camel with Spring Boot.
When you use Camel standalone, have a look at this example.
Related
For an IoT project I am working on I am researching a next, enhanced, version of our “Socket Handler” which is over 5 years of age and has evolved in a big beast doing apart from handling socket connections with IoT devices also in thread processing that has become a real pain to manage.
For my total rewrite I am looking into Apache Camel as a routing and transformation toolkit and understand how this can help us split processing steps into micro-services, loosely coupled through message queues.
One thing that I have trouble understanding however is how I can implement the following logic “the Apache Camel way”:
An IoT device sends an initial message which contains its id, some extra headers and a message payload.
Apart from extracting the message payload and routing it to a channel, I also need to use the device Id to check a message queue, named after the device id, for any commands that have to go to the device over the same socket connection that received the initial message.
Although it seems that Netty4, which is included in Camel, can deal with synchronous duplex comms, I cannot see how the above logic can be implemented in the Camel Netty4 component. Camel Routing seems to be one way only.
Is there a correct way to do this or should I forget about using camel for this and just use Netty4 bare?
It is possible to reproduce a full duplex communication by using two Camel routes :
thanks by using reuseChannel property
As this full duplex communication will be realised thanks to two different Camel routes, sync property must be set to false.
Here the first route:
from("netty4:tcp://{{tcpAddress}}:{{tcpPort}}?decoders=#length-decoder,#string-decoder&encoders=#length-encoder,#bytearray-encoder&sync=false&reuseChannel=true") .bean("myMessageService", "receiveFromTCP").to("jms:queue:<name>")
This first route will create a TCP/IP consumer thanks to a server socket (it is also possible to use a client socket thanks to property clientMode)
As we want to reuse the just created connection, it is important to initialize decoders but also encoders that will be used later thanks to a bean (see further). This bean will be responsible of sending data by using the Channel created in this first route (Netty Channel contains a pipeline for decoding / encoding messages before receiving from / sending to TCP/IP.
Now, we want to send back some data to the parter connected to the consumer (from) endpoint of the first route. Since we are not able to do it thanks to classical producer endpoint (to), we use a bean object :
from("jsm:queue:<name>").bean("myMessageService", "sendToTCP");
Here the bean code :
public class MessageService {
private Channel openedChannel;
public void sendToTCP(final Exchange exchange) {
// opened channel will use encoders before writing on the socket already
// created in the first route
openedChannel.writeAndFlush(exchange.getIn().getBody());
}
public void receiveFromTCP(final Exchange exchange) {
// record the channel created in the first route.
this.openedChannel = exchange.getProperty(NettyConstants.NETTY_CHANNEL, Channel.class);
}
}
Of course,
the same bean instance is used in the two routes, you need to use a registry to do so :
SimpleRegistry simpleRegistry = new SimpleRegistry();
simpleRegistry.put("myMessageService", new MessageService());
Since the bean is used in two different asynchronous routes, you will have to deal with some unexected situations, by for example protecting the access of openedChannel member, or dealing with unexpected deconnexion.
This post helped me a lot to find this solution :
how-to-send-a-response-back-over-a-established-tcp-connection-in-async-mode-usin
reuseChannel property documentation
After end of camel route, exchange's body and headers will back to requester as response.
Is it legal in Apache Camel to start route (and consumer) after it was stopped programmatically?
I have route which is not started automatically (noAutoStartup()). App is also using Spring Boot.
Now, starting this route, stopping and starting again causing to consumers to be duplicated; observed on Hazelcast consumer.
I've tried to add ServiceHelper.startService(consumer) and ServiceHelper.stopService(consumer) with no effect.
I tried to stop route using camelContext.stopRoute(route.getId()) and control bus - same effect.
Camel 2.19.4; 2.20.1
Solution:
It turned out that HazelcastComponent cannot be stopped because it listens to events from Hazelcast and do not unregister this listener during component shutdown.
However, this component is deprecated since 2.20.x, and part of its functionality is available in HazelcastQueueComponent. Finally, HazelcastQueueConsumer in POLL mode respects the fact that service is stopped.
I have a couple of Apache Camel routes created using the Java DSL and Spring.
#Bean
public CamelContext camelContext() throws Exception {
CamelContext camelContext = new DefaultCamelContext();
camelContext.addRoutes(route1bean());
...
camelContext.start();
return camelContext;
}
These routes use quartz2 component for scheduling and everything works as expected.
The jobs can however have errors when running and there is a requirement to retry them manually. I'm looking for a way to make adhoc manual execution of the route using hawtio or in Java code.
Yes , use jconsole. There are many mbeans exposed by camel. You can use them to start and stop. Of course you can do the same using Hawtio as well.
Updated based on your comment:
I get what you mean, This is the approach I will take. Create 3 routes. 2 light weight routes - Route A with Simple File From endpoint, Route B with Cron and Route C with direct:bla From endpoint, which contains the actual business logic. This way, you can trigger Route A whenever you want, Route C is common, Irrespective of when Route B is triggered by the cron.
I have a route like the following to a dynamic computed HTTP URL:
from("file:in")
.recipientList(simple(jettyUrl + "?id=${exchangeId}"))
.to("file:out?fileName=abc");
as it is described in the FAQ:
http://camel.apache.org/how-do-i-use-dynamic-uri-in-to.html
Each time an exchange is processed a new jetty component with a new threadpool is created. The threadpool is newer released. After a couple of exchanges the threads are exhausted.
I'am using Camel 2.12.2. In that version it is not possible anymore to set an httpClient instance or an executor to the jetty component to prevent the leak. The options httpClientThreadPool and httpClient that would be useful have been removed in camel 2.11.
How can I request an HTTP Url containing query parameters without leaking threads.
Maybe my approach is wrong and somebody can point me in the right direction.
My approach was wrong. By using an HTTP_QUERY or HTTP_URI header the recipientList is not needed anymore and only one endpoint is created. As a result there is no thread leak anymore.
.setHeader(Exchange.HTTP_URI, simple("http://somehost3244.org/id=${exchangeId}"))
.to("jetty:http://dummyhost243242.org")
I have aggregation configured in my code:
.aggregate(new BodyAggregationStrategy())
.constant(true)
.completionSize(1000) // Static value
.completionTimeout(300) // Static value
After I have started the Apache Camel context is it possible to change various parameters like completionSize and completionTimeout values?
When context is running a lot of data are transfering throught it and I want to increase some parameters like queue size and so on.
What you could do, is via the CameContext
stop the route
remove the route
add the route with new parameters
start the route
Have you tried to connect via JMX and see if those parameters can be configured?