Apache camel - How to use activemq Selective consumer using message body - apache-camel

I want two consumer with single activemq queue and wanted to filter while consuming. Selective is best option for me (please suggest if there is other). But sender does not sending me any header parameter or any property, selective only works with header or properties, now I wanted to filter message on message body . Is there any way to use selective with message body
My two messages body are differed by test and test2
{
"test":{
"abc":"123",
"cde":"123"
}
}
{
"test2":{
"abc":"321",
"cde":"321"
}
}
I want something like selective with message body
from("jms:selective?selector=" + java.net.URLEncoder.encode(${body.test})).
to("cxf:bean:replica01");
from("jms:selective?selector=" + java.net.URLEncoder.encode(${body.test2})).
to("cxf:bean:replica02");
Please suggest if there is any way to do so.

As the selector documentation for ActiveMQ 5.x points out, you can use XPath based selectors for messages which have XML bodies. However, the bodies of your messages aren't XML so there doesn't appear to be anyway to get the functionality you're looking for.
Keep in mind that as far as the broker is concerned the body of a message is just an array of bytes whereas message headers/properties are typed which allows for the kinds of comparison operations that make selectors viable.

Related

in-Message copied in out-Message

I have this simple route in my RouteBuilder.
from("amq:MyQueue").routeId(routeId).log(LoggingLevel.DEBUG, "Log: ${in.headers} - ${in.body}")
As stated in the doc for HTTP-component:
Camel will store the HTTP response from the external server on the OUT body. All headers from the IN message will be copied to the OUT message, ...
I would like to know if this concept also applies to amq-component, routeId, and log? Is it the default behaviour, that IN always gets copied to OUT?
Thank you,
Hadi
First of all: The concept of IN and OUT messages is deprecated in Camel 3.x.
This is mentioned in the Camel 3 migration guide and also annotated on the getOut method of the Camel Exchange.
However, it is not (yet) removed, but what you can take from it: don't care about the OUT message. Use the getMessage method and don't use getIn and getOut anymore.
To answer your question:
Yes, most components behave like this
Every step in the route takes the (IN) message and processes it
The body is typically overwritten with the new processing result
The headers typically stay, new headers can be added
So while the Camel Exchange traverses the route, typically the body is continuously updated and the header list grows.
However, some components like aggregator create new messages based on an AggregationStrategy. In such cases nothing is copied automatically and you have to implement the strategy to your needs.

How do I check if a Camel message body is stream based?

