I'm trying to figure out a way to update dynamically a property (from a PropertyComponent) without stopping the Camel Route:
Here's an example of it:
#Override
public void configure() throws Exception {
CamelContext ctx = super.getContext();
PropertiesComponent pc = new PropertiesComponent();
pc.setLocation("/tmp/apache-deltaspike.properties");
ctx.addComponent("properties", pc);
// Logs Hello World every 2000 milliseconds
from("timer://myEapTimer?fixedRate=true&period=2000")
.log(LoggingLevel.INFO, "com.sample.route", "{{customProperty}}")
.to("log:HelloWorldLog?level=INFO");
}
The external Property file contains the message to be printed every time the Timer fires. I'd need to find a way to let the Route reload the Property file without stopping it.
BTW I'm using Apache Camel 2.17.0.
Thanks
That is not possible, the {{xxx}} is resolved only once when the route is starting up.
You can use a Java bean where you can load the properties file yourself and get the value and do the logging there.
Or you can call the Java bean with bean parameter binding and have the properties value injected. But you then also need to configure the properties component to not use caching etc.
Related
Requisite disclaimer about being new to Camel--and, frankly, new to developing generally. I'd like to have a string generated as the output of some function be the source of my camel route which then gets written to some file. It's the first part that seems challenging: I have a string, how do I turn it into a message? I can't write it into a file nor can I use JMS. I feel like it should be easy and obvious, but I'm having a hard time finding a simple guide to help.
Some pseudo-code using the Java DSL:
def DesiredString() {return "MyString";}
// A camel route to be implemented elsewhere; I want something like:
class MyRoute() extends RouteBuilder {
source(DesiredString())
.to("file://C:/out/?fileName=MyFileFromString.txt");
}
I vaguely understand using the bean component, but I'm not sure that solves the problem: I can execute my method that generates the string, but how do I turn that into a message? The "vague" is doing a lot of work there: I could be missing something there.
Thanks!
Not sure if I understand your problem. There is a bit of confusion about what the String should be become: the route source or the message body.
However, I guess that you want to write the String returned by your method into a File through a Camel route.
If this is correct, I have to clarify first the route source. A Camel Route normally starts with
from(component:address)
So if you want to receive requests from remote via HTTP it could be
from("http4:localhost:8080")
This creates an HTTP server that listens on port 8080 for messages.
In your case I don't know if the method that returns the String is in the same application as the Camel route. If it is, you can use the Direct component for "method-like" calls in the same process.
from(direct:input)
.to("file:...");
input is a name you can freely choose. You can then route messages to this route from another Camel route or with a ProducerTemplate
ProducerTemplate template = camelContext.createProducerTemplate();
template.sendBody("direct:input", "This is my string");
The sendBody method takes the endpoint where to send the message and the message body. But there are much more variants of sendBody with different signatures depending on what you want to send it (headers etc).
If you want to dive into Camel get a copy of Camel in Action 2nd edition. It contains everything you need to know about Camel.
Example:Sending String(as a body content)to store in file using camel Java DSL:
CamelContext context = new DefaultCamelContext();
context.addRoutes(new RouteBuilder() {
public void configure() {
from("timer:StringSentToFile?period=2000")
.setBody(simple(DesiredString()))
.to("file:file://C:/out/?fileName=MyFileFromString.txt&noop=true")
.log("completed route");
}
});
ProducerTemplate template = context.createProducerTemplate();
context.start();
I'm trying to send a message from an Activiti Camel task to an ActiveMQ queue, which should resume the activity when it is received by Camel. As I understand it, when the message is received from the queue lacks the properties that would enable it to be identified by Camel in order to be routed to the correct activity task.
As such a Business key is Null Exception is raised and the route fails.
from("activiti:SampleProcess:myCamelTask")
.to("activemq:queue:myQueue");
As expected, if I hardcode either the PROCESS_ID_PROPERTY or the PROCESS_KEY_PROPERTY in the receiving route, the message is routed correctly (when the ID matches).
from("activemq:queue:myQueue")
.setBody(constant("test body"))
.setProperty(PROCESS_ID_PROPERTY, constant("50"))
// .setProperty(PROCESS_KEY_PROPERTY, constant("CUSTOM-KEY"))
.to("activiti:SampleProcess:receiveAsyncPing");
How can I get either property in the receiving route so I can set them accordingly?
Or is there a more recommended way to approach this?
A good question.
The way I handled this is to inject the PROCESS_KEY within the route using the setProperty() command:
See below where I set the process key (business key) to "bar":
from(startProcessEndpoint)
.log(LoggingLevel.INFO, logMsg3)
.setProperty("PROCESS_KEY_PROPERTY",foo)
.setBody(constant("bar"))
.to("activiti:testCamelTask:receive")
Now, if you dont want to use a constant, then you have access to the exchange object within the route and can use an Expression as shown below:
Expression foo = new Expression() {
#Override
public <T> T evaluate(Exchange exchange, Class<T> aClass) {
return (T) "foo";
}
};
Hope this helps,
Greg
I build camel application using org.apache.camel.main.Main class like this:
public static void main(String... args) throws Exception {
Main main = new Main();
main.enableHangupSupport();
main.addRouteBuilder(new MainRoute());
main.addRouteBuilder(ConfigurationRoute.getloginRoute());
main.run(args);
}
how to include properties file (src/main/resources/prop.properties) in the code?
Do you mean to configure the Camel properties component for properties placeholders?
http://camel.apache.org/using-propertyplaceholder.html
We could probably make this easier to configure on the Main class so you can configure it to one or more properties files.
I have logged a ticket to make this easier: https://issues.apache.org/jira/browse/CAMEL-10255
What you need to do is to
PropertiesComponent pc = new PropertiesComponent();
pc.setLocation("prop.properties");
main.bind("properties, pr);
Where you create the component and configure it. And then bind it with the id properties.
The location is automatic loaded from the classpath, so you do not need src/main/resources as prefix.
For example:
from("direct:test")
.multicast()
.to("direct:req1","direct:req2");
from("direct:req1")
.to(cxf:bean:endpoint1)
.process("response1");
from("direct:req2")
.process("requestProcessor2")
.to(cxf:bean:endpoint2)
.process(response2);
I am new to apache camel, i just wanna know is there any way to use the response which i get from the endpoint1 in "requestProcessor2" .
You could do something like this
from("direct:test")
.setProperty("test.body", body())
.to(cxf:bean:endpoint1)
.setProperty("endpoint1.body", body())
.process("response1")
.setBody(exchangeProperty("test.body"))
.to("direct:req2")
from("direct:req2")
.process("requestProcessor2")
.to(cxf:bean:endpoint2)
.process(response2);
You save the original body in an property and also the body from endpoint1. You then send the exchange to direct:req2 with the original body in the exhcnage body and the body form endpoint1 in a property which you then can access (in you processor or else where).
To access the the property in your processor:
public void process(final Exchange exchange) throws Exception {
Object body = exchange.getProperty("endpoint1.body");
}
You question already has the answer , use and you can get the property from the exchange whichever route you want. Also consider removing the property at the final route.
I am creating a JMS route programatically by following code :
from("jms:queue:OUTBOUND_QUEUE?concurrentConsumers=5&messageListenerContainerFactoryRef=msgListenerContainerFactory").processRef("mqprocessor");
I have class :
public class MessageListenerContainerFactoryImpl implements MessageListenerContainerFactory {
#Override
public AbstractMessageListenerContainer createMessageListenerContainer(
JmsEndpoint endpoint) {
}
}
I want to exchange some information/parameter between the above route and endpoint. And based on the parameter value I want choose the connection factory to be set in this message listener container.
Please let me know if I was able to explain my problem statement.
Is there any other way to achieve this? I want build connectionfactory at runtime and so do route.
Is there any method in JmsEndpoint which I can leverage to know route-id?
I would create such a route in a method, supply the MLC as a parameter, then when needed, remove that route gracefully and recreate it with new parameters. Changing the parameters does not really make much sense.