authenticated queue create/access with a name pattern with activemq - activemq

Hi i want configure a activemq to secure queue access and creation.
client.<client-id>.sub
client.<client-id>.pub
And late create a Camel redirect to a unique queue adding client-id headers on message redirected
Any suggestion?
PS Please forget my english

The way you handle authorization to ActiveMQ queues and topics is by the authorizationPlugin on a prefix and user level.
<authorizationPlugin>
<map>
<authorizationMap>
<authorizationEntries>
<authorizationEntry queue="client.client123.>" read="client123" write="client123" admin="admins" />
<authorizationEntry topic="client.client123.>" read="client123" write="client123" admin="admins"/>
... etc. for other clients.
</authorizationEntries>
This assumes client123 is authenticated, by any authentication mechanism.
I don't follow how you want Camel to deal with the routing, but something like this is probably what you want to route from multiple client queues to one single queue with headers (just an example, you prob. have to modify it to fit your case a bit, with error handling and such.
Note the use of > for wild card queues.
from("jms:queue:client.>")
.process(new Processor(){
#Override
public void process(Exchange exchange) throws Exception {
String queue = exchange.getIn().getHeader("JMSDestination").toString();
// queue name is: queue://client.<client_id>.xx
String clientId = queue.substring(queue.indexOf(".")+1);
int idx = clientId.lastIndexOf(".");
clientId = clientId.substring(0,idx);
System.out.println("ClientID: " + clientId);
exchange.getIn().setHeader("SendingClientId", clientId);
}
})
.to("jms:queue:collector.queue");

Related

Consume DirectExchange messages using routing key and exchange in spring boot

Am trying to consume the message from exiting queue which is of type Direct Exchange(created with the help of exchange and routing key). I have only the exchange name and routing key and not the queue name. There were support for plain Java, but there was no place where I can find it for Spring boot.
#RabbitListener
#RabbitHandler
public void consumeMessage(Object message) {
LOGGER.debug("Message Consumed.... : {}", message.toString());
}
How can I consume messages with routing key and exchange name not the queue name as #RabbitListener asks for queue.
Consumers consume from queues not exchanges. You must bind a queue to the exchange with the routing key.
EDIT
There are several ways to automatically declare a queue on the broker.
#RabbitListener(bindings =
#QueueBinding(exchange = #Exchange("myExchange"),
key = "myRk", value = #Queue("")))
public void listen(String in) {
System.out.println(in);
}
This will bind an anonymous queue (auto-delete) which will be deleted when the application is stopped.
#RabbitListener(bindings =
#QueueBinding(exchange = #Exchange("myExchange"),
key = "myRk", value = #Queue("foo")))
public void listen(String in) {
System.out.println(in);
}
Will bind a permanent queue foo to the exchange with the routing key.
You can also simply declare #Bean s for the queue, exchange and binding.
See Configuring the broker.

sending acknowledgement from consumer to producer and handle it in activemq and rabbitmq

As I know ActiveMQ has a feature called AUTO Acknowledge that actually inform the broker that message has been received (not acknowledging the producer).
I want to know if it is possible to send acknowledgement from consumer to producer in ActiveMQ or RabbitMQ. then I want to handle the acknowledgment message in producer and if it wouldn't receive acknowledge then sending the message again to the consumer.
You want to perform a synchronous usecase over an asynchronous medium.
In RabbitMQ's case you can use RPC, as described here - https://www.rabbitmq.com/tutorials/tutorial-six-python.html
and
https://www.rabbitmq.com/direct-reply-to.html
Please notice that even authors advise to avoid it:
When in doubt avoid RPC. If you can, you should use an asynchronous pipeline - instead of RPC-like blocking, results are asynchronously pushed to a next computation stage.
RabbitMQ Java client provides auto-acking through com.rabbitmq.client.Channel.basicConsume.
At least for ActiveMQ - this is built in. You have to turn it on in activemq.xml
<policyEntry queue=">" advisoryForConsumed="true"/>
Simply listen the advisory topic for the queue you want to monitor consumed messages for. Then you can extract message id:s and what not to "tick off" outstanding requests.
For a complete end-to-end acknowledgement, I recommend something more custom. I.e. your producer-app should listen to some "response" queue that receives responses about the status of the produced message. I.e. if processing failed - you may want to know why etc..
Anyway, here is some code with a producer that also listens to acknowledgements from ActiveMQ.
public void run() throws Exception {
ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory("tcp://localhost:61616");
conn = cf.createConnection();
sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
Destination dest = sess.createQueue("duck");
MessageConsumer mc = sess.createConsumer(AdvisorySupport.getMessageConsumedAdvisoryTopic(dest));
mc.setMessageListener(this);
conn.start();
MessageProducer mp = sess.createProducer(sess.createQueue("duck"));
mp.send(sess.createTextMessage("quack"));
}
public void onMessage(Message msg) {
try {
String msgId = msg.getStringProperty("orignalMessageId");
System.out.println("Msg: " + msgId + " consumed");
} catch ( Exception e) {
e.printStackTrace();
}
}

