Spring integration: propagate headers to 'errorChannel' - spring-integration

Is there a way to configure Spring Integration channels such that in case of uncaught exceptions, the headers at the time of exception (if available) are published to the errorChannel along with the exception object?
Right now, I can subscribe to the 'errorChannel' and adds handling code there which is extremely useful. But in errorChannel, I can only get the exception; headers from the original channel are lost. I tried looking at the reference here (https://docs.spring.io/spring-integration/reference/htmlsingle/#namespace-errorhandler) but no luck.

The ErrorMessage payload is a MessagingException with 2 properties cause and failedMessage. The headers are available on the latter.

Related

http retry advice not retrying when an exception is thrown

I have service activator method which throws database exception, I am catching that exception and sending ResponseEntity to the output channel. I have retry advice configured on the service activator but its doesn't retry(I am assuming its because I am catching it and sending custom exception to the output channel), I want it to retry 4 times first and then send custom exception. can you please how can I achieve it?
<int:chain id="a1-chain" input-channel="dRequestInputChannel" output-channel="dIntermediateChannel">
<int:service-activator ref="dAdapterController" method="dPersist">
<int:request-handler-advice-chain>
<int:retry-advice max-attempts="4" recovery-channel="dRetryChannel">
<int:exponential-back-off initial="1000" multiplier="5.0" maximum="60000" />
</int:retry-advice>
</int:request-handler-advice-chain>
</int:service-activator>
</int:chain>
<int:transformer input-channel="dRetryChannel" expression="payload.getFailedMessage()"/>
There is some piece of code after this in which I have a chain which has input channel as dIntermediateChannel and one router etc. which works fine! I meant to say flow works fine without retrying!
You said it yourself:
I am catching that exception and sending ResponseEntity to the output channel.
It is not clear what made you think that retry has to work in this case: if not exception is thrown from the user code, then nothing to catch in the retry interceptor and therefore no trigger to initiate retry policy.
Please, don't confuse yourself and us. We don't know what is your code, but your say:
then send custom exception
So, send it is a part of ResponseEntity or throw?
I would say in the first case it is just custom reply and doesn't matter what is its body. As long as it does not cause throws it is not an exception to catch.
If you want a retry and then fallback, so take a look into a logic where you don't catch exception yourself, but let it to be done by the retry-advice.
To make a custom reply, you need to look into a RecoveryCallback injected into a RequestHandlerRetryAdvice. Unfortunately, that int:retry-advice does not expose RecoveryCallback. An existing recovery-channel does not expect a reply to be produced from the publishing.
Another way is to use an ExpressionEvaluatingRequestHandlerAdvice around this retry to catch the final exception and produce some compensation.

Add SoapHeader to a Spring WS Endpoint

I have a spring ws endpoint as part of a Spring Integration project and I would like to access the Soap Header. When I add the SoapHeader to the method parameters i get the following exception:
[10/05/16 05:00:05:005 PDT] localhost-startStop-1 DEBUG
springframework.integration.util.MessagingMethodInvokerHelper.doWith():
Method [public
com.bstonetech.ptms.integration.model.ws.external.contract.GetContractResponse
com.bstonetech.ptms.integration.service.ws.GetContractEndpoint.getContract(com.bstonetech.ptms.integration.model.ws.external.contract.GetContractRequest,org.springframework.ws.context.MessageContext)
throws java.lang.Exception] is not eligible for Message handling Found
more than one parameter type candidate:
[#org.springframework.ws.server.endpoint.annotation.RequestPayload
com.bstonetech.ptms.integration.model.ws.external.contract.GetContractRequest]
and [org.springframework.ws.context.MessageContext]. [10/05/16
05:00:05:005 PDT] localhost-startStop-1 WARN
web.context.support.XmlWebApplicationContext.refresh(): Exception
encountered during context initialization - cancelling refresh attempt
java.lang.IllegalArgumentException: Target object of type [class
com.bstonetech.ptms.integration.service.ws.GetContractEndpoint] has no
eligible methods for handling Messages.
The same error occurs when using MessageContext messageContext too.
I am obviously missing something. Any help would be appreciated.
Integration is as follows:
<oxm:jaxb2-marshaller id="contractMarshaller" context-path="com.bstonetech.ptms.integration.model.ws.external.contract"/>
<ws:inbound-gateway id="getContractWs" request-channel="inboundGetContractChannel" mapped-request-headers="fileId" mapped-reply-headers="fileId"
marshaller="contractMarshaller" unmarshaller="contractMarshaller"/>
<int:service-activator id="contractEndpoint" input-channel="inboundGetContractChannel" ref="getContractEndpoint"/>
The endpoint looks as follows:
#Endpoint
public class GetContractEndpoint {
private static final String NAMESPACE_URI = "http://bstonetech.com/contract";
#PayloadRoot(namespace = NAMESPACE_URI, localPart = "GetContractRequest")
#ResponsePayload
public GetContractResponse getContract(#RequestPayload GetContractRequest request, SoapHeader soapHeader) throws Exception {
.....
}
Sorry for delay. We were busy with Spring Integration 4.3.0.RC1 release :-).
Well, looks like you have missed something and therefore ended up with the mix of concerns.
The Spring WS POJO method invocation annotations (#RequestPayload, #PayloadRoot) and SOAP-specific argument injection is really for the POJO case, when you have #Endpoint on the service and rely on the #EnableWs or similar Spring WS mechanism.
On the other hand, right, Spring Integration WS module is fully based on the Spring WS project, but it aims to convert everything into Spring Integration Messaging model as fast as possible. Therefore a result of the <ws:inbound-gateway> is Message sent to the request-channel="inboundGetContractChannel". In your case the payload will be already unmarshalled to some your domain object according to the JaxB mapping.
The <service-activator> can now deal only with the Messaging infrastructure and it already know nothing about SOAP. That is the general purpose of the Messaging, when you can switch to fully different source (e.g. DB), but still use the same <service-activator>.
To meet some POJO method invocation there are useful annotations like #Payload #Header etc.
To be consistent and still provide some SOAP info, the AbstractWebServiceInboundGateway consults with the DefaultSoapHeaderMapper and extract source.getSoapHeader() state as a separate MessageHeaders. So, you still have access to desired headers from request.

Why is exception is not thrown to the error-channel of the inbound when claim-check is used

In the error-channel attribute of message-driven-channel-adapter
I want the original inbound message as the payload not the payload at the point of failure. To achieve this I use claim-check-in/out and SimpleMessageStore. The UUID I get from claim-check-in is stored in the header of the original inbound message. This message is now consumed by the transformer and then webservice call.
When the service time out or transformation exception is thrown the error-channel of message-driven-channel-adapter does not get any message, also it seems to retry in its own infinite loop rather than throwing an exception to error-channel. Is this the expected behaviour, Please let me know if I am missing something.

Can I somehow get a backtrace of a message in Spring Integration?

When, for example, an exception occurres in the middle of a spring integration flow, is there any way to get a path the message have traveled before the crash happend?
The message tracks its path only if #EnableMessageHistory is switched on.
Independently of error handling, Spring Integration always wraps any exception to the MessagingException which has failedMessage property.
Getting that message and analizing its MessageHistory.HEADER_NAME you get the path before an exception.

How to rollback message taken from IBM MQ in spring integration

I have a spring integration flow like this:
1) message-driven-channel-adapter ->
1.1) output-channel connected to -> service-activator -> outbound-channel-adapter (for sending response)
1.2) error-channel connected to -> exception-type-router
1.2.1) message is sent to different queues depending on the exception type using outbound-channel-adapter
I have set acknowledge="transacted" in message-driven-channel-adapter. I want to introduce rollback for a specific type of exception, after error-channel.
First, I tried to connect the exception-type-router output to service-activator. But i get exception:
Code:
<service-activator id="rollBackActivator" input-channel="RollBackChannel"
ref="errorTransformer" method="rollBackMessage"/>
public void rollBackMessage(MessagingException message){
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
System.out.println("Message rolled back:"+TransactionAspectSupport.currentTransactionStatus().isRollbackOnly());
}
Exception:
org.springframework.messaging.MessageHandlingException: org.springframework.transaction.NoTransactionException: No transaction aspect-managed TransactionStatus in scope
Then, I tried with outbound-channel-adapter expression , But got another exception again
Code:
<outbound-channel-adapter id="rollbackOut" channel="RollBackChannel"
expression="T(org.springframework.transaction.interceptor.TransactionAspectSupport).currentTransactionStatus().setRollbackOnly()"/>
Exception:
org.springframework.messaging.MessageHandlingException: Expression evaluation failed: T(org.springframework.transaction.interceptor.TransactionAspectSupport).currentTransactionStatus().setRollbackOnly()
Please advise to implement rollback in this scenario.
The container uses local transactions on the session by default. There's no AOP involved. Simply throw an exception and the container will roll back the message.

Resources