The Message.getBody() method javadoc says,
Notice if the message body is stream based then....
So how do I check if the body is stream based? The check like this
Object body = exchange.getIn().getBody();
if (body instanceof InputStream) {
doesn't work for, say, files. I am writing a generic code and it should do certain things for incoming streams, and leave non-streaming objects intact, thus I am cautious to call
Object body = exchange.getIn().getBody(InputStream.class);
because I don't know what it will do with plain String or List or Integer etc.
There is no simple single check that covers 100% situations. Camel is open ended in terms of what payload format it supports and hence the message body is just a java.lang.Object. So to check if its streaming based, you need to check for streaming types such as `java.io.InputStream', but then you also have other types like files, and from 3rd party components that may have their own representation of streaming data.
Camel has built in stream caching (https://camel.apache.org/manual/latest/stream-caching.html) where it supports most streaming types and if you use that, then you can check if the body is an org.apache.camel.StreamCache instance.

Camel aggregation from two queues in Java DSL

I have two queues which having same type of objects in them. I want to aggregate them into a single queue through java DSL. Could anyone tell me if this is possible? If so, any code references?
If I understand your question correctly, it is possible to do such a thing.
If you need just to drive them into a single route (without any aggregations, enrichments, etc.) you can just proceed with this piece of code:
from('direct:queue1')
.to('direct:start');
from('direct:queue2')
.to('direct:start');
from('direct:start')
//there goes your processing
If you need to aggregate them later on, use Aggregator. Or you can use example from java-addict301's answer if it solves your case.
I believe this may be doable in Camel using the Content Enricher pattern.
Specifically, the following paradigm can be used to retrieve a message from one queue (where direct:start is) and enrich it with a message from the second queue (where direct:resource is). The combined message can then be built in your AggregationStrategy implementation class.
AggregationStrategy aggregationStrategy = ...
from("direct:start")
.enrich("direct:resource", aggregationStrategy)
.to("direct:result");
from("direct:resource")

Apache Camel - What is most Camel way to send errors and good object simultaneously from Component Endpoint?

Edit: To be specific I think I am asking for an elegant way to specify 2 endpoints, which I want to send 2 different exchanges from an input of 1 exchange.
I know Camel 'can' do this - but I only have inelegant methods involving sending an object which contains both types to a multicast() and processors on each section removing
I expect there to be potentially multiple error messages with source objects attached. I could just throw them each as exceptions, but this feels incorrect. I'm wondering what the 'correct' approach might be. I almost just want to be able to specify an error endpoint as a target for my component
Currently I have
camel.addComponent( "my", new MyComponent() )
from( some source )
... processing // Lists of input objects as body of in
... onException()
.to( "my:endpoint" )
MyComponent <-- MyEndpoint <-- MyProducer
I want to process the items in each List object that arrives at MyProducer. I process the elements and send failing items out to one endpoint, and good items out to an endpoint
I do not see a good / elegant way of achieving this. If it was single elements (i.e. not collection) I can just throw an exception and catch it in an onException stream.
But I really want to be able to take items, and separate good items and send them one way, and bad items and send them another.
In other words, I want to simultaneously send 2 different messages to 2 different endpoints from the same input from an Endpoint. (The endpoint isn't actually so important here, it is juts I am writing one, it could be any Processor).
I know I could make a decomposable object with good and bad items on it, then multicast and process each good and bad section out on different pieces, but I really would like a succinct reusable mechanism (e.g. built into a Processor or endpoint)
In Camel the stuff between the from() and the to() are an Exchange which is treated as a single message. The component should just be a factory for Endpoint instances, which either creates or sends exchanges. It shouldn't be processing the message (which is what it sounds like here) so there's not really a concept of of errors or good objects, that's for the Route and the Processors/Beans to decide.
If you want to do it all within a single exchange then you can simply have your processor add 2 lists to exchange properties and route them based on the contents.
from("direct:somesource")
.process(new Processor() {
public void process(Exchange exchange) {
// get contents,
// turn it into a list
//
List<Object> worked = new ArrayList<>();
List<Object> failed = new ArrayList<>();
for (Object o : listFromBody) {
try {
// do work
worked.add(o);
} catch (Exception e) {
failed.add(o)
}
}
exchange.getIn().setProperty("worked", worked);
exchange.getIn().setProperty("failed", failed);
}
};)
.choice()
.when(header("failed").isNotEqualTo(null)) // might be a better way to do this, I've not got the IDE open
.process(turnFailedHeaderIntoMessageBody)
.to("direct:errorQueue")
.otherwise()
.process(turnWorkedHeaderIntoMessageBody)
.to("direct:workedQueue");
However this is not a good camel pattern. It's messy and tries to treat the properties as different messages which is contrary to how camel works. From the route's perspective the exchange is an atomic unit, so if you need to break the message up, it's usual to route the contents of the Exchange to be processed as an Exchange by a different route.
I personally would split the list into separate exchanges and process them individually like this:
from("direct:somesource")
.split(body())
.to("direct:processIndividualMessage");
from("direct:direct:processIndividualMessage")
.doTry()
.process(myProcessor)
.to("direct:goodQueue")
.doCatch(Exception.class)
.to("direct:errorQueue")
.end()
It's all depends on your data model. But Camel has no limitations in this regards, you certainly achieve this. I can clarify if you have any specific question.

Passing values between processors in apache camel

In apache camel, which of those is the best way to pass values from an exchange processor to another (and why) :
storing it in the exchange headers
using the setProperty method while building the route.
another way..
One distinction not mentioned by Ben and Petter is that properties are safely stored for the entire duration of the processing of the message in Camel. In contrast, headers are part of the message protocol, and may not be propagated during routing. For example, JMS has limitations what you can store as headers etc.
You may want to read the free chapter 1 of the Camel in Action book as it covers the Camel concepts with Exchange, Message, etc.
Properties and headers are pretty much the same. Headers are, however, converted to/from protocol specific headers on certain components, such as Jms. So,
Meta data inside a route: properties
Meta data to/from outside: headers
the Exchange is passed between Processors. It contains properties, IN message and optional OUT message. Each of these is capable of storing Object data, but in general:
use the Exchange Properties for general meta-data about the message (used less frequently)
use the IN message headers to configure endpoint properties or for meta-data about the message body (used often)
use the IN message body for the payload of the message (used most often)
create an OUT message only if necessary to maintain separate IN vs. OUT messages during processing (by default only IN is used)
That said, it really depends on the component called following your processor. Most have some headers and/or body values that are required to use the endpoint, etc. See the specific component page for these details.
Also, the Exchange/Message are explained in more detail on these pages:
http://camel.apache.org/maven/current/camel-core/apidocs/org/apache/camel/Exchange.html
http://fusesource.com/docs/router/2.8/prog_guide/MsgFormats-Exchanges.html
Answer is here:
Properties: The properties is a Map and may look like message
headers. The main difference is their lifetime: the properties exist during the whole
exchange execution, whereas the headers are limited to the message duration (and a
message can change a lot during routing, so during the exchange execution). Camel
itself may add some properties for some use cases.

Resources