Spring Integration Service Activator Without Output Channel - java

In my code I have a inbound adapter channel and a service activator I want not to connect service activator with out bound channel ,
Code I am using
<file:inbound-channel-adapter id="filesIn"
directory="E:/usmandata/logs/input" filter="onlyLogFiles"
auto-startup="true">
<int:poller id="poller" fixed-delay="5000" />
</file:inbound-channel-adapter>
<int:service-activator input-channel="filesIn" ref="handler" />

As mentioned in the docs , simply make it as void return type or set it to nullChannel
If the method returns a result and no "output-channel" is defined, the framework will then check the request Message’s replyChannel header value. If that value is available, it will then check its type. If it is a MessageChannel, the reply message will be sent to that channel. If it is a String, then the endpoint will attempt to resolve the channel name to a channel instance. If the channel cannot be resolved, then a DestinationResolutionException will be thrown. It it can be resolved, the Message will be sent there. If the request Message doesn’t have replyChannel header and and the reply object is a Message, its replyChannel header is consulted for a target destination. This is the technique used for Request Reply messaging in Spring Integration, and it is also an example of the Return Address pattern.
If your method returns a result, and you want to discard it and end the flow, you should configure the output-channel to send to a NullChannel. For convenience, the framework registers one with the name nullChannel. See Section 4.1.6, “Special Channels” for more information.
The Service Activator is one of those components that is not required to produce a reply message. If your method returns null or has a void return type, the Service Activator exits after the method invocation, without any signals. This behavior can be controlled by the AbstractReplyProducingMessageHandler.requiresReply option, also exposed as requires-reply when configuring with the XML namespace. If the flag is set to true and the method returns null, a ReplyRequiredException is thrown.

Related

Spring AMQP: Amqp.outboundAdapter to #RabbitListener, error sending response due to missing "reply-to" property

So,
I have 2 Spring Boot applications (2.6.10) that need to communicate via RabbitMQ / AMQP. App #1 is Spring Integration based and uses
Amqp.outboundAdapter(rabbitTemplate).routingKey("app1-to-2")
to send messages in flow #1
Amqp.inboundAdapter(connectionFactory, "app2-to-1")
to receive messages in flow #2
App #2 is using RabbitListener to receive messages from App #1, process them immediately and return a reply:
#RabbitListener(queues={"app1-to-2"})
public MyResponse handleMessage(final MyRequest request) {
var myResponse = this.process(myRequest);
rabbitTemplate.convertAndSend("app2-to-1",myResponse);
}
However, upon receiving myRequest in App #2, the response cannot be send, due to:
AmqpException: Cannot determine ReplyTo message property value: Request message does not contain reply-to property, and no default response Exchange was set.
Question is: Why is the routing key from convertAndSend ignored or how to set reply-to property with Amqp.outboundAdapter?
Your error has nothing to do with the convertAndSend().
It is the problem of the #RabbitListener method signature.
Since you don't deal with request-reply pattern, your listener method must have a void return type. Otherwise it tries to send that MyResponse object as a reply message body and therefore we see that error trying to resolve ReplyTo from default strategy.

spring integration JMS message driven channel adaptor using selector

<int-jms:message-driven-channel-adapter>
Using message driven adapter , i want to filter message from AMQ broker using selector .
message has to filtered against dynamic bean variable value which is validated using selector bean ref option
In reply to your comments..
Thanks for your reply , I want to filter message using selector attribute in Message driven channel adaptor . i was able to call bean method inside selector attribute #bean.method() , but not able to pass header parameter to that method #bean.method(header.param) . I am expecting selector should validate dynamically passing the header parameter to bean method and return boolean result so that message can be filtered.
<int-jms:message-driven-channel-adapter connection-factory="connectionFactoryName"
destination="destinationName" channel="channelName"
selector="#{#bean.method(header.param)}" auto-startup="false"/>
the above selector attribute has bean method configured to receive header param dynamically whenever pick message from AMQ . but it is syntactically wrong not able to pass header param. can you help?
You don't seem to understand what a JMS message selector is...
selector="foo='bar'"
...tells the broker to only send messages with the foo property equal to bar.
It is configured on the consumer during startup.
What you have is not "dynamic". #{...} expressions are evaluated once during context initialization.
What you are trying to do makes no sense; there is no "message" from which to evaluate a header yet. You can't tell the broker which message(s) to send, based on the contents of a message. The filtering is done on the broker before sending the message(s).
If you don't mind "losing" the messages you are not interested in (or are consuming from a topic) and you want to filter the messages you want to process, then add a
<filter ... expression="#{#bean.method(header.param)}" />
after the adapter. You could use the discard channel to republish the ignored message(s) to another queue (or do something else with them).

