Camel 2.12 routing with RabbitMQ - java

I've been attempting to get camel to route using the RabbitMQComponent releases in the 2.12.1-SNAPSHOT. In doing so, I've been able to consume easily, but have ad issues when routing to another queues.
CamelContext context = new DefaultCamelContext();
context.addComponent("rabbit-mq", factoryComponent());
from("rabbit-mq://localhost/test.exchange&queue=test.queue&username=guest&password=guest&autoDelete=false&durable=true")
.log("${in.body}")
.to("rabbit-mq://localhost/out.queue&routingKey=out.queue&durable=true&autoAck=false&autoDelete=false&username=guest&password=guest")
.end();
In this, I've verified that there the specified exchanges are configured with the appropriate routing keys. I've noted that I'm able to consume in volume, but not able to produce to the out.queue.
The following are the only reference to the RabbitMQProducer that would process the message.
09:10:28,119 DEBUG RabbitMQProducer[main]: - Starting producer: Producer[rabbit-mq://localhost/out.queue?autoAck=false&autoDelete=false&durable=true&password=xxxxxx&routingKey=out.queue&username=guest]
09:10:48,238 DEBUG RabbitMQProducer[Camel (camel-1) thread #11 - ShutdownTask]: - Stopping producer: Producer[rabbit-mq://localhost/out.queue?autoAck=false&autoDelete=false&durable=true&password=xxxxxx&routingKey=out.queue&username=guest]
I've spent time looking into the Camel unit tests for the RabbitMQ component, but I've seen nothing of extremely valuable use. Has anyone been able to get this to work?
Thanks.

i did it using spring dsl. Here's the url that I used. Isn't port number necessary in java dsl ?
rabbitmq://localhost:5672/subscribeExchange?queue=subscribeQueue&durable=true&username=guest&password=guest&routingKey=subscribe

As per http://camel.apache.org/rabbitmq.html the port is optional.
Best

I came across the same issue even though I'm trying after 5 years since the original question was asked. But posting here how I got it working incase anyone else face the same issue.
The problem is, rabbitmq routing key doesn't gets changed even though we add the 'routingKey' to the URI. The trick was to add a header before sending out. If you log the message receive and message which is being sent out we can clearly see the routing key is the same.
Below is my code. It will read the message from 'receiveQueue' and send to 'sendQueue'
#Value("${rabbit.mq.host}")
private String host;
#Value("${rabbit.mq.port}")
private int port;
#Value("${rabbit.mq.exchange}")
private String exchange;
#Value("${rabbit.mq.receive.queue}")
private String receiveQueue;
#Value("${rabbit.mq.send.queue}")
private String sendQueue;
public void configure() throws Exception {
String uriPattern = "rabbitmq://{0}:{1}/{2}?queue={3}&declare=false";
String fromUri = MessageFormat.format(uriPattern, host, port, exchange, receiveQueue);
String toUri = MessageFormat.format(uriPattern, host, port, exchange, sendQueue);
from(fromUri).to("log:Incoming?showAll=true&multiline=true").
unmarshal().json(JsonLibrary.Gson, Message.class).bean(MessageReceiver.class).to("direct:out");
from("direct:out").marshal().json(JsonLibrary.Gson).setHeader("rabbitmq.ROUTING_KEY",
constant(sendQueue)).to(toUri);
}

Related

Increase heartbeat value in spring rabbit

I'm facing some problems with my setup and I'm trying to increase the heartbeat interval in order to test a possible fix.
I'm using
Spring boot 1.3.2.RELEASE
Spring rabbit 1.5.3.RELEASE
And the code instantiating the connection factory is the below
RabbitConnectionFactoryBean connectionFactoryBean = new RabbitConnectionFactoryBean();
connectionFactoryBean.setUseSSL(useSsl);
connectionFactoryBean.setHost(rabbitHostname);
connectionFactoryBean.setVirtualHost(rabbitVhost);
connectionFactoryBean.setUsername(rabbitUsername);
connectionFactoryBean.setPassword(rabbitPassword);
connectionFactoryBean.setConnectionTimeout(900000);
connectionFactoryBean.setRequestedHeartbeat(900);
connectionFactoryBean.afterPropertiesSet();
CachingConnectionFactory cf = new CachingConnectionFactory(connectionFactoryBean.getObject());
cf.setChannelCacheSize(40);
return cf;
The problem is that the heartbeat interval is not changing. I quick look in AMQConnection reveals the below
int heartbeat = negotiatedMaxValue(this.requestedHeartbeat,
connTune.getHeartbeat());
private static int negotiatedMaxValue(int clientValue, int serverValue) {
return (clientValue == 0 || serverValue == 0) ?
Math.max(clientValue, serverValue) :
Math.min(clientValue, serverValue);
}
The value coming from the server is 60. The method negotiatedMaxValue will not respect the client's preferences (cannot disable heartbeat nor increase it). Am I missing something?
You are correct. The AMQConnection will determine the heartbeat value based on that method and then sends that value with the TuneOk method to the server (https://www.rabbitmq.com/amqp-0-9-1-reference.html#connection.tune-ok). You can see it sends the result of the negotiatedMaxValue() a few lines down from where you see the call to the method:
_channel0.transmit(new AMQP.Connection.TuneOk.Builder()
.channelMax(channelMax)
.frameMax(frameMax)
.heartbeat(heartbeat)
.build());
It seems based on the logic of the code that you can only reduce the heartbeat but the maximum heartbeat will be whatever the server sends and can't be increased more than that. RabbitMQ documentation is a little vague on the specifics of being able to increase the heartbeat that the server initially sends but does say it can be overwritten: https://www.rabbitmq.com/heartbeats.html
I checked in the latest version of spring rabbit and it still has the same configuration so doesn't look like it is changing anytime soon.
Checking the RabbitMQ GitHub doesn't show any existing issues around setting the heartbeat value greater than the server's sent value. Maybe submit an issue there and see what the developers say? https://github.com/rabbitmq/rabbitmq-java-client/issues?utf8=%E2%9C%93&q=heartbeat

javax.jms.IllegalStateException: The Session is closed

I have different problems with a Camel Producer that I tried to solved but I've fallen into other problems.
1) The first implementation I did was to create a producer template each time we needed to communicate with an ActiveMQ topic. That resulted with poor memory results leading to server crashing after sometime.
The solution for the memory problem was to stop() producer template after each request. That fix has corrected the memory issue but cause some latency problem.
2) I read somewhere that it's not necessary to create each time a producer template. So I decide to fix the latency problem and declared only one producer template in my class and use it for each request. It seem to work fine, no memory leak, fix the latency problem...
BUT, when we send multiple queries that take a lot of time (20 sec each), it looks like we hit a timeout and the component crash with something like «javax.jms.IllegalStateException: The Session is closed».
Is there a way to do multi threading? Is this cause by using InOut exchange pattern? How the MAXIMUM_CACHE_POOL_SIZE works? Is my implementation is right?
I've put a sample of the code of my component:
public void process(Exchange exchange) throws Exception
{
Message in = exchange.getIn();
if (producerTemplate == null) {
CamelContext camelContext = exchange.getContext();
//camelContext.getProperties().put(Exchange.MAXIMUM_CACHE_POOL_SIZE, "50");
producerTemplate = camelContext.createProducerTemplate();
}
...
result = producerTemplate.sendBody(String.format("activemq:%s", camelContext.resolvePropertyPlaceholders("{{channel1}}")), ExchangePattern.InOut, messageToSend).toString();
...
finalResult = producerTemplate.sendBody(String.format("activemq:%s", camelContext.resolvePropertyPlaceholders("{{channel2}}")), ExchangePattern.InOut, result).toString();
...
in.setBody(finalResult );
}
Yes it is because you use InOut pattern.
Your route expects a response to the specified reply queue, which is never received, and therefore results in the default 20 sec. timeout.
Change the Exchange pattern to InOnly to resolve your issue.
Apart from that, your posted code seems to be fine.
The MAXIMUM_CACHE_POOL_SIZE is used internally in Camel, and thus does not effect the ActiveMQ endpoint settings.

Apache camel,RabbitMQ how to send messages/objects

I hope someone can provide some help on this matter.
I am using camel rabbitmq and for testing purpose I am trying to send a message to the queue, which I'm trying to display in rabbitmq interface and then also read it back.
However I can't get this working.
What I believe works is that I created, in the exchange tab of rabbitmq management interface, a new exchange.
In my java code I send the message to that exchange. When the code is executed, I can see a spike in the web interface showing that something has been received but I can't see what has been received.
When I try to read, I can't read and get the following errror:
< in route: Route(route2)[[From[rabbitmq://192.168.59.103:5672/rt... because of Route route2 has no output processors. You need to add outputs to the route such as to("log:foo").
Can someone provide me a practical example on how to send a message,see it in the web interace and also read it? any tutorial showing this process will be also appreciated.
Thank you
=================
SECOND PART
The error I'm getting now is the following:
Caused by: com.rabbitmq.client.ShutdownSignalException: channel error; reason: {#method<channel.close>(reply-code=406, reply-text=PRECONDITION_FAILED - cannot redeclare exchange 'rhSearchExchange' in vhost '/' with different type, durable, internal or autodelete value, class-id=40, method-id=10), null, ""}
at com.rabbitmq.utility.ValueOrException.getValue(ValueOrException.java:67)
at com.rabbitmq.utility.BlockingValueOrException.uninterruptibleGetValue(BlockingValueOrException.java:33)
at com.rabbitmq.client.impl.AMQChannel$BlockingRpcContinuation.getReply(AMQChannel.java:343)
at com.rabbitmq.client.impl.AMQChannel.privateRpc(AMQChannel.java:216)
at com.rabbitmq.client.impl.AMQChannel.exnWrappingRpc(AMQChannel.java:118)
... 47 more
I have the following settings:
I get this error, I believe I’m doing something wrong with the URI and I have to define some extra parameters that I’m missing
My exchange is of direct type
My queue is of durable type
And my uri is :
rabbitmq://192.168.59.105:5672/rhSearchExchange?username=guest&password=guest&routingKey=rhSearchQueue
any input on this?
Thanks
So I was able to figure this out yesterday, I had the same (or at least similar) problems you were having.
The options you have in the RabbitMQ URI must exactly match the options that your exchange was created with. For example, in my configuration, I had an exchange called tasks that was a direct type, was durable, and was not configured to autodelete. Note that the default value for the autodelete option in the rabbitmq camel component is true. Additionally, I wanted to get the messages with the routing key camel. That means my rabbitmq URI needed to look like:
rabbitmq:localhost:5672/tasks?username=guest&password=guest&autoDelete=false&routingKey=camel
Additionally, I wanted to read from an existing queue, called task_queue rather than have the rabbitmq camel component declare it's own queue. Therefore, I also needed to add an additional query parameter, so my rabbitmq URI was
rabbitmq:localhost:5672/tasks?username=guest&password=guest&autoDelete=false&routingKey=camel&queue=task_queue
This configuration worked for me. Below, I added some Java code snippets from the code that configures the exchange and queue and sends a message, and my Camel Route configuration.
Exchange and Queue configuration:
rabbitConnFactory = new ConnectionFactory();
rabbitConnFactory.setHost("localhost");
final Connection conn = rabbitConnFactory.newConnection();
final Channel channel = conn.createChannel();
// declare a direct, durable, non autodelete exchange named 'tasks'
channel.exchangeDeclare("tasks", "direct", true);
// declare a durable, non exclusive, non autodelete queue named 'task_queue'
channel.queueDeclare("task_queue", true, false, false, null);
// bind 'task_queue' to the 'tasks' exchange with the routing key 'camel'
channel.queueBind("task_queue", "tasks", "camel");
Sending a message:
channel.basicPublish("tasks", "camel", MessageProperties.PERSISTENT_TEXT_PLAIN, "hello, world!".getBytes());
Camel Route:
#Override
public void configure() throws Exception {
from("rabbitmq:localhost:5672/tasks?username=guest&password=guest&autoDelete=false&routingKey=camel&queue=task_queue")
.to("mock:result");
}
I hope this helps!
Because this it the top hit on Google for rabbitmq/camel integration I feel the need to add a bit more to the subject. The lack of simple camel examples is astonishing to me.
import org.apache.camel.CamelContext;
import org.apache.camel.ConsumerTemplate;
import org.apache.camel.Endpoint;
import org.apache.camel.Exchange;
import org.apache.camel.ProducerTemplate;
import org.apache.camel.impl.DefaultCamelContext;
import org.junit.Test;
public class CamelTests {
CamelContext context;
ProducerTemplate producer;
ConsumerTemplate consumer;
Endpoint endpoint;
#Test
public void camelRabbitMq() throws Exception {
context = new DefaultCamelContext();
context.start();
endpoint = context.getEndpoint("rabbitmq://192.168.56.11:5672/tasks?username=benchmark&password=benchmark&autoDelete=false&routingKey=camel&queue=task_queue");
producer = context.createProducerTemplate();
producer.setDefaultEndpoint(endpoint);
producer.sendBody("one");
producer.sendBody("two");
producer.sendBody("three");
producer.sendBody("four");
producer.sendBody("done");
consumer = context.createConsumerTemplate();
String body = null;
while (!"done".equals(body)) {
Exchange receive = consumer.receive(endpoint);
body = receive.getIn().getBody(String.class);
System.out.println(body);
}
context.stop();
}
}

how to delay JMS message in spring on weblogic 10.3 server

I want to delay message delivery by certain time which will be different for each message.
I referred weblogic 10.3 WLMessage documentation which recommends using javax.jms.Message.getIntProperty("JMS_BEA_DeliveryTime").
However I'm unable to figure out how do I set JMS_BEA_DeliveryTime as INTEGER. I was expecting it to be long.
I'm unable to find out any documentation about this attribute JMS_BEA_DeliveryTime to undesratand how to set and use it. Can anybody give example about how to set the desired delivery time or link to documenation of use of this attribute.
My code looks like typical use of Spring JMS template:
jmsTemplate.send(destination, new MessageCreator() {
public Message createMessage(Session session) throws JMSException {
TextMessage message = session.createTextMessage(textMessage);
return message;
}
});
I was wondering if it is possible to set header for delivery time before returning message.
Good article with examples of delaying delivery for different JMS providers, include WL.
Well there is this page which states
JMS Delivery Time: The earliest absolute time at which
a message can be delivered to a consumer.
It should be trivial to set with Message.setIntProperty(...), there is not much mention as to what the time actually constitutes though, although I did find this article which suggests milliseconds from now.
Hope that helps.

FIX protocol using java

I have developed a utility in Java using the Financial Information eXchange(FIX) protocol to pull data from an input stream. However, I currently have not found any test servers online to which I can connect to that implement the FIX protocol. Could someone please let me know how I can achieve this?
http://www.quickfixj.org/ have an open source fix engine. It comes with an example that has a simple server. You might want to use their library for the client too rather than rebuilding a FIX engine from scratch...
You can use CoralFIX to quickly fire up a test server. It takes care of all the session level FIX messages, such as Logon, ResendRequest, SequenceReset, Heartbeat so you are ready to start exchanging messages with your client. Below a simple example:
import com.coralblocks.coralfix.FixMessage;
import com.coralblocks.coralreactor.client.Client;
import com.coralblocks.coralreactor.nio.NioReactor;
import com.coralblocks.coralreactor.util.Configuration;
import com.coralblocks.coralreactor.util.MapConfiguration;
public class SimpleFixApplicationServer extends FixApplicationServer {
public SimpleFixApplicationServer(NioReactor nio, int port, Configuration config) {
super(nio, port, config);
}
#Override
protected void handleFixApplicationMessage(Client client, FixMessage fixMsg, boolean possDupe) {
// do whatever you want to do with the application message received from this client...
}
public static void main(String[] args) {
NioReactor nio = NioReactor.create();
MapConfiguration config = new MapConfiguration();
// print all messages received and sent to STDOUT for debugging purposes
// (default is false)
config.add("debugMessages", "true");
// accept as the client inbound sequence whatever
// sequence I receive in the first message coming from the client
// (default is false)
config.add("acceptInboundSeqFromClient", "false");
Server server = new SimpleFixApplicationServer(nio, 45451, config);
server.open();
nio.start();
}
}
A full explanation of the code above can be found here.
Disclaimer: I am one of the developers of CoralFIX.
I assume you haven't built it in a vacuum, but rather to talk to some broker's FIX server? If that's the case, speak to your broker as they are likely to have a test server you could connect to.
It depends if you want a hosted or a DIY solution. If you want to quickly bring up a FIX sessions without having to compile/build/setup then I would go for a hosted simulator.
We have an account with these guys http://www.fixsim.com/ and would recommend them (simple to setup and add more connections).
(I don't work for the company and get nothing to say this)
you can try to search more information here: http://fixprotocol.org/discuss/
I work for a broker, and you're more than welcome to connect to our Staging FIX servers. I do not know of any anonymous servers around, perhaps this is something the FIX community could set up..
Cheers,
Chris

Categories

Resources