confirm-ack-channel is not getting invoked - spring-integration

Below is my config. In case of successful posting to queue the flow is not passing to confirm-ack-channel. Can anyone suggest where am going wrong?
<int-amqp:outbound-channel-adapter channel="fulfillmentOutboundChannel"
routing-key="xyz"
amqp-template="transactionalRabbitTemplate"
confirm-correlation-expression="payload"
confirm-ack-channel="successRespTransformChannel"
confirm-nack-channel="failureRespTransformChannel"
return-channel="failureRespTransformChannel"
mapped-request-headers="*"
/>
<int:channel id="successRespTransformChannel">
<int:interceptors><int:wire-tap channel="loggerChannel"/></int:interceptors>
</int:channel>
<chain input-channel="successRespTransformChannel">
<int:header-enricher>
<error-channel ref="failed-publishing" />
</int:header-enricher>
<service-activator id="successResp" expression="#abc.addRequestTracking(payload.id,'success')"/>
</chain>

In order to get acks/nacks, in addition to setting up the adapter with confirm-correlation, You also need to enable publisherConfirms on the CachingConnectionFactory.
From the documentation:
For Publisher Confirms (aka Publisher Acknowledgements), the template requires a CachingConnectionFactory that has its publisherConfirms property set to true.

Thanks for your response Gary. I have already made publish-confirms=true as below..
<rabbit:connection-factory id="fufillConnectionFactory"
connection-factory="rabbitClientConnectionFactory"
publisher-confirms="true"
publisher-returns="true"/>
<bean id="rabbitClientConnectionFactory" class="com.rabbitmq.client.ConnectionFactory" >
<property name="uri" value="${mq.uri}" />
<property name="requestedHeartbeat" value="30" />
</bean>

Related

Spring Integration Null correlation not allowed. Maybe the CorrelationStrategy is failing?

