Hi i am having a JMS consumer route in camel, my requirement is to stop/suspend that route at certain incident(based on the some field value) and then resume that route using a scheduler.
For this i have created two routes, one is my original jms consumer route and one is scheduler route, that resume the jms consumer routes, although i am able to suspend the route but second route is not resuming the suspended route and its showing the state as started.
below are my two routes
original consumer route
from("activeMQ:demo.audit.event1?testConnectionOnStartup=true&acknowledgementModeName=CLIENT_ACKNOWLEDGE")
.routeId("javadslconsumer")
.log("before stopping==="+new Date().toString())
.process(new Processor() {
#Override
public void process(final Exchange exchange) throws Exception {
try {
Route route = exchange.getContext().getRoute("javadslconsumer");
System.out.println("route.supportsSuspension()"+route.supportsSuspension());
exchange.getContext().suspendRoute("javadslconsumer",1l,TimeUnit.SECONDS);
// create another helper route, using which we can start or resume this route based
// on the current life cycle phase of this route.
} catch (Exception e) {
// ignore
e.printStackTrace();
}
}
})
.log("after stopping logs==="+new Date().toString())
.unmarshal(dataFormat)
.beanRef("auditProcessor", "getErrorAuditDTO")
.beanRef("auditProcessor", "processCreateAudit");
scheduler route
from("timer:dlqscheduler?period=6000&fixedRate=true")
.process(new Processor(){
#Override
public void process(Exchange exchange) throws Exception {
System.out.println("timer process started");
try {
exchange.getContext().resumeRoute("javadslconsumer");
//exchange.getContext().startRoute("javadslconsumer");
} catch (Exception e) {
System.out.println("-----d-d-d-d-"+e.getMessage());
}
ServiceStatus serviceStatus = getContext().getRouteStatus("javadslconsumer");
System.out.println("serviceStatus.isStopped()"+serviceStatus.isStopped()); // showing false instead of true
System.out.println("serviceStatus.isSuspended()"+serviceStatus.isSuspended()); // showing false instead of true
System.out.println("serviceStatus"+serviceStatus);// showing started
}
})
.log("after resuming the route javadslconsumer");
Please help me how i can implement the above scenario.
You need to give it more time than 1 second. That is a fallback timeout, so if the suspension could not happen within 1 sec it let the route run instead. eg read the javadoc documentation of the API you use, and you can see that information.
Also btw there is a controlbus component so you can just send a message to an endpoint to suspend/resume a route.
http://camel.apache.org/controlbus
Related
To retrieve some open data from a remote web server to process, I'm trying out Apache Camel.
The problem is that it seems that the data is never received. I have tried the jetty, ahc and cxf components but can't get it to work. For example like this:
import org.apache.camel.CamelContext;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.impl.DefaultCamelContext;
public class CamelHttpDemo {
public static void main(final String... args) {
final CamelContext context = new DefaultCamelContext();
try {
context.addRoutes(new RouteBuilder() {
#Override
public void configure() throws Exception {
this.from("direct:start")
.to("ahc:http://camel.apache.org/")
.process(exchange -> {
System.out.println(exchange);
});
}
});
context.start();
Thread.sleep(10000);
context.stop();
} catch (final Exception e) {
e.printStackTrace();
}
}
}
No output is written so the line System.out.println(exchange); is never executed and I assume the data is not retrieved.
I'm using the most recent version of Apache Camel, 2.17.1.
You need some message producer in your route to emit Exchange that would trigger the http component. Your route starts with direct:start which cannot emit new Exchanges, it just sits and waits for someone to initiate the process.
The easiest way to make your route work is to replace direct:start with some producer. For instance, replacing it with this timer .from("timer://foo?fixedRate=true&period=10000") will trigger your http-request once every 10 seconds.
If you want to initiate the request manually, you need to create a ProducerTemplate and use it to send a message to direct:start. That would be:
ProducerTemplate template = context.createProducerTemplate();
template.sendMessage("direct:start", "Message body");
Following is the route that I have created -
from("jetty:http://localhost:8181/abc").routeId("abc").choice()
// Authenticate the request
.when(authenticator).endChoice()
// Authorize the request
.when(authorizer).endChoice()
// Validate the request
.when(abcValidator).endChoice()
.otherwise()
.process(abcRequestProcessor).process(storeFeatureRequestDetails).process(featureRequestApproverUpdater).split(body()).process(abcApproverMailer).to("direct:toMail");
The above route is functional but I do not want to add the authenticator and authorizer step to each and every route. Is there a way by which I can configure them to run before each route.
I tried the following -
from("jetty:http://localhost:8181/*").process(new Processor() {
#Override
public void process(Exchange exchange) throws Exception {
System.out.println("Triggered");
}
});
but it looks for exact match.
you can use the Camel interceptor API for this...
// intercept all incoming routes and log it
interceptFrom().process(new Processor() {
#Override
public void process(Exchange exchange) throws Exception {
System.out.println("Triggered");
}
});
If you don't want to put your AAA in every to each and every route why don't you extract their functionality and put them in separate routes and call them inside your route? Example code:
from("jetty:http://localhost:8181/abc").routeId("abc").choice()
// Authenticate the request
.to("direct:authenticator")
// Authorize the request
.to("direct:authorizer")
// Validate the request
.to("direct:abcValidator")
.process(abcRequestProcessor).process(storeFeatureRequestDetails).process(featureRequestApproverUpdater).split(body()).process(abcApproverMailer).to("direct:toMail");
Basically the authenticator is now in a separate route. You call it by "direct:authenticator". The same goes for authorize and validate.
This way, if you have other routes that need to use this functionality you just call the AAA routes.
I would like to run a route once and stop the context when the route is completed. Currently I do the usual Thread.sleep(3000) in the main Java class to leave some time for the route to finish but it's obviously not accurate, my route may take 1 second or 20 seconds I can not know in advance.
The Java class:
public static void main(String[] args) throws Exception {
try (ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("camel-context.xml")) {
CamelContext camelContext = SpringCamelContext.springCamelContext(context);
// context.start(); // apparently not necessary
camelContext.startRoute("route1");
try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); }
// context.stop(); // apparently not necessary
}
}
The Spring xml:
<route id="route1" autoStartup="false">
<from uri="timer://runOnce?repeatCount=1&delay=3000" />
...
</route>
After reading http://camel.465427.n5.nabble.com/Need-control-back-in-the-Main-routine-so-that-we-can-terminate-JVM-td4483312.html#a4484845 especially the 4th post, from Claus Ibsen, I was thinking of using camelContext.getRouteStatus() in a loop with a Thread.sleep() but wherever I try to get the route status in the code (even after the Thread.sleep(3000)), the status is always "started". I don't know any other way to detect when the route is done.
What is the recommended way to stop the Camel context when a/all route(s) is/are completed, using Spring?
The route will never stop because routes do not have complete state. They can just be started, stopped or paused. A route will always be running if it's in the started state unless you do something to change that.
To accomplish what you are looking for, you can do a couple of things:
You can use the controlbus component and stop the route in the last step of your route. That way you can check (for example the way you mentioned checking for camelContext.getRouteStatus()) when you should stop the context as well.
You can write a small Processor that whenever it receives an Exchange it will stop the camelContext. Once ready, you will add it to the last step of your route.
Camel supports onCompletion callbacks, which can be equivalent to the option above. See the camel page.
Probably, the first option is the easiest for your use case, however I would go for the second option. It seems cleaner to me.
A more elegant way would be to use a synchronisation mechanism provided by Java like CountDownLatch. Main thread will wait for the latch to be opened by the Route thread. Something like :
CountDownLatch latch = new CountDownLatch(1);
camelContext.addRoutes(createRoute(latch));
and somewhere in the createRoute Method add a processor at the end of the route to open the latch. This worked perfectly for me.
.process(new Processor() {
#Override
public void process(Exchange exchange) throws Exception {
latch.countDown();
}
});
I am writing my first camel application. it is a standalone application with a main method. As starting point i used the maven camel java archetype. It provides a simple main method that calls main.run().
Now i re-factored it a little bit and pulled the main.run out in a new class (and method) that will be my main-control of all camel stuff.
Now i want to create the "opposite" method of run(). At the moment i want to implement tests for single routs that start (run()) the context then wait (at the moment i am unsure how to wait 'til a route is finished) and the stop the context.
But now i discovered many method that could start and stop stuff all in Main class. The Jvadoc didn't help - that some methods are inherited doesn't make it easier ;-). So someone please tell me the exact meaning (or use case) for:
Main.run()
Main.start()
Main.stop()
Main.suspend()
Main.resume()
Thanks in advance.
See this page about the lifecycle of the various Camel services
http://camel.apache.org/lifecycle
And for waiting until a route is finished, then you can check the inflight registry if there is any current in-flight exchanges to know if a route is finished.
http://camel.apache.org/maven/current/camel-core/apidocs/org/apache/camel/spi/InflightRepository.html
We must separate the methods into 2 groups.
The first is the one described in the life cycle http://camel.apache.org/lifecycle
The second is composed of run and shutdown.
run runs indefinitely and can be stopped when invoking shutdown, the latter must be invoked in a different thread and sent before the run invocation.
Example:
import org.apache.camel.main.Main;
public class ShutdownTest {
public static void main(String[] args) throws Exception {
Main camel = new Main();
camel.addRouteBuilder( new MyRouteBuilder() );
// In this case the thread will wait a certain time and then invoke shutdown.
MyRunnable r = new MyRunnable(5000, camel);
r.excecute();
camel.run();
}
}
Simple Runnable class
public class MyRunnable implements Runnable {
long waitingFor = -1;
Main camel;
public MyRunnable(long waitingFor, Main camel){
this.waitingFor = waitingFor;
this.camel = camel;
}
public void excecute(){
Thread thread = new Thread(this);
thread.start();
}
#Override
public void run() {
try {
synchronized (this) {
this.wait( waitingFor );
}
} catch (InterruptedException e) {
}
try {
System.out.println("camel.shutdown()");
camel.shutdown();
} catch (Exception e) {
e.printStackTrace();
}
}
}
I'm working on a camel prototype which uses two start points in the same camel context.
The first route consumes messages which are used to "configure" the application. Messages are loaded in a configuration repository through a configService bean:
// read configuration files
from("file:data/config?noop=true&include=.*.xml")
.startupOrder(1)
.to("bean:configService?method=loadConfiguration")
.log("Configuration loaded");
The second route implements a recipient list eip pattern, delivering a different kind of input messages to a number of recipients, which are read dinamically from the same configuration repository:
// process some source files (using configuration)
from("file:data/source?noop=true")
.startupOrder(2)
.unmarshal()
.to("setupProcessor") // set "recipients" header
.recipientList(header("recipients"))
// ...
The question that arises now is how to synchronize them, so the second route "waits" if the first is processing new data.
I'm new to Apache Camel and pretty lost on how to approach such a problem, any suggestion would be appreciated.
Use aggregate in combination with the possibility to start and stop routes dynamically:
from("file:data/config?noop=true&include=.*.xml")
.id("route-config")
.aggregate(constant(true), new MyAggregationStrategy()).completionSize(2).completionTimeout(2000)
.process(new Processor() {
#Override
public void process(final Exchange exchange) throws Exception {
exchange.getContext().startRoute("route-source");
}
});
from("file:data/source?noop=true&idempotent=false")
.id("route-source") // the id is needed so that the route is found by the start and stop processors
.autoStartup(false) // this route is only started at runtime
.aggregate(constant(true), new MyAggregationStrategy()).completionSize(2).completionTimeout(2000)
.setHeader("recipients", constant("direct:end")) // this would be done in a separate processor
.recipientList(header("recipients"))
.to("seda:shutdown"); // shutdown asynchronously or the route would be waiting for pending exchanges
from("seda:shutdown")
.process(new Processor() {
#Override
public void process(final Exchange exchange) throws Exception {
exchange.getContext().stopRoute("route-source");
}
});
from("direct:end")
.log("End");
That way, route-source is only started when route-config is completed. route-config and consequently route-source are restarted if new files are found in the config directory.
You can also place an "on completion" http://camel.apache.org/oncompletion.html in the first route that activates the second one.
Apache camel File will create a lock for the file that being processed. Any other File process on this file will not pool on if there is a lock (except if you put consumer.exclusiveReadLock=false)
source :
http://camel.apache.org/file.html => URI Options => consumer.exclusiveReadLock