how to mark a message as persistent using spring-rabbitmq?

This is how I'm creating an exchange and binding a queue to it
<rabbit:topic-exchange id="dataExchange" name="MQ-EXCHANGE" durable="true">
<rabbit:bindings>
<rabbit:binding queue="COMM_QUEUE" pattern="queue.*" />
</rabbit:bindings>
</rabbit:topic-exchange>
I have read a lot of posts on the Internet where it is written that a message is also needed to be marked persistent if it is to be secured in case rabbitmq or the queue crashes. But I couldn't figure out how to mark my messages persistent.
This is how I'm publishing the messages to the queue
#Autowired
private RabbitTemplate template;
#Override
public void produceMessage(Object message, String routingKey) {
template.convertAndSend(routingKey, message);
}
I looked for different API methods to know this and also tried to look for any specific property that I could configure in the XML but couldn't find a way. Any guidance ?
The default delivery mode (in MessageProperties) is PERSISTENT. See here.
To make it non-persistent you need to use a convertAndSend(...) method with a MessagePostProcessor to set the deliveryMode property.

Java Spring RabbitMq consumer

I am trying to create a RabbitMq consumer in Java Spring framework. Where I need to implement RabbitMq RPC model, so basically consumer shall receive some message from RabbitMq broker, process it, and send it back to the associated reply queue.
Can somebody please point me a neat sample code which implements this requirement in Spring ?
Thanks in advance.
Consider using the Spring AMQP Project.
See the documentation about async consumers. You just need to implement a POJO method and use a MessageListenerAdapter (which is inserted by default when using XML configuration) - if your POJO method returns a result, the framework will automatically send the reply to the replyTo in the inbound message, which can be a simple queue name, or exchange/routingKey.
<rabbit:listener-container connection-factory="rabbitConnectionFactory">
<rabbit:listener queues="some.queue" ref="somePojo" method="handle"/>
</rabbit:listener-container>
public class SomePojo {
public String handle(String in) {
return in.toUpperCase();
}
}
Or, you can use the annotation #RabbitListener in your POJO - again, see the documentation.
Thanks Gary, it worked for me. I used #RabbitListener annotation.
Strangely it only works when I provide queue alone, However specifying a binding of exchange, routing key and queue doesn't work. Not sure what the issue here.
Here is client code snippet in python.
#!/usr/bin/env python
import pika
connection = pika.BlockingConnection(pika.ConnectionParameters(
host='localhost'))
channel = connection.channel()
channel.queue_declare(queue='myQueue',durable='true')
channel.basic_publish(exchange='myExchange',
routing_key='rpc_queue',
body='Hello World!')
print " [x] Sent 'Hello World!'"
connection.close()
Here is spring consumer code.
#RabbitListener(
bindings = #QueueBinding(
value = #Queue(value = "myQueue", durable = "true"),
exchange = #Exchange(value = "myExchange"),
key = "rpc_queue")
)
public void processOrder(Message message) {
String messageBody= new String(message.getBody());
System.out.println("Received : "+messageBody);
}
Not sure whats going wrong with this binding.

Spring Integration with AMQP: get original message's custom-headers on error-channel

