Get Camel route information from Endpoint - apache-camel

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.

Related

Use string as Apache Camel endpoint?

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();

Resume Activiti task from Camel ActiveMQ route

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

Reload a Property from a Camel Route without stopping it

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.

Apache Camel - How to set global component options

I'm using Camel with Spring Boot. I want to set "connectionTimeToLive" option for http component at global scope so that every use of the component will have the option. How can I do that?
After reading Camel test cases, I found out this solution using Custom Camel context configuration:
#Bean
CamelContextConfiguration contextConfiguration() {
return new CamelContextConfiguration() {
#Override
public void beforeApplicationStart(CamelContext context) {
HttpComponent http = context.getComponent("http4", HttpComponent.class);
http.setConnectionTimeToLive(5000);
}
#Override
public void afterApplicationStart(CamelContext camelContext) {
}
};
}
You have several options.
Add it to the camel registry and fetch it from there.
Add it as a Camel Exchange property.
Fetch it from a property file.
The way Camel works, you will have to configure this value in a property placeholder.
Also you can define endpoints in camel, instead of defining them straight away in the routes. (Eg: <endpoint id="bla" uri="foo" .. />). This way you can refer them in multiple places.
Also if you want to use this endpoint for multiple hosts, then consider passing things like host name, etc as a header. Eg: Exchange.HTTP_PATH
I am not sure whether Camel has any other Global config approach.
Cheers.

Why Don't DomainService Constructor Overloads Show Up as DomainContext Constructor Overloads?

I wrote an overload for my DomainService class. Problem is, when I recompile, it's not showing up as an overload for my DomainContext. What's wrong? Here is a code sample:
[EnableClientAccess]
public class FoodDomainService : LinqToEntitiesDomainService<FoodEntities>
{
public FoodDomainService(CultureInfo cultureInfo)
{
Thread.CurrentThread.CurrentCulture = cultureInfo;
}
}
And this doesn't work:
FoodDomainContext _foodContext = new FoodDomainContext(Thread.CurrentThread.CurrentCulture);
I get an error that there is no overload matching that. Am I not allowed to do this? Do I need an attribute of some kind?
You are not allowed to do this. When newing up the context from your Silverlight client, you are not directly intantiating your service. Instead, you instantiate a proxy class that was generated by RIA Services, and that proxy class will then call your service. This is why you don't see your constructor: because RIA did not generate it in your proxy.
Doing what you're trying to do would also implicate that there is a round-trip to the server at the time of newing up that FoodDomainContext class, which is not going to happen, because you need to complete the initialisation of that object before you can do so.
Anyway, instead of that you can create a method called SetCurrentCulture() and then call it after initializing the proxy.
This will not work because DomainContext is generated on client code of silverlight, click on view all folders or jump to definition and you will see that code generated will not contain your extra constructor.
Instead you will have to create a method in your domain service and pass information to server.
public SetCultreInfo(int lang,...)
{
.. set culture info
}
On your client, inside constructor you should call,
public MyDomainContext()
{
this.SetCulture(....);
}

Resources