I have an application with two queues, the first queue has control messages and the other has data messages. Based on the JMSCorrelationID of the message from the control queue i need to read only messages with that JMSCorrelationID from the data queue.
I am able to selectively read messages from the data queue using a selector defined as below.
<int-jms:message-driven-channel-adapter id="messageDrivenInboundAdapter"
channel="inboundChannel" destination-name="inboundMQ"
selector="JMSCorrelationID = 'JMSCORELIS1234'"
connection-factory="connectionFactory" extract-payload="false"/>
I need to dynamically update value for the JMSCorrelationID for the selector based on messages received on a different channel.
Is it possible to do that? Is there a different way to implement this solution in spring integration?
It's not possible with the message-driven adapter; the selector is baked into the message listener container constructed during initialization.
You can change the message selector of a polled <inbound-channel-adapter/>; the change will take effect on the next poll.
You can get a handle to the JmsDestinationPollingSource with auto wiring, or via the bean name (adapterId.source).
Related
Following on from this question Messages DO NOT appear in the Spring Integration (Kafka) ErrorChannel when Broker is unavailable
I now have it working nicely and the spring integration Kafka default ErrorChannel is being called when there is an error state, with the associated ErrorMessage. My problem now, is that I need to determine the Topic of the message and there is no way to do this, other than including it in the Message Header.
What is the best approach for doing this - shall I create a special errorChannel that is associated with one and only one Topic?
The payload.failedMessage property of the error message is the original message that arrived at the adapter.
You could use a <header-enricher /> upstream of the adapter, to set header kafka_topic to the topic. That is the default mechanism used if no topic or topic-expression is configured on the adapter.
I'm working with a Camel application that is taking messages from one JMS queue and writing them to another JMS queue.
The output messages are JMS TextMessages which are not quite preferred for this particular JMS broker. I've determined for this product, and for the downstream (non-JMS) consumers, we'd like Camel to produce javax.jms.BytesMessages, but populate their data as a string via Message.writeUTF(String).
I have found that the Spring JMSConfiguration does allow me to set a property jmsMessageType="Bytes" which gets me halfway there, but is there any other configuration to make it write my String payload via writeUTF? Currently it appears to be encoding the string down to a byte array then setting it via BytesMessage.writeBytes(byte[]).
See the documentation how to use a custom message converter
http://camel.apache.org/jms
Then you can do the mapping to JMS Message yourself and use the writeUTF method
I have a rabbitmq listener as a separate class and JSF 2 managed bean.
In my bean I send a message and need to wait for result. I can't use sendAndReceive... because I send the message to one queue but receive from another queue, so I assign correlationId before sending.
So I need to wait asynchronously, I need to wait until right message comes to the listener. How to do it in rmq?
Looking at javadoc and source of RabbitTemplate it seems that he waits for response in reply queue. Do you set 'reply-to' property in your messages? If yes, then RabbitTemplate sendAndReceive methods should wait for response in 'reply-to' queue. Be sure to populate replyTo field correctly and test it.
Side note:
In RabbitMQ you do not send messages to the queue.
You send messages to the exchanges. Exchanges are routing messages to the queue(s) using bindings. With default or direct exchange type it looks like you send directly to the queue, but this is over-simplification.
See https://www.rabbitmq.com/tutorials/amqp-concepts.html for details.
Edit:
It seems there are some fix for that in AMQP 1.4.5.RELEASE
https://spring.io/blog/2015/05/08/spring-amqp-1-4-5-release-and-1-5-0-m1-available
Configurable Exchange/Routing Key for Replies
Previously, when using request/reply messaging with the
RabbitTemplate, replies were routed to the default exchange and routed
with the queue name. It is now possible to supply a reply-address with
the form exchange/routingKey to route using a specific exchange and
routing key.
Is it possible to configure an interceptor in Spring Integration to specify a logging message?
This is in contrast to using a wire-tap to send the message to a logging channel to which a logging channel adapter subscribes. The problem with this approach is that the logging channel has the expression for what exactly to log. In my use case I'd like to use a global channel-interceptor to specify a logging message and send it to a logging channel adapter, rather than having to define a logging channel adapter for every possible logging message I might want.
For a moment I thought I could define a service activator with an SpEL expression to produce the string logging message (and with an output-channel of the deisred logging channel) inside a channel-interceptor definition, but it's looking for an input-channel.
Instead of using a wire-tap, you could make the channels you are interested in <publish-subscribe-channel/>s.
Subscribe the appropriate transformer to the channel (with an output-channel going to the logging adapter).
You can control whether the log happens before or after the real subscriber using the order attribute on the transformer and other subscriber.
Another alternative is a global interceptor that adds a header to the message
MessageBuilder.fromMessage(message).setHeader('foo', routeForThisMessageType).build()
Then send it to a <header-value-router/> which, in turn, routes to the appropriate transformer, and thence to the single logging channel adapter.
Of course, if you want, you can combine the routing and/or transforming right into the interceptor.
My application is running under Tomcat with a number of Spring's DefaultMessageListenerContainer listening to a number of different JMS queues running under Oracle 11g Weblogic server.
DefaultMessageListenerContainer configuration is.. well.. default with sessionTransacted = false and sessionAcknowledgeMode = AUTO_ACKNOWLEDGE. The type of messages my application receives is javax.jms.TextMessage. The actual body of the message (message.getText()) is an XML string.
I was faced with a problem when a number of application instances (dev boxes, test boxes, etc) needed to be pointed to the same JMS server, so once message comes to the queue it is unknown which server will consume it (I believe the one that runs receive() method first). The problem is that any given application instance is only interested in messages dedicated to that particular application instance, so with a current configuration most of the messages get lost (consumed by other application instances and ignored in message processing business logic).
I have no control on JMS server implementation, but I can force it to set a particular XML element in the message body to an application instance specific value, so I can read it and decide what application instance should consume it.
The most natural way to do that would be setting messageSelector property on DefaultMessageListenerContainer so decision is made on JMS server which consumer should receive what message. I also learned about Weblogic specific JMS_BEA_SELECT message selector expression that works with XML message types. Unfortunately it doesn't seem to work with javax.jms.TextMessage messages with XML payload (or at least I couldn't make it to work). I was trying the following expression with no luck:
<property name="messageSelector" value="JMS_BEA_SELECT('xpath', '//Event/CorrelationID/text()') = 'MY_SELECTOR_TEST_3'"/>
According to this article the other options are:
Use a transacted session, then rollback the session so the message will go back to the queue and can be consumed by other application instance.
Use Session.CLIENT_ACKNOWLEDGE when creating a session, then recover the session so the message will go back to the queue and can be consumed by other application instance.
I understand that I need to set sessionTransacted and sessionAcknowledgeMode on DefaultMessageListenerContainer to non-default values (what values?) and then rollback the session in the message processor code (option 1) or don't call message.acknowledge() (option 2).
It looks like DefaultMessageListenerContainer controls message processing / session life cycle. How can I customise it?
Solution with rollbacks looks really weird.
Setting message selector should be enough. I didn't work with BEA JMS implementation but i guess you can take care with regular "SELECT" and selecting from header .
<property name="messageSelector" value="CorrelationID='MY_SELECTOR_TEST_3'/>
Do you work on both side of communication points (server,client) to control correlation id?