Using Spring Integration with RabbitMQ in my project I face a problem.
The project consist of receiving messaging from a queue, trace the incoming message, process the message using a service-activator, and trace the response or the exception thrown by the service activator.
Here is the sample configuration:
<!-- inbound-gateway -->
<int-amqp:inbound-gateway id="inboundGateway"
request-channel="gatewayRequestChannel"
queue-names="myQueue"
connection-factory="rabbitMQConnectionFactory"
reply-channel="gatewayResponseChannel"
error-channel="gatewayErrorChannel"
error-handler="rabbitMQErrorHandler"
mapped-request-headers="traceId"
mapped-reply-headers="traceId" />
<!-- section to dispatch incoming messages to trace and execute service-activator -->
<int:publish-subscribe-channel id="gatewayRequestChannel" />
<int:bridge input-channel="gatewayRequestChannel" output-channel="traceChannel"/>
<int:bridge input-channel="gatewayRequestChannel" output-channel="serviceActivatorInputChannel"/>
<!-- the trace channel-->
<int:logging-channel-adapter id="traceChannel"
expression="headers['traceId'] + '= [Headers=' + headers + ', Payload=' + payload+']'" logger-name="my.logger" level="DEBUG" />
<!-- service activator which may throw an exception -->
<int:service-activator ref="myBean" method="myMethod" input-channel="serviceActivatorInputChannel" output-channel="serviceActivatorOutputChannel"/>
<!-- section to dispatch output-messages from service-activator to trace them and return them to the gateway -->
<int:publish-subscribe-channel id="serviceActivatorOutputChannel" />
<int:bridge input-channel="serviceActivatorOutputChannel"
output-channel="traceChannel" />
<int:bridge input-channel="serviceActivatorOutputChannel"
output-channel="gatewayResponseChannel" />
<!-- section to dispatch exceptions from service-activator to trace them and return them to the gateway -->
<int:bridge input-channel="gatewayErrorChannel"
output-channel="traceChannel" />
<int:bridge input-channel="gatewayErrorChannel"
output-channel="gatewayResponseChannel" />
I simplified the code to suit my explanation. The idea is to trace the input and output/error messages coming and outgoing to/from the service-activator. To do this, I use a message's header named traceId. This identifier is used as a correlation-identifier to be able to associate the request-message with its response (these two messages share the same traceId value).
Everything is working fine when no exception is thrown by the service-activator.
But when an exception is thrown, it seems a new message is generated by the gateway, without my original traceId header.
Looking a little bit into the gateway code, I find the following piece of code into the class org.springframework.integration.gateway.MessagingGatewaySupport :
private Object doSendAndReceive(Object object, boolean shouldConvert) {
...
if (error != null) {
if (this.errorChannel != null) {
Message<?> errorMessage = new ErrorMessage(error);
Message<?> errorFlowReply = null;
try {
errorFlowReply = this.messagingTemplate.sendAndReceive(this.errorChannel, errorMessage);
}
...
}
It seems that, when an exception occurred, a new message is created with the exception message as payload and is sent to the gateway's errorChannel. Here is where I loose my custom headers.
Is there a way to preserve my custom-headers when an exception is occurring? (maybe there is a way to configure it and I may be missing it...). Or maybe I am not implementing my flow in a right way. If this is the case, any comment or suggestion is welcome.
By the way, I am using the version 4.0.3.RELEASE of the spring-integration-core artifact.
Thanks for yours answers
Edit: as Gary Russel said, this exemple is missing the following puslish/subscribe queue configuration
<int:publish-subscribe-channel id="gatewayErrorChannel"/>
The message on the error-channel is an ErrorMessage. It has two properties: cause - the original exception and failedMessage - the message at the point of failure. The ErrorMessage does not get the failedMessage's headers.
You can't just send the ErrorMessage back to the gateway without some extra work.
Typically, error flows will perform some analysis of the error before returning a response.
If you want to restore some custom header, you will need a header enricher on the error flow.
Something like
<int:header-enricher ...>
<int:header name="traceId" expression="payload.failedMessage.headers.traceId" />
</int:header-enricher>
In addition, your configuration is a little odd in that you have 2 subscribers on gatewayErrorChannel. Unless it is a <publish-subscribe-channel/>, these consumers will get alternate messages; it seems like you expect them both to get it so you need to declare the channel properly.