Spring AMQP MessageProperties:all headers were removed during deadlettering

I have got a question about Spring AMQP Message:
During processing I was able to update headers of message properties in String AMQP Message with some specific values.
After DeadLettering of this message, all specific headers were disappeared/removed.
Is this behaviour correct ?
Looking forward to your response.
Regards, Anton.
spring-rabbit.version: 1.3.5.RELEASE
spring.version: 4.1.1.RELEASE
The broker knows nothing about your client-side consumer changes; the original message (with its orignal headers) is dead-lettered by the broker (with an x-death header added to indicate the reason - rejection, expiry etc).
In order to do what you want, you need to publish your modified message yourself rather than using dead-lettering.
See the RepublishMessageRecoverer for an example using Spring retry. You can make a custom recover, or simply catch the exception in your listener to republish.

How is Request/Reply best implemented using JMS and Spring Integration (2.2)

I have a simple request reply test implemented using the following configuration:
<int:gateway id="myGateway"
service-interface="TestGateway"
default-request-channel="sendingChannel"
default-reply-channel="replyChannel"
default-reply-timeout="2000"
/>
<int:channel id="sendingChannel" />
<int:channel id="replyChannel" />
<int-jms:outbound-gateway id="myJmsGateway"
connection-factory="jmsConnectionFactory"
request-channel="sendingChannel"
request-destination-name="outQueue"
reply-channel="replyChannel"
reply-destination-name="outQueueReply"
receive-timeout="60000"
/>
and the Interface:
public interface TestGateway {
#Gateway
public String requestReply(#Header("myHeaderKey") String headerValue, String data);
}
While the above configuration does "work" I have the following reservations.
The configuration feels redundant. Extra gateway and two extra channels required. Both gateways implement a reply timeout (although the int:gateway timeout doesn't fire when connected to a int-jms:outbound-gateway).
The semantics of the gateway method change depending on what is implementing the request/reply. On Timeout the int-jms:outbound-gateway will throw an exception, which will propagate to the user of TestGateway. If the config is changed to replace int-jms:outbound-gateway the int:gateway will return null.
Given this the client code has to both handle null and the exception in the same way.
Are there any better ways to wire up the gateways? One option would be to change the int:channel's to PollableChannel's which solves problem 2 at the expense of an extra thread pool.
You don't need to configure reply channels; by default the jms gateway (with no reply channel) will return the message to the inbound gateway automatically.
When using direct channels, the messaging gateway's timeout only starts when the thread tries to receive any reply that was returned from the flow.
You can avoid the different semantics (null Vs exception) by adding an error-channel to the inbound gateway.
It's important to understand that myGateway isolates your client from the messaging system, you code to the interface only. Of course you could inject the JMS gateway directly but then you've added dependencies to your code. With a messaging gateway, you can change technologies without making any changes to your client code. You can also unit test your code by providing a test implementation of TestGateway. This is a powerful feature of Spring Integration.

Spring Integration Gateway with no arguments

On my gateway, I have a method
#Gateway
String commsTest();
The idea is that I can call commsTest from the bean and use spring integration to wire it up to the service activator that will check comms.
When I do that I get a receive is not supported, because no pollable reply channel has been configured error. I realise that this is because a method with no params means "I am trying to poll a message from the channel"
This is a two part question.
What does it mean to poll a message from the channel.
How can I get the functionality I want.
Spring Integration currently has no concept of a message without a payload. By default, a gateway method with no arguments implies you want to receive data (rather than sending data or sending and receiving data).
You can change that default behavior, as described in the reference documentation.

Categories