spring integration jms traceability - spring-integration

We have a requirement to add the traceability (to add trace-id and spell-id) for incoming and outgoing JMS messages in controller module which is based on Spring Integration. Can anyone help me with the interceptor that can be used for this which can intercept all request coming into JMS queue and all the request that will be send onto the queue.
Below is the code snippet:
<!-- Need to trace the message once we receive in incoming_queue -->
<int-jms:message-driven-channel-adapter id="jmsIn" channel="channel_1"
destination-name="incoming_queue"></int-jms:message-driven-channel-adapter>
<!-- Need to trace the message before we send the message to outgoing_queue -->
<int-jms:outbound-channel-adapter id="jmsOut"
channel="channel_1" connection-factory="connectionFactory"
destination-name="outgoing_queue"/>
Thanks

On both side there is a DefaultJmsHeaderMapper with this JavaDoc:
* This implementation copies JMS API headers (e.g. JMSReplyTo) to and from
* Spring Integration Messages. Any user-defined properties will also be copied
* from a JMS Message to a Spring Integration Message, and any other headers
* on a Spring Integration Message (beyond the JMS API headers) will likewise
* be copied to a JMS Message. Those other headers will be copied to the
* general properties of a JMS Message whereas the JMS API headers are passed
* to the appropriate setter methods (e.g. setJMSReplyTo).
So, if your those trace-id and spell-id are in compatible types:
private static List<Class<?>> SUPPORTED_PROPERTY_TYPES = Arrays.asList(new Class<?>[] {
Boolean.class, Byte.class, Double.class, Float.class, Integer.class, Long.class, Short.class, String.class });
You are good to send and receive those headers.
If you think about something like logging those headers, you definitely can take a look into the ChannelInterceptor implementation to log those headers before/after sending/receiving to/from JMS.

Related

consuming Server Sent Events with Webflux or Flux-producing Endpoint in Spring Integration

How can I consume Server Sent Events with Spring Integration? I am aware Spring supports SSE with Webflux, but how to convert the incoming Flux into separate Message instances? And possibly wrap this code into some Spring-Integration-Lifecycle-aware component (MessageProducerSupport?)
WebClient client = WebClient.create("http://myhost:8080/sse");
ParameterizedTypeReference<ServerSentEvent<String>> type
= new ParameterizedTypeReference<ServerSentEvent<String>>() {};
Flux<ServerSentEvent<String>> eventStream = client.get()
.uri("/stream-sse")
.retrieve()
.bodyToFlux(type);
eventStream.subscribe(
content -> ;/* here I believe the message should be produced/sent to a channel */ );
See Spring Integration WebFlux Outbound Gateway: https://docs.spring.io/spring-integration/docs/current/reference/html/webflux.html#webflux-outbound:
The setExpectedResponseType(Class<?>) or setExpectedResponseTypeExpression(Expression) identifies the target type of the response body element conversion. If replyPayloadToFlux is set to true, the response body is converted to a Flux with the provided expectedResponseType for each element, and this Flux is sent as the payload downstream. Afterwards, you can use a splitter to iterate over this Flux in a reactive manner.
WebFlux.outboundGateway("http://myhost:8080/sse/stream-sse")
.httpMethod(HttpMethod.GET)
.replyPayloadToFlux(true)
.setExpectedResponseTypeExpression(new ParameterizedTypeReference<ServerSentEvent<String>>() {})
To make it start working just after an application is ready, yo can implement an ApplicationRunner to send a "void" message into a channel for the flow with that WebFlux.outboundGateway(). I don't think we need a special, dedicated component just for SSE requesting and producing. The combination of existing components is fully enough.

How to add JMS properties via Spring Integration using ws:outbound-gateway (JMS transport)

I have a ws:outbound-gateway in place pointing to a org.springframework.ws.transport.jms.JmsMessageSender class in order to push a Soap message into the queue.
The output message has been generated okay and published into the queue normally with the following JMS properties on it: SOAPJMS_soapAction, SOAPJMS_contentLength, SOAPJMS_contentType, etc.
My question is: how can I add a custom JMS property as part of the JMS properties generated by default? Is this possible? I'm using Spring Integration 4.3.5.RELEASE.
The JmsMessageSender can be supplied with the MessagePostProcessor.
The you can supply any desired JMS property on target Message.

Spring Integration Control Bus message to change selector of a JMS Inbound Channel Adapter

