Trying to log channel error and using a retry policy, i log two exception stacktrace instead of only one.
Channel configuration :
<bean id="retryInterceptor" class="org.springframework.amqp.rabbit.config.StatelessRetryOperationsInterceptorFactoryBean">
<property name="messageRecoverer" ref="rejectAndDontRequeueRecoverer"/>
<property name="retryOperations" ref="retryTemplate" />
</bean>
<bean id="rejectAndDontRequeueRecoverer" class="org.springframework.amqp.rabbit.retry.RejectAndDontRequeueRecoverer"/>
<!-- Configuration du retry -->
<bean id="retryTemplate" class="org.springframework.retry.support.RetryTemplate">
<property name="backOffPolicy">
<bean class="org.springframework.retry.backoff.ExponentialBackOffPolicy">
<!-- Intervalle de temps en millisecondes entre deux tentatives -->
<property name="initialInterval" value="2000" />
</bean>
</property>
<property name="retryPolicy">
<bean class="org.springframework.retry.policy.SimpleRetryPolicy">
<!-- Nombre de retry max -->
<property name="maxAttempts" value="3" />
</bean>
</property>
</bean>
<bean id="log" class="com.logger.Logger"/>
<!-- Logger -->
<int:channel id="one" ></int:channel>
<int:channel id="error1" ></int:channel>
<int:publish-subscribe-channel id="processChannel1" />
<int:logging-channel-adapter channel="processChannel1" logger-name="log1" level="ERROR" expression="payload.message"/>
<int:service-activator input-channel="processChannel1" ref="log" output-channel="error1" />
<!-- Source -->
<rabbit:connection-factory id="connectionFactory" username="guest" password="guest" addresses="XX.XX.XX.XX:5672" cache-mode="CONNECTION" virtual-host="/" />
<int-amqp:inbound-channel-adapter channel="one" id="inboundChannelAdapter1" queue-names="myqueue" connection-factory="connectionFactory" error-channel="processChannel1" channel-transacted="true" advice-chain="retryInterceptor" />
<!-- Destination -->
<rabbit:connection-factory id="connectionFactoryRmqDest" username="guest" password="guest111" addresses="YY.YY.YY.YY:5672" cache-mode="CONNECTION" connection-cache-size="50" virtual-host="/" />
<rabbit:template id="rabbitTemplateRmqDest" connection-factory="connectionFactoryRmqDest" />
<int-amqp:outbound-channel-adapter channel="one" id="outboundChannelAdapter1" routing-key="keyMyQueue" exchange-name="direct.exchange" amqp-template="rabbitTemplateRmqDest" default-delivery-mode="PERSISTENT"/>
Logger.java
package com.logger;
public class Logger {
public Message<?> log(Message<?> message) {
System.out.println("*************************************");
throw new AmqpException("Error on channel");
}
}
Log file :
2018-03-12 16:34:43.008 [(inner bean)#160e9f2e-1] ERROR log1 - error occurred in message handler [org.springframework.integration.amqp.outbound.AmqpOutboundEndpoint#0]; nested exception is org.springframework.amqp.AmqpAuthenticationException: com.rabbitmq.client.AuthenticationFailureException: ACCESS_REFUSED - Login was refused using authentication mechanism PLAIN. For details see the broker logfile.
2018-03-12 16:34:43.021 [(inner bean)#160e9f2e-1] ERROR log1 - Message conversion failed
2018-03-12 16:34:45.181 [(inner bean)#160e9f2e-1] ERROR log1 - error occurred in message handler [org.springframework.integration.amqp.outbound.AmqpOutboundEndpoint#0]; nested exception is org.springframework.amqp.AmqpAuthenticationException: com.rabbitmq.client.AuthenticationFailureException: ACCESS_REFUSED - Login was refused using authentication mechanism PLAIN. For details see the broker logfile.
2018-03-12 16:34:45.182 [(inner bean)#160e9f2e-1] ERROR log1 - Message conversion failed
2018-03-12 16:34:49.345 [(inner bean)#160e9f2e-1] ERROR log1 - error occurred in message handler [org.springframework.integration.amqp.outbound.AmqpOutboundEndpoint#0]; nested exception is org.springframework.amqp.AmqpAuthenticationException: com.rabbitmq.client.AuthenticationFailureException: ACCESS_REFUSED - Login was refused using authentication mechanism PLAIN. For details see the broker logfile.
2018-03-12 16:34:49.346 [(inner bean)#160e9f2e-1] ERROR log1 - Message conversion failed
Removing the expression attributes, stack traces are (just one attempt on the 3 retries):
2018-03-12 17:24:03.303 [(inner bean)#76e1e924-1] ERROR log1 - org.springframework.messaging.MessageHandlingException: error occurred in message handler [org.springframework.integration.amqp.outbound.AmqpOutboundEndpoint#0]; nested exception is org.springframework.amqp.AmqpAuthenticationException: com.rabbitmq.client.AuthenticationFailureException: ACCESS_REFUSED - Login was refused using authentication mechanism PLAIN. For details see the broker logfile., failedMessage=GenericMessage [payload=byte[20], headers={timestamp=1520871843104, id=7c9f713f-90a1-2720-60e4-a0e33ef98ecb, amqp_receivedRoutingKey=myqueue, amqp_consumerQueue=myqueue, amqp_consumerTag=amq.ctag-ENdQ-j6xD1LRXDxGr_iJuQ, amqp_receivedDeliveryMode=NON_PERSISTENT, amqp_redelivered=false, amqp_deliveryTag=1}]
at org.springframework.integration.handler.AbstractMessageHandler.handleMessage(AbstractMessageHandler.java:139)
at org.springframework.integration.dispatcher.AbstractDispatcher.tryOptimizedDispatch(AbstractDispatcher.java:116)
at org.springframework.integration.dispatcher.UnicastingDispatcher.doDispatch(UnicastingDispatcher.java:148)
at org.springframework.integration.dispatcher.UnicastingDispatcher.dispatch(UnicastingDispatcher.java:121)
at org.springframework.integration.channel.AbstractSubscribableChannel.doSend(AbstractSubscribableChannel.java:89)
at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:425)
at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:375)
at org.springframework.messaging.core.GenericMessagingTemplate.doSend(GenericMessagingTemplate.java:115)
at org.springframework.messaging.core.GenericMessagingTemplate.doSend(GenericMessagingTemplate.java:45)
at org.springframework.messaging.core.AbstractMessageSendingTemplate.send(AbstractMessageSendingTemplate.java:105)
at org.springframework.integration.endpoint.MessageProducerSupport.sendMessage(MessageProducerSupport.java:188)
at org.springframework.integration.amqp.inbound.AmqpInboundChannelAdapter.access$1100(AmqpInboundChannelAdapter.java:56)
at org.springframework.integration.amqp.inbound.AmqpInboundChannelAdapter$Listener.processMessage(AmqpInboundChannelAdapter.java:246)
at org.springframework.integration.amqp.inbound.AmqpInboundChannelAdapter$Listener.onMessage(AmqpInboundChannelAdapter.java:203)
at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.doInvokeListener(AbstractMessageListenerContainer.java:848)
at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.invokeListener(AbstractMessageListenerContainer.java:771)
at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.access$001(SimpleMessageListenerContainer.java:102)
at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer$1.invokeListener(SimpleMessageListenerContainer.java:198)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:333)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
at org.springframework.retry.interceptor.RetryOperationsInterceptor$1.doWithRetry(RetryOperationsInterceptor.java:74)
at org.springframework.retry.support.RetryTemplate.doExecute(RetryTemplate.java:276)
at org.springframework.retry.support.RetryTemplate.execute(RetryTemplate.java:172)
at org.springframework.retry.interceptor.RetryOperationsInterceptor.invoke(RetryOperationsInterceptor.java:98)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213)
at com.sun.proxy.$Proxy9.invokeListener(Unknown Source)
at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.invokeListener(SimpleMessageListenerContainer.java:1311)
at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.executeListener(AbstractMessageListenerContainer.java:752)
at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.doReceiveAndExecute(SimpleMessageListenerContainer.java:1254)
at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.receiveAndExecute(SimpleMessageListenerContainer.java:1224)
at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.access$1600(SimpleMessageListenerContainer.java:102)
at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer$AsyncMessageProcessingConsumer.run(SimpleMessageListenerContainer.java:1470)
at java.lang.Thread.run(Thread.java:745)
Caused by: org.springframework.amqp.AmqpAuthenticationException: com.rabbitmq.client.AuthenticationFailureException: ACCESS_REFUSED - Login was refused using authentication mechanism PLAIN. For details see the broker logfile.
at org.springframework.amqp.rabbit.support.RabbitExceptionTranslator.convertRabbitAccessException(RabbitExceptionTranslator.java:65)
at org.springframework.amqp.rabbit.connection.AbstractConnectionFactory.createBareConnection(AbstractConnectionFactory.java:368)
at org.springframework.amqp.rabbit.connection.CachingConnectionFactory.createConnection(CachingConnectionFactory.java:603)
at org.springframework.amqp.rabbit.core.RabbitTemplate.doExecute(RabbitTemplate.java:1430)
at org.springframework.amqp.rabbit.core.RabbitTemplate.execute(RabbitTemplate.java:1411)
at org.springframework.amqp.rabbit.core.RabbitTemplate.send(RabbitTemplate.java:712)
at org.springframework.integration.amqp.outbound.AmqpOutboundEndpoint.send(AmqpOutboundEndpoint.java:134)
at org.springframework.integration.amqp.outbound.AmqpOutboundEndpoint.handleRequestMessage(AmqpOutboundEndpoint.java:122)
at org.springframework.integration.handler.AbstractReplyProducingMessageHandler.handleMessageInternal(AbstractReplyProducingMessageHandler.java:109)
at org.springframework.integration.handler.AbstractMessageHandler.handleMessage(AbstractMessageHandler.java:127)
... 38 more
Caused by: com.rabbitmq.client.AuthenticationFailureException: ACCESS_REFUSED - Login was refused using authentication mechanism PLAIN. For details see the broker logfile.
at com.rabbitmq.client.impl.AMQConnection.start(AMQConnection.java:342)
at com.rabbitmq.client.ConnectionFactory.newConnection(ConnectionFactory.java:909)
at com.rabbitmq.client.ConnectionFactory.newConnection(ConnectionFactory.java:859)
at com.rabbitmq.client.ConnectionFactory.newConnection(ConnectionFactory.java:799)
at org.springframework.amqp.rabbit.connection.AbstractConnectionFactory.createBareConnection(AbstractConnectionFactory.java:352)
... 46 more
2018-03-12 17:24:03.314 [(inner bean)#76e1e924-1] ERROR log1 - org.springframework.amqp.rabbit.listener.exception.ListenerExecutionFailedException: Message conversion failed
at org.springframework.integration.amqp.inbound.AmqpInboundChannelAdapter$Listener.onMessage(AmqpInboundChannelAdapter.java:223)
at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.doInvokeListener(AbstractMessageListenerContainer.java:848)
at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.invokeListener(AbstractMessageListenerContainer.java:771)
at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.access$001(SimpleMessageListenerContainer.java:102)
at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer$1.invokeListener(SimpleMessageListenerContainer.java:198)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:333)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
at org.springframework.retry.interceptor.RetryOperationsInterceptor$1.doWithRetry(RetryOperationsInterceptor.java:74)
at org.springframework.retry.support.RetryTemplate.doExecute(RetryTemplate.java:276)
at org.springframework.retry.support.RetryTemplate.execute(RetryTemplate.java:172)
at org.springframework.retry.interceptor.RetryOperationsInterceptor.invoke(RetryOperationsInterceptor.java:98)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213)
at com.sun.proxy.$Proxy9.invokeListener(Unknown Source)
at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.invokeListener(SimpleMessageListenerContainer.java:1311)
at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.executeListener(AbstractMessageListenerContainer.java:752)
at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.doReceiveAndExecute(SimpleMessageListenerContainer.java:1254)
at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.receiveAndExecute(SimpleMessageListenerContainer.java:1224)
at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.access$1600(SimpleMessageListenerContainer.java:102)
at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer$AsyncMessageProcessingConsumer.run(SimpleMessageListenerContainer.java:1470)
at java.lang.Thread.run(Thread.java:745)
Caused by: org.springframework.messaging.MessageHandlingException: nested exception is org.springframework.amqp.AmqpException: Erreur sur le channel, failedMessage=EnhancedErrorMessage [payload=org.springframework.messaging.MessageHandlingException: error occurred in message handler [org.springframework.integration.amqp.outbound.AmqpOutboundEndpoint#0]; nested exception is org.springframework.amqp.AmqpAuthenticationException: com.rabbitmq.client.AuthenticationFailureException: ACCESS_REFUSED - Login was refused using authentication mechanism PLAIN. For details see the broker logfile., failedMessage=GenericMessage [payload=byte[20], headers={timestamp=1520871843104, id=7c9f713f-90a1-2720-60e4-a0e33ef98ecb, amqp_receivedRoutingKey=myqueue, amqp_consumerQueue=myqueue, amqp_consumerTag=amq.ctag-ENdQ-j6xD1LRXDxGr_iJuQ, amqp_receivedDeliveryMode=NON_PERSISTENT, amqp_redelivered=false, amqp_deliveryTag=1}], headers={timestamp=1520871843291, id=dbde6a9f-3c26-086f-53a1-7c98482efcce, amqp_raw_message=(Body:'[B#56360d58(byte[20])' MessageProperties [headers={}, timestamp=null, messageId=null, userId=null, receivedUserId=null, appId=null, clusterId=null, type=null, correlationId=null, correlationIdString=null, replyTo=null, contentType=null, contentEncoding=null, contentLength=0, deliveryMode=null, receivedDeliveryMode=NON_PERSISTENT, expiration=null, priority=null, redelivered=false, receivedExchange=, receivedRoutingKey=myqueue, receivedDelay=null, deliveryTag=1, messageCount=0, consumerTag=amq.ctag-ENdQ-j6xD1LRXDxGr_iJuQ, consumerQueue=myqueue])}] for original GenericMessage [payload=byte[20], headers={timestamp=1520871843104, id=7c9f713f-90a1-2720-60e4-a0e33ef98ecb, amqp_receivedRoutingKey=myqueue, amqp_consumerQueue=myqueue, amqp_consumerTag=amq.ctag-ENdQ-j6xD1LRXDxGr_iJuQ, amqp_receivedDeliveryMode=NON_PERSISTENT, amqp_redelivered=false, amqp_deliveryTag=1}]
at org.springframework.integration.handler.MethodInvokingMessageProcessor.processMessage(MethodInvokingMessageProcessor.java:96)
at org.springframework.integration.handler.ServiceActivatingHandler.handleRequestMessage(ServiceActivatingHandler.java:89)
at org.springframework.integration.handler.AbstractReplyProducingMessageHandler.handleMessageInternal(AbstractReplyProducingMessageHandler.java:109)
at org.springframework.integration.handler.AbstractMessageHandler.handleMessage(AbstractMessageHandler.java:127)
at org.springframework.integration.dispatcher.BroadcastingDispatcher.invokeHandler(BroadcastingDispatcher.java:236)
at org.springframework.integration.dispatcher.BroadcastingDispatcher.dispatch(BroadcastingDispatcher.java:185)
at org.springframework.integration.channel.AbstractSubscribableChannel.doSend(AbstractSubscribableChannel.java:89)
at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:425)
at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:375)
at org.springframework.messaging.core.GenericMessagingTemplate.doSend(GenericMessagingTemplate.java:115)
at org.springframework.messaging.core.GenericMessagingTemplate.doSend(GenericMessagingTemplate.java:45)
at org.springframework.messaging.core.AbstractMessageSendingTemplate.send(AbstractMessageSendingTemplate.java:105)
at org.springframework.integration.endpoint.MessageProducerSupport.sendErrorMessageIfNecessary(MessageProducerSupport.java:207)
at org.springframework.integration.endpoint.MessageProducerSupport.sendMessage(MessageProducerSupport.java:191)
at org.springframework.integration.amqp.inbound.AmqpInboundChannelAdapter.access$1100(AmqpInboundChannelAdapter.java:56)
at org.springframework.integration.amqp.inbound.AmqpInboundChannelAdapter$Listener.processMessage(AmqpInboundChannelAdapter.java:246)
at org.springframework.integration.amqp.inbound.AmqpInboundChannelAdapter$Listener.onMessage(AmqpInboundChannelAdapter.java:203)
... 25 more
Caused by: org.springframework.amqp.AmqpException: Erreur sur le channel
at com.logger.Logger.log(Logger.java:36)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.springframework.expression.spel.support.ReflectiveMethodExecutor.execute(ReflectiveMethodExecutor.java:117)
at org.springframework.expression.spel.ast.MethodReference.getValueInternal(MethodReference.java:129)
at org.springframework.expression.spel.ast.MethodReference.access$000(MethodReference.java:49)
at org.springframework.expression.spel.ast.MethodReference$MethodValueRef.getValue(MethodReference.java:347)
at org.springframework.expression.spel.ast.CompoundExpression.getValueInternal(CompoundExpression.java:88)
at org.springframework.expression.spel.ast.SpelNodeImpl.getTypedValue(SpelNodeImpl.java:132)
at org.springframework.expression.spel.standard.SpelExpression.getValue(SpelExpression.java:360)
at org.springframework.integration.util.AbstractExpressionEvaluator.evaluateExpression(AbstractExpressionEvaluator.java:169)
at org.springframework.integration.util.MessagingMethodInvokerHelper.processInternal(MessagingMethodInvokerHelper.java:319)
at org.springframework.integration.util.MessagingMethodInvokerHelper.process(MessagingMethodInvokerHelper.java:155)
at org.springframework.integration.handler.MethodInvokingMessageProcessor.processMessage(MethodInvokingMessageProcessor.java:93)
... 41 more
In the log file i have 3 attemps for transfer the message. => Retry is ok
I would like to have only one stacktrace? What the mean of the "Message conversion failed"? How can i prevent it?
Is there a way to test if the cause of an exception is empty or null? I would like to use "payload.cause.message" in the expression?
Thanks for your help,
Regards
Eric
The first log message comes from the <int:logging-channel-adapter> just because you use an error-channel="processChannel1" on the <int-amqp:outbound-channel-adapter>.
The second one comes from the AbstractMessageListenerContainer because your Logger doesn't log message, but does exactly this:
throw new AmqpException("Error on channel");
So, when we do in the AmqpInboundChannelAdapter.Listener this:
getMessagingTemplate().send(getErrorChannel(), buildErrorMessage(null,
new ListenerExecutionFailedException("Message conversion failed", e, message)));
Send error message to the error channel, you just re-throw an exception from the to the top-level AMQP listener and that one logs it one more time.
You should consider do not re-throw an exception from your Logger component, or don't use use one more <int:logging-channel-adapter> subscriber, or just don't use error-channel approach at all!
For the payload.cause.message expression you should use a SpEL ternary operator : payload.cause != null ? payload.cause.message : payload.message
UPDATE
OK. I see what's going on.
We send an exception to the errorChannel during MessageProducerSupport.sendMessage() process:
try {
this.messagingTemplate.send(getOutputChannel(), message);
}
catch (RuntimeException e) {
if (!sendErrorMessageIfNecessary(message, e)) {
throw e;
}
}
And since you have one more subscriber to throw a fresh exception (or just re-throw), that sendErrorMessageIfNecessary() finishes with a bubbled exception.
This one come to the catch (RuntimeException e) { of the AmqpInboundChannelAdapter.Listener.onMessage() like mentioned before. And a new ErrorMessage is sent to the errorChannel. That's how you see that one more logged message. But since the second subscriber re-throws an exception, that's how it comes back to the listener container and initiate retries. And that's how you see a stack trace only once, after all the retry attempts. However I can guess that it is already a wrong stack trace, because you would like to see the real reason of the sending to the AMQP problem.
What I suggest here for you as a solution is like this:
No error-channel on the <int-amqp:inbound-channel-adapter>
No second subscriber to the processChannel1 - the existing <int:logging-channel-adapter> is enough.
You configure ExpressionEvaluatingRequestHandlerAdvice with the failureChannel to the processChannel1 and onFailureExpression to the #this
Use this ExpressionEvaluatingRequestHandlerAdvice as a <request-handler-advice-chain> reference for the <int-amqp:outbound-channel-adapter>
This way you'll get logs on each retry and according the trapException = false, a real exception will be re-thrown to the listener cotnainer for retry.
I tried to download files using the following code:
<int-sftp:inbound-channel-adapter id="sftpInbondAdapter"
auto-startup="true" channel="receiveChannel" session-factory="sftpSessionFactory"
local-directory="file:${directory.files.local}" remote-directory="${directory.files.remote}"
auto-create-local-directory="true" delete-remote-files="true"
filename-pattern="*.txt">
<int:poller fixed-delay="${sftp.interval.request}"
max-messages-per-poll="-1" error-channel="sftp.in.error.channel" />
</int-sftp:inbound-channel-adapter>
<bean id="defaultSftpSessionFactory"
class="org.springframework.integration.sftp.session.DefaultSftpSessionFactory">
<property name="host" value="${sftp.host}" />
<property name="port" value="${sftp.port}" />
<property name="user" value="${user}" />
<property name="password" value="${password}" />
<property name="allowUnknownKeys" value="true" />
</bean>
I'm sure that the user is authorized because i tried it with shell:
sftp user#x.x.x.x
then i write the password and the download succeed with "get".
but i can't download files, the error is:
DEBUG LOG:
jsch:52 - Authentications that can continue: gssapi-with-mic,publickey,keyboard-interactive,password
2016-02-02 07:54:04 INFO jsch:52 - Next authentication method: gssapi-with-mic
2016-02-02 07:54:04 INFO jsch:52 - Authentications that can continue: publickey,keyboard-interactive,password
2016-02-02 07:54:04 INFO jsch:52 - Next authentication method: publickey
2016-02-02 07:54:04 INFO jsch:52 - Authentications that can continue: password
2016-02-02 07:54:04 INFO jsch:52 - Next authentication method: password
2016-02-02 07:54:04 INFO jsch:52 - Authentication succeeded (password).
2016-02-02 07:54:05 DEBUG SimplePool:190 - Obtained new org.springframework.integration.sftp.session.SftpSession#39c9c99a.
2016-02-02 07:54:05 DEBUG CachingSessionFactory:187 - Releasing Session org.springframework.integration.sftp.session.SftpSession#39c9c99a back to the pool.
2016-02-02 07:54:05 INFO jsch:52 - Disconnecting from x.x.x.x port 22
I would enable DEBUG logging for jsch as well as org.springframework.integration.
That last message is coming from this code...
#Override
public boolean promptYesNo(String message) {
logger.info(message); // <<<<<<<<< INFO message in your log line 538
if (hasDelegate()) {
return getDelegate().promptYesNo(message);
}
else {
if (logger.isDebugEnabled()) {
logger.debug("No UserInfo provided - " + message + ", returning:"
+ DefaultSftpSessionFactory.this.allowUnknownKeys);
}
return DefaultSftpSessionFactory.this.allowUnknownKeys;
}
}
Since you have not provided a delegate UserInfo (according to your configuration in the question), it should return true (because you have allowUnknownKeys set to true).
If you can't figure it out; edit your question with the appropriate part of the log.
EDIT
You removed the most useful part of the log you posted on your first edit:
2016-02-01 18:28:27 DEBUG DefaultSftpSessionFactory:544 - No UserInfo provided - The authenticity of host '192.168.21.36' can't be established.
RSA key fingerprint is 98:1d:7e:73:77:97:f6:af:f9:2a:fc:2b:21:8e:8e:bf.
Are you sure you want to continue connecting?, returning:false
"Returning:false" means that the allowUnknownKeys property is false, not true as you show in your configuration. Perhaps you have another session factory bean that's overriding this one?
Spring Integration and Spring Integration AMQP.
I have the following code:
<bean id="allHeadersMapper" class="org.springframework.integration.amqp.support.DefaultAmqpHeaderMapper">
<property name="requestHeaderNames" value="*" />
<property name="replyHeaderNames" value="*" />
</bean>
<int-amqp:inbound-channel-adapter channel="ResponseChannel" queue-names="OutputQueue" connection-factory="amqpConnectionFactory" error-channel="274ErrorChannel" header-mapper="allHeadersMapper" />
I am converting the EDI message to JSON and Placing in "OutputQueue" . While I try to Read the mesage from OutputQueue and Place in Channel, I try to map all standard and non Standard Header.
Eg.
[payload={abcPayload}, headers={amqp_consumerQueue=OutputQueue, amqp_receivedExchange=XExchange, VERSION_ID=1.0, amqp_contentEncoding=UTF-8, contentType=text/plain, amqp_redelivered=true, STATUS=ABC, timestamp=1432235031343, id=793599d5-6236-c6a1-717e-4f85f9cd9f7b, history=JSONChannel,ResponseLogging,FilterChannel1, amqp_receivedRoutingKey=OutputQueueKey, MESSAGE_ID=MESSAGE_ID, amqp_deliveryMode=NON_PERSISTENT, RECORD_ID=RECORD_ID, amqp_consumerTag=amq.ctag-7jyApLDNT5s_HbxOU8gkPQ, FLOW_NAME=BCD, amqp_deliveryTag=1}]
I am getting the Exception:
Incorrect type specified for header 'history'. Expected [class org.springframework.integration.history.MessageHistory] but actual type is [class java.util.ArrayList]
I have the following exception:
INFO 2015-01-19 11:00:00 [AbstractCorrelatingMessageHandler] - Expiring MessageGroup with correlationKey[aa7eb738-b47e-3bbe-8aca-282453ae5b29]
ERROR 2015-01-19 11:00:00 [JdbcMessageStore] - Exception in expiry callback
org.springframework.integration.MessageDeliveryException: Dispatcher has no subscribers for channel 'org.springframework.context.support.ClassPathXmlApplicationContext#19e0ff2f.SIEBELDOC_PARK_after_aggregation'.
at org.springframework.integration.channel.AbstractSubscribableChannel.doSend(AbstractSubscribableChannel.java:81)
at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:181)
at org.springframework.integration.core.MessagingTemplate.doSend(MessagingTemplate.java:330)
at org.springframework.integration.core.MessagingTemplate.send(MessagingTemplate.java:169)
at org.springframework.integration.aggregator.AbstractCorrelatingMessageHandler.sendReplyMessage(AbstractCorrelatingMessageHandler.java:436)
at org.springframework.integration.aggregator.AbstractCorrelatingMessageHandler.sendReplies(AbstractCorrelatingMessageHandler.java:429)
at org.springframework.integration.aggregator.AbstractCorrelatingMessageHandler.completeGroup(AbstractCorrelatingMessageHandler.java:404)
at org.springframework.integration.aggregator.AbstractCorrelatingMessageHandler.completeGroup(AbstractCorrelatingMessageHandler.java:389)
at org.springframework.integration.aggregator.AbstractCorrelatingMessageHandler.expireGroup(AbstractCorrelatingMessageHandler.java:371)
at org.springframework.integration.aggregator.AbstractCorrelatingMessageHandler.forceComplete(AbstractCorrelatingMessageHandler.java:308)
at org.springframework.integration.aggregator.AbstractCorrelatingMessageHandler.access$000(AbstractCorrelatingMessageHandler.java:71)
at org.springframework.integration.aggregator.AbstractCorrelatingMessageHandler$1.execute(AbstractCorrelatingMessageHandler.java:137)
at org.springframework.integration.store.AbstractMessageGroupStore.expire(AbstractMessageGroupStore.java:117)
at org.springframework.integration.store.AbstractMessageGroupStore.expireMessageGroups(AbstractMessageGroupStore.java:87)
at org.springframework.integration.store.MessageGroupStoreReaper.run(MessageGroupStoreReaper.java:115)
at sun.reflect.GeneratedMethodAccessor58.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:64)
at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:53)
at org.springframework.scheduling.concurrent.ReschedulingRunnable.run(ReschedulingRunnable.java:81)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:441)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
at java.util.concurrent.FutureTask.run(FutureTask.java:138)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:98)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:206)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:662)
That's the flow:
<int:channel id="SIEBELDOC_PARK_job_Channel"/>
<int:channel id="SIEBELDOC_PARK_after_split"/>
<int:channel id="SIEBELDOC_PARK_after_aggregation"/>
<int:inbound-channel-adapter channel="SIEBELDOC_PARK_job_Channel" expression="#parkingGetItems.getItems('SIEBELDOC_PARK')">
<int:poller fixed-rate="${fdl.db.item.polling.rate}"/>
</int:inbound-channel-adapter>
<int:splitter input-channel="SIEBELDOC_PARK_job_Channel" output-channel="SIEBELDOC_PARK_after_split"/>
<int:aggregator input-channel="SIEBELDOC_PARK_after_split" output-channel="SIEBELDOC_PARK_after_aggregation" message-store="SIEBELDOC_PARK_messageStore"
ref="parkingStackMessageAggregator" method="aggregate"
correlation-strategy="parkingStackMessageAggregator"
correlation-strategy-method="correlate"
release-strategy="parkingStackMessageAggregator"
release-strategy-method="release"
send-partial-result-on-expiry="true"
expire-groups-upon-completion="true"
>
</int:aggregator>
<int:chain id="jobexecutor" input-channel="SIEBELDOC_PARK_after_aggregation" >
<int:transformer>
<bean class="hu.telekom.fdl.job.IntegrationMessageToJobRequest"/>
</int:transformer>
<int:service-activator>
<bean class = "hu.telekom.fdl.job.JobLaunchMessageHandler"/>
</int:service-activator>
</int:chain>
I'm using the following reaper and messagestore code:
<int-jdbc:message-store id="SIEBELDOC_PARK_messageStore" region="SIEBELDOC_PARK_GRP" data-source="jobRepoDataSource" table-prefix="INT_" lob-handler="lobHandler"/>
<bean id="SIEBELDOC_PARK_messageStoreReaper" class="org.springframework.integration.store.MessageGroupStoreReaper">
<property name="messageGroupStore" ref="SIEBELDOC_PARK_messageStore" />
<property name="timeout" value="100000" />
</bean>
<task:scheduled-tasks>
<task:scheduled ref="SIEBELDOC_PARK_messageStoreReaper" method="run" cron="* */30 * * * ?"/>
</task:scheduled-tasks>
Can you give me advices what could be the problem?
Thanks,
For me the channel name: org.springframework.context.support.ClassPathXmlApplicationContext#19e0ff2f.SIEBELDOC_PARK_after_aggregation is also strange for me.
The original channel name is: SIEBELDOC_PARK_after_aggregation which is not the same as the channel name referred in the stacktracce.
Ferenc
org.springframework.context.support.ClassPathXmlApplicationContext#19e0ff2f.SIEBELDOC_PARK_after_aggregation is a result of AbstractMessageChannel#getFullChannelName(). As you see we include there an ApplicationContext id.
I may guess, but would be better if you remove that jobexecutor id from the <chain>. There might be another bean in the ctx with the same id. No ?
How does it work if you just send messages to the aggregator for regular releasing? Don't you see the same MessageDeliveryException ?
I am converting each incoming message to a file and uploading to SFTP server.
I get huge exception stack trace logs when SFTP is not available during file upload. This happens every incoming message. Just wondering is there any cleaner solution, where I can catch these exceptions and log a custom message using my CONFIGURED LOGGER ?
<bean id="sftpSessionFactory" class="org.springframework.integration.sftp.session.DefaultSftpSessionFactory">
<property name="host" value="${ftp.host}"></property>
<property name="port" value="22" />
<property name="user" value="${ftp.username}"></property>
<property name="password" value="${ftp.password}"></property>
<property name="timeout" value="2000"></property>
</bean>
<int:publish-subscribe-channel id="sftpChannel"></int:publish-subscribe-channel>
<sftp:outbound-channel-adapter id="sftpOutboundAdapter" auto-create-directory="true" session-factory="sftpSessionFactory" channel="sftpChannel" charset="UTF-8" remote-directory="${ftp.path}" remote-filename-generator-expression="headers[fileName] + '.xml'">
<sftp:request-handler-advice-chain>
<bean class="org.springframework.integration.handler.advice.ExpressionEvaluatingRequestHandlerAdvice">
<property name="onSuccessExpression" value="payload.delete()" />
</bean>
</sftp:request-handler-advice-chain>
</sftp:outbound-channel-adapter>
I have modified the config as below :
<int:publish-subscribe-channel id="sftpChannel"></int:publish-subscribe-channel>
<sftp:outbound-channel-adapter id="sftpOutboundAdapter" auto-create-directory="true" session-factory="sftpSessionFactory" channel="sftpChannel" charset="UTF-8" remote-directory="${spectrum.ftp.path}" remote-filename-generator-expression="headers[fileName] + '.xml'">
<sftp:request-handler-advice-chain>
<bean class="org.springframework.integration.handler.advice.ExpressionEvaluatingRequestHandlerAdvice">
<property name="onSuccessExpression" value="payload.delete()" />
<property name="failureChannel" ref="errorChannel" />
</bean>
</sftp:request-handler-advice-chain>
</sftp:outbound-channel-adapter>
I send this file using :
outputChannel = context.getBean("sftpChannel", org.springframework.integration.MessageChannel.class);
line#120-> if (outputChannel.send(payload)) {
ptsoLog.info("Successfully uploaded file : " + fileName + ".xml");
}else{
ptsoLog.error("File upload failed : " + e.getMessage());
}
but still get this exception :
org.springframework.integration.MessagingException: Failed to execute on session
at org.springframework.integration.file.remote.RemoteFileTemplate.execute(RemoteFileTemplate.java:306) ~[spring-integration-file-3.0.5.RELEASE.jar:na]
at org.springframework.integration.file.remote.RemoteFileTemplate.send(RemoteFileTemplate.java:190) ~[spring-integration-file-3.0.5.RELEASE.jar:na]
at org.springframework.integration.file.remote.RemoteFileTemplate.send(RemoteFileTemplate.java:182) ~[spring-integration-file-3.0.5.RELEASE.jar:na]
at org.springframework.integration.file.remote.handler.FileTransferringMessageHandler.handleMessageInternal(FileTransferringMessageHandler.java:112) ~[spring-integration-file-3.0.5.RELEASE.jar:na]
at org.springframework.integration.handler.AbstractMessageHandler.handleMessage(AbstractMessageHandler.java:73) ~[spring-integration-core-3.0.5.RELEASE.jar:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.6.0_30]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) ~[na:1.6.0_30]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) ~[na:1.6.0_30]
at java.lang.reflect.Method.invoke(Method.java:597) ~[na:1.6.0_30]
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:317) ~[spring-aop-3.2.4.RELEASE.jar:3.2.4.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:183) ~[spring-aop-3.2.4.RELEASE.jar:3.2.4.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150) ~[spring-aop-3.2.4.RELEASE.jar:3.2.4.RELEASE]
at org.springframework.integration.handler.advice.AbstractRequestHandlerAdvice$1.execute(AbstractRequestHandlerAdvice.java:72) ~[spring-integration-core-3.0.5.RELEASE.jar:na]
at org.springframework.integration.handler.advice.ExpressionEvaluatingRequestHandlerAdvice.doInvoke(ExpressionEvaluatingRequestHandlerAdvice.java:115) ~[spring-integration-core-3.0.5.RELEASE.jar:na]
at org.springframework.integration.handler.advice.AbstractRequestHandlerAdvice.invoke(AbstractRequestHandlerAdvice.java:68) ~[spring-integration-core-3.0.5.RELEASE.jar:na]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172) ~[spring-aop-3.2.4.RELEASE.jar:3.2.4.RELEASE]
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204) ~[spring-aop-3.2.4.RELEASE.jar:3.2.4.RELEASE]
at $Proxy27.handleMessage(Unknown Source) ~[na:na]
at org.springframework.integration.dispatcher.BroadcastingDispatcher.invokeHandler(BroadcastingDispatcher.java:141) ~[spring-integration-core-3.0.5.RELEASE.jar:na]
at org.springframework.integration.dispatcher.BroadcastingDispatcher.dispatch(BroadcastingDispatcher.java:123) ~[spring-integration-core-3.0.5.RELEASE.jar:na]
at org.springframework.integration.channel.AbstractSubscribableChannel.doSend(AbstractSubscribableChannel.java:77) ~[spring-integration-core-3.0.5.RELEASE.jar:na]
at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:178) ~[spring-integration-core-3.0.5.RELEASE.jar:na]
at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:149) ~[spring-integration-core-3.0.5.RELEASE.jar:na]
at com.xx.xx.xxx.outputMessage(xxxOutputter.java:120) ~[src/:na]
Caused by: java.lang.IllegalStateException: failed to create SFTP Session
at org.springframework.integration.sftp.session.DefaultSftpSessionFactory.getSession(DefaultSftpSessionFactory.java:321) ~[spring-integration-sftp-3.0.5.RELEASE.jar:na]
at org.springframework.integration.file.remote.RemoteFileTemplate.execute(RemoteFileTemplate.java:295) ~[spring-integration-file-3.0.5.RELEASE.jar:na]
... 48 common frames omitted
Caused by: java.lang.IllegalStateException: failed to connect
at org.springframework.integration.sftp.session.SftpSession.connect(SftpSession.java:250) ~[spring-integration-sftp-3.0.5.RELEASE.jar:na]
at org.springframework.integration.sftp.session.DefaultSftpSessionFactory.getSession(DefaultSftpSessionFactory.java:316) ~[spring-integration-sftp-3.0.5.RELEASE.jar:na]
... 49 common frames omitted
Caused by: com.jcraft.jsch.JSchException: timeout: socket is not established
at com.jcraft.jsch.Util.createSocket(Util.java:394) ~[jsch-0.1.51.jar:na]
at com.jcraft.jsch.Session.connect(Session.java:215) ~[jsch-0.1.51.jar:na]
at com.jcraft.jsch.Session.connect(Session.java:183) ~[jsch-0.1.51.jar:na]
at org.springframework.integration.sftp.session.SftpSession.connect(SftpSession.java:241) ~[spring-integration-sftp-3.0.5.RELEASE.jar:na]
... 50 common frames omitted
Caused by: java.lang.IllegalStateException: failed to create SFTP Session
at org.springframework.integration.sftp.session.DefaultSftpSessionFactory.getSession(DefaultSftpSessionFactory.java:321) ~[spring-integration-sftp-3.0.5.RELEASE.jar:na]
at org.springframework.integration.file.remote.RemoteFileTemplate.execute(RemoteFileTemplate.java:295) ~[spring-integration-file-3.0.5.RELEASE.jar:na]
... 47 common frames omitted
Caused by: java.lang.IllegalStateException: failed to connect
at org.springframework.integration.sftp.session.SftpSession.connect(SftpSession.java:250) ~[spring-integration-sftp-3.0.5.RELEASE.jar:na]
at org.springframework.integration.sftp.session.DefaultSftpSessionFactory.getSession(DefaultSftpSessionFactory.java:316) ~[spring-integration-sftp-3.0.5.RELEASE.jar:na]
... 48 common frames omitted
Caused by: com.jcraft.jsch.JSchException: timeout: socket is not established
at com.jcraft.jsch.Util.createSocket(Util.java:394) ~[jsch-0.1.51.jar:na]
at com.jcraft.jsch.Session.connect(Session.java:215) ~[jsch-0.1.51.jar:na]
at com.jcraft.jsch.Session.connect(Session.java:183) ~[jsch-0.1.51.jar:na]
at org.springframework.integration.sftp.session.SftpSession.connect(SftpSession.java:241) ~[spring-integration-sftp-3.0.5.RELEASE.jar:na]
... 49 common frames omitted
Since you already use ExpressionEvaluatingRequestHandlerAdvice, you can specify the second onFailureExpression option alongside with failureChannel to send an ErrorMessage with the Exception to another channel and do some transformation and logging in that flow.
UPDATE
Thank you for so wide info around an issue.
So, as we see by the StackTrace the ExpressionEvaluatingRequestHandlerAdvice is there too.
And what I can say by source code of it, that it sends an ErrorMessage to the failureChannel only if you specify onFailureExpression. (#root) should be enough for you.
And there is one more option - trapException = true if you want to suppress that exception for rethrowing to the caller.