How to create channel interceptor programmatically in spring - spring

I want to create programmatically the following XML config on demand:
<int-mqtt:message-driven-channel-adapter id="inboundAdapter"
client-id="${mqtt.client.id}"
url="${mqtt.broker.url}"
topics="${mqtt.subscribed.topics}"
client-factory="clientFactory"
channel="input-channel-1" converter="customConverter" />
<int:channel id="input-channel-1">
<int:queue/>
<int:interceptors>
<int:wire-tap channel="logger"/>
<int:ref bean="messageListener"/>
</int:interceptors>
</int:channel>
<int:channel id="logger" />
<int:logging-channel-adapter channel="logger"
auto-startup="true" level="INFO" id="loggerAdapter" log-full-message="true" />
What i can do is the following
CustomMqttPahoMessageDrivenChannelAdapter adapter = new CustomMqttPahoMessageDrivenChannelAdapter(url, clientId, topic);
adapter.setOutputChannel(outputChannel);
adapter.setConverter(ctx.getBean("customConverter", MyPahoMessageConverter.class));
Now I need to add interceptor bean through which each client will get notified when message arrives according to their subscribed topics respectively.
What I am trying to achieve is:
1) Create mqtt adapter when a client connects to server.(each client will subscribe to different topics as per configuration)
2) Dispose mqtt adapter when client disconnects.
Can anyone help me on this?

It's not clear what you are trying to do; what do you have downstream of the input-channel-1 in the XML configuration.
What does messageListener do?
It is an anti-pattern to put business logic in a channel; unless it's something really lightweight, consider invoking it using a <service-activator/> instead - possibly by making input-channel-1 a pub-sub channel.
To answer your simple question, to add the interceptor, you can use outputChannel.addInterceptor(ctx.getBean("messageListener", ChannelInterceptor.class));.

Related

Spring Integration Redis RPOPLPUSH

I am new to Spring Integration & Redis, So my apology if I am making a naive mistake.
My requirement is as below -
Need to implement a message queue. For dispatching money to the user based on some events.
The queue should not be volatile and Ensuring Atomicity. If I restarted the server or it crashed it should not lose the event message. This also includes messages which are currently in progress.
The queue should deliver the message granted once and only once. It will be a multithreaded(workers) and multi-server environment.
My progress till now is - configured Spring Integration and Spring Integration Redis in my spring project. My Spring Integration config as below -
<int-redis:queue-outbound-channel-adapter
id="event-outbound-channel-adapter"
channel="eventChannelJson"
serializer="serializer"
auto-startup="true" connection-factory="redisConnectionFactory"
queue="my-event-queue" />
<int:gateway id="eventChannelGateway"
service-interface="com.test.RedisChannelGateway"
error-channel="errorChannel" default-request-channel="eventChannel">
<int:default-header name="topic" value="queue"/>
</int:gateway>
<int:channel id="eventChannelJson"/>
<int:channel id="eventChannel">
<int:queue/>
</int:channel>
<bean id="serializer" class="org.springframework.data.redis.serializer.StringRedisSerializer"/>
<int:object-to-json-transformer input-channel="eventChannel"
output-channel="eventChannelJson"/>
<int-redis:queue-inbound-channel-adapter id="event-inbound-channel-adapter"
channel="eventChannelJson" queue="my-event-queue"
serializer="serializer" auto-startup="true"
connection-factory="redisConnectionFactory"/>
<bean id="serializer" class="org.springframework.data.redis.serializer.StringRedisSerializer"/>
<int:json-to-object-transformer input-channel="eventChannelJson"
output-channel="eventChannel"
type="com.test.PostPublishedEvent"/>
<int:service-activator input-channel="eventChannel" ref="RedisEventProcessingService"
method="process">
<int:poller fixed-delay="10" time-unit="SECONDS" max-messages-per-poll="500"/>
</int:service-activator>
I read an article on similar topic where they were using redis RPOPLPUSH for this purpose. But I am unable too figure out how to do it in Spring Integration.
Link for the article is - https://redis.io/commands/RPOPLPUSH
Please advise me regading this. I will realy appricate your help.
Spring integration does not have a component that utilizes that operation.
To use it, you should wrap a RedisTemplate in a <int:service-activator/> and call one of its rightPopAndLeftPush() methods.

Spring Integration Web Service Log SOAP Request Message (EVEN if the soap message is not correct)

Could you tell me the way to log the SOAP message of , even if the message is not correct format ?
<sws:interceptors>
<bean class="com.capgemini.manulife.integration.interceptor.LogInterceptor" />
</sws:interceptors>
<!-- inbound -->
<ws:inbound-gateway id="cas-inbound-gateway" request-channel="casRequestChannel" reply-channel="casResponseChannel"
marshaller="casMarshaller" unmarshaller="casMarshaller" />
<int:channel id="casRequestChannel">
<int:interceptors>
<int:wire-tap channel="SOAPLogChannel"/>
</int:interceptors>
</int:channel>
<int:channel id="SOAPLogChannel" />
<int:logging-channel-adapter id="logger" expression="payload" level="INFO" channel="SOAPLogChannel"/>
As you see, I already using PayloadLoggingInterceptor (LogInterceptor extends PayloadLoggingInterceptor ), but it did not go through PayloadLoggingInterceptor
Thank you and best regards,
It's not Spring Integration question, but more up to SOAP directly.
So, if your XML isn't with correct format, you don't have choice unless check it manually before unmarshalling.
So, you have to rely on the simple <ws:inbound-gateway> do the <int-xml:validating-filter> (or some other check) and only after that perform <int-xml:unmarshalling-transformer>.
Yes, we can add Filter to Spring Web Service using FilterRegistrationBean ^^