I'm currently implementing a flow on a Spring Integration-based (ver. 3.0.1.RELEASE) application that requires to store messages on a JMS queue to be picked up later.
For that, I've been trying to use a Spring Integration JMS Inbound Channel Adapter with a custom selector, and then picking up the message from the queue by changing the JMS selector of the JMSDestinationPollingSource to some matching ID included as a header property.
One of the requirements for this is that I cannot add a new service or a JAVA method, so I've been trying to sort it out using a Control Bus, but keep receiving the same error when I send the message to set the messageSelector to something different.
Inbound Channel Adapter definition:
<int-jms:inbound-channel-adapter id="inboundAdapter"
channel="inboundChannel"
destinationName="bufferQueue"
connection-factory="connectionFactory"
selector="matchingID = 'NO VALUE'">
<int:poller fixed-delay="1000"/>
</int-jms:inbound-channel-adapter>
Message:
#'inboundAdapter.source'.setMessageSelector("matchingID = 'VALUE'")
Error:
EvaluationException: The method 'public void org.springframework.integration.jms.JmsDestinationPollingSource.setMessageSelector(java.lang.String)' is not supported by this command processor. If usign the Control Bus, consider adding #ManagedOperation or #ManagedAttribute.
Which, AFAIK, means that the JmsDestinationPollingSource class is not Control Bus manageable, as it's not passing the ControlBusMethodFilter.
Is this approach nonviable, or is there something I'm missing? Is there any way to set the selector dynamically using SI XML configuration files only?
First of all it is strange to use Java tool and don't allow to write code on Java...
But that is your choice, or as you said requirements.
Change the employer! ;-)
That's correct: Control Bus allows only #ManagedOperation and #ManagedAttribute method. Since JmsDestinationPollingSource.setMessageSelector. We can make it like that. But does it make so much sense if we can reach it a bit different approach?
<int:outbound-channel-adapter id="changeSelectorChannel"
ref"inboundAdapter.source method="setMessageSelector"/>
where a new selector expression should be as a payload of the Message to this channel.

how get payload in int-http:outbound-gateway in call to rest/json service

From a channel with a payload call to
one int-http:outbound-gateway that call to an url to returns a JSON response
How get the initial payload from caller to get the initial payload,
i´d need it to use in aggregator
This is the scene
message --> channel --> service activator --> outputchannel
outputchannel--->int-http:outbound-gateway(call rest service1) -->response to *
outputchannel--->int-http:outbound-gateway(call rest service2) -->response to *
aggregator
You should place it to the MessageHeaders:
<header-enricher>
<header name="requestPayload" expression="payload"/>
</header-enricher>
before those <int-http:outbound-gateway> invocation and extract it from headers in the aggregator logic.

How to acknowledge message through program using Spring AMQP/Spring integration

1) Server sends a message to client.
2) Inbound channel adapter is configured to wait for "MANUAL" acknowledge mode operation from consumer
3) "TaskBundlereceiver" bean is implementing "ChannelAwareMessageListener" and in the implementation method, I am performing message acknowledgement.
I don't see "TaskBundlereceiver" getting executed. Am I missing something ?
Below is the configuration details of the steps that I have explained.
Appreciate your inputs.
#Override
public void onMessage(org.springframework.amqp.core.Message message, Channel channel) throws Exception
{
logger.debug("In onMessage method of the channel aware listener. message =["+message.getBody().toString()+"]");
channel.basicAck(message.getMessageProperties().getDeliveryTag(), true);
}
XML Configuration :
<!-- Channel that receives the task bundle from the server for execution -->
<int:channel id="fromKServerChannel"/>
<int-amqp:inbound-channel-adapter id="taskBundleReceiverAdapter"
channel="fromKServerChannel"
error-channel="taskBundleErrorChannel"
acknowledge-mode="MANUAL"
expose-listener-channel="true"
queue-names="kanga_task_queue"
connection-factory="connectionFactory"
concurrent-consumers="20"/>
<int:chain input-channel="fromKServerChannel" output-channel="nullChannel">
<int:service-activator ref="taskBundleReceiver" method="onMessage"/>
<int:service-activator ref="taskBundleExecutor" method="executeBundle"/>
</int:chain>
It doesn't work that way; the listener is the adapter, not the service invoked via the service-activator. The adapter currently does not support passing the channel to the client for manual acks. The expose-listener-channel attribute is for use when using transactions, so a down-stack rabbit template can participate in the transaction.
Why do you want MANUAL acks? AUTO (default) means the ack will be done automatically by the container when the thread returns normally; if your service throws an exception, the message will be nacked.
So, that's how to control the ack.
If you really want to use MANUAL acks, you'll have to use a <rabbit:listener-container/> to invoke your taskBundleReceiver directly. It could then send a message to the executor using a messaging gateway.

Resources