I am getting the error `Null correlation not allowed. Maybe the CorrelationStrategy is failing?
This forum thread seemed to resolve it with something like the below, however that approach Is not working for me, http://forum.spring.io/forum/spring-projects/integration/102054-aggregator-correlation-strategy-failing.
My understanding is that the inbound-streaming-channel-adapter puts FILE_NAME as a header value, and I'd like to join on that.
<int-ftp:inbound-streaming-channel-adapter
auto-startup="true" id="ftpListener" channel="ftpChannel"
session-factory="ftpSessionFactory" remote-directory="/export/home/udyj"
filename-pattern="test1.txt">
<integration:poller fixed-rate="5000"
max-messages-per-poll="-1" />
</int-ftp:inbound-streaming-channel-adapter>
<int-ftp:inbound-streaming-channel-adapter
auto-startup="true" id="ftpListener2" channel="ftpChannel"
session-factory="ftpSessionFactory" remote-directory="/export/home/udyj"
filename-pattern="test2.txt">
<integration:poller fixed-rate="5000"
max-messages-per-poll="-1" />
</int-ftp:inbound-streaming-channel-adapter>
<bean id="correlationStrategy"
class="org.springframework.integration.aggregator.HeaderAttributeCorrelationStrategy">
<constructor-arg value="FILE_NAME.substring(0,3)" />
</bean>
<integration:aggregator id="nuggetAggregator"
input-channel="ftpChannel" output-channel="sendMQDistributionChannel"
correlation-strategy="correlationStrategy">
</integration:aggregator>
Look, you say HeaderAttributeCorrelationStrategy, what definitely expect a header name to get. but at the same you specify the header name as a FILE_NAME.substring(0,3) which looks more like an expression. And you get null because there is really no such a header.
If you want to evaluate an expression, consider to use ExpressionEvaluatingCorrelationStrategy instead:
<bean id="correlationStrategy"
class="org.springframework.integration.aggregator.ExpressionEvaluatingCorrelationStrategy">
<constructor-arg value="headers.file_name.substring(0,3)" />
</bean>

Spring Integration jmsmessage-driven-channel-adapter with IBM MQ

I have written code to read message from IBM MQ using Spring Integration JMS-message-driven-channel-adapter but not able to read message from queue can anybody help me out below is my configuration.
<beans:bean id="ibmJmsConnectionFactory" class="com.ibm.mq.jms.MQQueueConnectionFactory">
<beans:property name="transportType" value="1"/>
<beans:property name="queueManager" value="***"/>
<beans:property name="hostName" value="**"/>
<beans:property name="port" value="**" />
<beans:property name="channel" value="***"/>
</beans:bean>
<beans:bean id="receiverQueue" class="com.ibm.mq.jms.MQQueue">
<beans:constructor-arg index="0" value="****"/>
<beans:constructor-arg index="1" value="****"/>
</beans:bean>
<integration:channel id="componentInfoChannel" />
<jms:message-driven-channel-adapter
id="componentInfoAdapter" connection-factory="ibmJmsConnectionFactory" destination="receiverQueue" channel="componentInfoChannel"
/>
<integration:service-activator id="componentInfoActivator"
input-channel="componentInfoChannel" ref="componentInfoConsumer"
method="componentInfoListen" />
Above configuration is working but failing when I added logging adapter its continously printing warning on console .Detail are mention below .
<integration:logging-channel-adapter
id="componentInfologger" level="INFO" />
<integration:wire-tap id="componentInfoWireTap"
channel="componentInfologger" pattern="*" order="2" />
<integration:logging-channel-adapter
id="logger" log-full-message="true" level="INFO" />
2017-02-23 00:09:05.093 WARN [componentdatafiles,48f69e84ab395754,ebf4ae7f3b812a01,false] 90072 --- [ter.container-1] o.s.j.l.DefaultMessageListenerContainer : Execution of JMS message listener failed, and no ErrorHandler has been set.
java.lang.StackOverflowError: null
at java.util.Collections$SynchronizedMap.put(Unknown Source)
at ch.qos.logback.classic.util.LogbackMDCAdapter.put(LogbackMDCAdapter.java:110)
at org.slf4j.MDC.put(MDC.java:147)
at org.springframework.cloud.sleuth.log.Slf4jSpanLogger.logStartedSpan(Slf4jSpanLogger.java:48)
at org.springframework.cloud.sleuth.trace.DefaultTracer.createChild(DefaultTracer.java:170)
at org.springframework.cloud.sleuth.trace.DefaultTracer.createSpan(DefaultTracer.java:72)
at org.springframework.cloud.sleuth.instrument.messaging.TraceChannelInterceptor.startSpan(TraceChannelInterceptor.java:98)
at org.springframework.cloud.sleuth.instrument.messaging.TraceChannelInterceptor.preSend(TraceChannelInterceptor.java:78)
at org.springframework.integration.channel.AbstractMessageChannel$ChannelInterceptorList.preSend(AbstractMessageChannel.java:538)
at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:415)
at org.springframework.integration.channel.interceptor.WireTap.preSend(WireTap.java:168)
at org.springframework.integration.channel.AbstractMessageChannel$ChannelInterceptorList.preSend(AbstractMessageChannel.java:538)
at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:415)
at org.springframework.integration.channel.interceptor.WireTap.preSend(WireTap.java:168)
at org.springframework.integration.channel.AbstractMessageChannel$ChannelInterceptorList.preSend(AbstractMessageChannel.java:538)
at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:415)
at org.springframework.integration.channel.interceptor.WireTap.preSend(WireTap.java:168)
at org.springframework.integration.channel.AbstractMessageChannel$ChannelInterceptorList.preSend(AbstractMessageChannel.java:538)
at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:415)
at org.springframework.integration.channel.interceptor.WireTap.preSend(WireTap.java:168)
Sorry for delay. So, I guess your id="logger" is redundant component. And the problem is exactly with the <integration:wire-tap> and combination with the TraceChannelInterceptor.
I mean that you use here Spring Cloud Sleuth.
Would you mind sharing DEBUG for the org.springframework.integration category meanwhile I'm trying to reproduce an issue locally.
Plus you can exclude componentInfologger from the tracing to avoid that java.lang.StackOverflowError.
I think it happens somehow that we loop tracing via wire-tap.

messages not getting consumed depending whether the message is of type text or string

Below i have the program to send a message and consume a message from queue , rite now i have commented out the sending part and only want to consume the messages from queue , the message can be type of string or object message for which i have configure router.
Now there are text message in the queue which my below program is not consuming please advise how to overcome from this below is my configuration , as you can see i have commented out the sender part so the only reading part from the queue is the active one
and also when rite now i have observe that messages are getting consumed but files are not being generated so this means that there is some error after payload router i have configured
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/integration/jms
http://www.springframework.org/schema/integration/jms/spring-integration-jms.xsd
http://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/integration/file
http://www.springframework.org/schema/integration/file/spring-integration-file.xsd
http://www.springframework.org/schema/context/spring-context.xsd">
<int:poller id="poller" default="true">
<int:interval-trigger interval="200" />
</int:poller>
<int:channel id="input">
<int:queue capacity="10" />
</int:channel>
<bean id="tibcoEMSJndiTemplate" class="org.springframework.jndi.JndiTemplate">
<property name="environment">
<props>
<prop key="java.naming.factory.initial">com.tibco.tibjms.naming.TibjmsInitialContextFactory
</prop>
<prop key="java.naming.provider.url">tcp://lsdrtems2.fm.crdgrp.net:7333</prop>
<prop key="java.naming.security.principal">acfgtir</prop>
<prop key="java.naming.security.credentials">acfgtir</prop>
</props>
</property>
</bean>
<bean id="tibcoEMSConnFactory" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiTemplate">
<ref bean="tibcoEMSJndiTemplate" />
</property>
<property name="jndiName">
<value>GenericConnectionFactory</value>
</property>
</bean>
<bean id="tibcosendJMSTemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory">
<ref bean="tibcoEMSConnFactory" />
</property>
<property name="defaultDestinationName">
<value>acfgtirrtyation.ioa.swretift_publish_poc1</value>
</property>
<property name="pubSubDomain">
<value>false</value>
</property>
<property name="receiveTimeout">
<value>120000</value>
</property>
</bean>
<!-- <jms:outbound-channel-adapter channel="input"
destination-name="acfgtirrtyation.ioa.swretift_publish_poc1" connection-factory="tibcoEMSConnFactory" /> -->
<int:channel id="objetChannel"></int:channel>
<int:channel id="StringChannel"></int:channel>
<int:channel id="jmsInChannel" />
<jms:message-driven-channel-adapter id="jmsIn" concurrent-consumers="10"
destination-name="acfgtirrtyation.ioa.swretift_publish_poc1" connection-factory="tibcoEMSConnFactory" extract-payload="false"
channel="jmsInChannel" />
<int:payload-type-router input-channel="jmsInChannel">
<int:mapping type="javax.jms.ObjectMessage" channel="objetChannel" />
<int:mapping type="javax.jms.TextMessage" channel="StringChannel" />
</int:payload-type-router>
<file:outbound-channel-adapter id="filesoutOject" channel="objetChannel" directory="C:\\abcsaral"
filename-generator="generatorr" />
<file:outbound-channel-adapter id="filesoutString" channel="StringChannel" directory="C:\\abcsaral"
filename-generator="generatorr" />
<bean id="generatorr" class="com.abs.tibco.TimestampTextGenerator">
</bean>
</beans>
Folks please advise for this any early help would be much appreciated
below is the timestamp generator class as shown below
public class TimestampTextGenerator implements FileNameGenerator {
#Override
public String generateFileName(Message<?> arg0) {
return new java.text.SimpleDateFormat("yyyyMMdd-HHmmss.SSS")
.format(new java.util.Date()) + ".txt";
}
}
Folks please advise as I am completely stuck up on this..!
Remove this attribute extract-payload="false" in your message-driven-channel-adapter. It changes expected payload type and your payload-type-router doesn't work.
Also look this 20.1. Inbound Channel Adapter manual chapter.
The best way to understand what's wrong with your application is to take a look into logs. I should admit that sometimes Java is more smarter than me :-).
See Gary Russel's answer for you on the matter: Enabling logging in spring integration utiliy
Please, try to follow with all our answers to you around this topic.
I suggested you to use extract-payload="false" to get the whole javax.jms.ObjectMessage or javax.jms.TextMessage as a payload independently of the conversion result, when the javax.jms.ObjectMessage maybe converted to the java.lang.String as well. Although, right, in most case the routing based just only on the java.lang.String and all others should work, too.
Now about the <file:outbound-channel-adapter> problem. If you take a into logs you should see something like:
else {
throw new IllegalArgumentException(
"unsupported Message payload type [" + payload.getClass().getName() + "]");
}
M-m-m, yeah, I mean the result of this Exception in logs. Just because your payload is javax.jms.Message, but to write into file you should supply File, InputStream, byte[] or String.
So, as I said in comments to my answer (consuming all the object type messages from a queue) to your similar question, you should convert the message after routing into some appropriate type for <file:outbound-channel-adapter>.

Spring Integration : How to handle multiple Subscribers in one transaction?

My Spring Integration Xml.
<int:channel id="request-write-to-PMSQueueChannel" >
<int:queue message-store="channelStore" />
</int:channel>
<int:bridge input-channel="request-write-to-PMSQueueChannel" output-channel="writetoPMSChannel">
<int:poller fixed-rate="5000" max-messages-per-poll="-1">
<int:transactional propagation="REQUIRED" transaction-manager="transactionManager"/>
</int:poller>
</int:bridge>
<int:channel id="redBlue-error-channel"/>
<int:service-activator id="errorServiceActivator" input-channel ="redBlue-error-channel">
<bean id="errorSVC"
class="com.sds.redBlue.core.module.analyzer.sample.ErrorServiceActivator"/>
</int:service-activator>
<bean id="channelStore" class="org.springframework.integration.jdbc.store.JdbcChannelMessageStore">
<property name="dataSource" ref="dataSource" />
<property name="channelMessageStoreQueryProvider" ref="queryProvider" />
</bean>
<bean id="queryProvider" class="org.springframework.integration.jdbc.store.channel.DerbyChannelMessageStoreQueryProvider"/>
<int:publish-subscribe-channel id="writetoPMSChannel" ignore-failures = "false"/>
<int:chain input-channel="writetoPMSChannel"
output-channel="writetoPMS001Channel">
<int:service-activator method="exectue">
<bean id=""
class="com.sds.redBlue.core.module.analyzer.convert.ModelingConvertSVC">
</bean>
</int:service-activator>
<int:splitter ref="fromListToRowSplitter" />
</int:chain>
<int:chain input-channel="writetoPMSChannel"
output-channel="writetoPMS002Channel">
<int:service-activator method="exectue002">
<bean id=""
class="com.sds.redBlue.core.module.analyzer.convert.ModelingConvertSVC">
</bean>
</int:service-activator>
<int:splitter ref="fromListToRowSplitter" />
</int:chain>
<int:chain input-channel="writetoPMSChannel"
output-channel="writetoPMS003Channel">
<int:service-activator method="exectue003">
<bean id=""
class="com.sds.redBlue.core.module.analyzer.convert.ModelingConvertSVC">
</bean>
</int:service-activator>
<int:splitter ref="fromListToRowSplitter" />
</int:chain>
<int:chain input-channel="writetoPMSChannel"
output-channel="writetoPMS004Channel">
<int:service-activator method="exectue004">
<bean id=""
class="com.sds.redBlue.core.module.analyzer.convert.ModelingConvertSVC">
</bean>
</int:service-activator>
<int:splitter ref="fromListToRowSplitter" />
</int:chain>
<int:chain input-channel="writetoPMSChannel"
output-channel="writetoPMS005Channel">
<int:service-activator method="exectue005">
<bean id=""
class="com.sds.redBlue.core.module.analyzer.convert.ModelingConvertSVC">
</bean>
</int:service-activator>
<int:splitter ref="fromListToRowSplitter" />
</int:chain>
I want to 5 subscribers have to be executed at once or have to be rollback if one subscribe throws any exception. But I can't find the way to sovle.
related article:
Pub-Sub error handling strategy
I already asked with the the eip pattern pic and Gary helped. but, I stucked.
(Spring Integration : How to guarantee the transaction two more jdbc-outbound-gateway?)
Since transaction is bounded to the Thread, you should be sure that all your subscribers are withing the same direct flow. In this case they will be invoked one by one.
However I see that you use ignore-failures = "false". Having you ignore all downstream exception and allow for your subscribers to do their work. Although you lose TX rollback, of course.
So, revise your use-case if you really want to have automatic rallback.
There is an async trick to control TX, but it is a bit complex and require some logic with aggregator.

Right way to use transactional and request-handler-advice-chain in a JPAOutboundGateway

I've got for a JPA Outbound-channel-adapter both transactional and request-handler-advice-chain. In the advice-chain I try to log the Exception, when it happens.
It iss not logged, but I know that it actually happend since the Message was sent to failover clickDbFailoverChannel . What can be a problem with it? Is it a bug in Spring Integration?
<int:channel id="clickDbWithFailoverChannelSite-1">
<int:dispatcher load-balancer="none" task-executor="clickDbSiteRouterExecutor"/>
</int:channel>
<int:bridge input-channel="clickDbWithFailoverChannelSite-1"
output-channel="jpaOutboundChannelSite-1" order="1" send-timeout="100" />
<int:bridge input-channel="clickDbWithFailoverChannelSite-1"
output-channel="clickDbFailoverChannel" order="2" />
<int-jpa:outbound-channel-adapter id="jpaOutboundChannelSite-1"
persist-mode="PERSIST" flush-size="100" entity-manager-factory="emfSite-1">
<int-jpa:transactional transaction-manager="transactionManagerSite-1" />
<int-jpa:request-handler-advice-chain>
<bean class="org.springframework.integration.handler.advice.ExpressionEvaluatingRequestHandlerAdvice">
<property name="failureChannel" ref="clickDbFailureLogger"/>
<property name="onFailureExpression" value="#exception"/>
</bean>
</int-jpa:request-handler-advice-chain>
</int-jpa:outbound-channel-adapter>
OK. I can guess where is your issue. The real exception to rollback the transaction is caused before an internal logic, where <request-handler-advice-chain> does the stuff. That's why your ExpressionEvaluatingRequestHandlerAdvice doesn't get a failure message.
To workaround your rollback issue, you should replace <int-jpa:transactional> with <tx:advice> within <int-jpa:request-handler-advice-chain>.
You should understand here that <int-jpa:transactional> is for entire MessageHandler.handleMessage, but <int-jpa:request-handler-advice-chain> is just for its part - AbstractReplyProducingMessageHandler.handleRequestMessage.
UPDATE
TX Advice should be like this:
<tx:advice transaction-manager="transactionManagerSite-1"/>
<tx:attributes>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>

Resources