How to intercept the reply message of an jms inbound gateway

I have a jms-inbound-gateway that reads requests from a WebsphereMQ broker, passes them though my integration system and then replies with a response message.
I need to log the messages with the jms_messageId and jms_correlationId headers set, so I can match request/reply messages in the log file (and show it to my client when he says that my response does not have the correct jms_correlationId)
Is there a way to intercept the method producer.sendReply(...) after the correlationId header is set?
There is no need to intercept there; the headers are available in the Spring Integration messsage in the gateway reply message before it gets to the gateway.
Simply make the reply-channel a publish-subscribe-channel and add a <logging-channel-adapter/> that has it as its input channel.
The reply message will be sent to both the gateway and the logger.
If you are using the default mechanism to route the reply (no output-channel on your last integration component), simply add an output-channel and route to the reply channel.
This is the gist of my solution after Gary's input:
<jms:inbound-gateway
id="inboundDestination"
connection-factory="connectionFactory"
request-destination="nmRequestsQueue"
request-channel="request-begin"
reply-channel="request-end"
error-channel="normaErrorChannel"
concurrent-consumers="1"
acknowledge="transacted" />
<int:logging-channel-adapter id="request-response-logger"
log-full-message="true"
level="DEBUG"
logger-name="com.audaxys.si.messages" />
<int:channel id="request-begin">
<int:interceptors>
<int:wire-tap channel="request-response-logger" />
</int:interceptors>
</int:channel>
<int:chain input-channel="request-begin" output-channel="request-end">
... Do Stuff ...
</int:chain>
<int:publish-subscribe-channel id="request-end">
<int:interceptors>
<int:wire-tap channel="request-response-logger" />
</int:interceptors>
</int:publish-subscribe-channel>

Logging in Spring-integration, statistics for the queue

Working with Spring-integration, I am using this code for logging (and I have configured the log4j).
<int:message-history/>
<int:logging-channel-adapter id="logger" auto-startup="true" log-full-message="true" level="INFO" logger-name="logger"/>
<int:channel id="messages" >
<int:queue />
<int:interceptors>
<int:wire-tap channel="logger" />
</int:interceptors>
</int:channel>
Here I am logging the full-message, but I would like to use the SpEL in order to log the ChannelName, and the message.
I need also to log the number of Messages in the Queue at each insertion or Poll but I didn't found how to do it and what to declare in the log4j.xml.
There is nothing to do for log4j: you just should configure specific category and level on the matter.
WireTap doesn't do anything with channel for which it is configured. It just sends a message to the provided channel. And it does it only onSend. It doesn't do anything onReceive.
To get deal with channel you have to implement your own ChannelInterceptor and do logging just there. I mean you don't need <wire-tap> and <logging-channel-adapter> anymore.
To get a number of Messages in the Queue you should configure:
<context:mbean-export />
<context:mbean-server />
After that all Integration components will be wrapped with *Metrics proxy.
For example the QueueChannel becomes QueueChannelMetrics.
And this info you can get from your new ChannelInterceptor before logging it together with the Message and channelName.

spring integration prevent polling when database not available

we are using Spring Integration 2.1 for persisting messages into database sent by clients.
There is a queue which will be filled by a custom adapter. The configured service activator polls this queue and releases the message to a spring managed #Repository bean. All errors will be captured to an error channel and will be handled by a service. The configuration works so far fine.
My concern is that if the database is not available the service-activators polls all incoming message from the queue and puts them into the error channel. Is there a way to prevent the service-activator to poll the message if the database is obviously not available, for example by sending a test query ?
My configuraton:
<int:channel id="inChannel">
<int:queue />
</int:channel>
<bean id="service" class="some.service.Service" />
<int:service-activator ref="service"
method="write" input-channel="inChannel">
<int:poller fixed-rate="100" task-executor="srvTaskExecutor"
receive-timeout="90" error-channel="errChannel" />
</int:service-activator>
<task:executor id="srvTaskExecutor" pool-size="2-10"
queue-capacity="0" rejection-policy="DISCARD" />
<int:channel id="errChannel" />
<int:service-activator input-channel="errChannel"
ref="errorService" method="write"/>
Regards.
If you give the polling service-activator an "id", you can refer to that instance and call start() or stop() on it based on the DB being available or not. Most likely you'd want to set auto-startup="false" on that service-activator as well.
Additionally, you can even define a "control-bus" element and then send messages like "myActivator.start()" and "myActivator.stop()" to that control bus' input-channel.
Hope that helps,
Mark

Resources