Spring integration http:inbound-channel-adapter error-channel - spring

I recently update from Spring Integration 4.1.3 to 4.2.6 and noticed that I started getting a 500 response from an http:inbound-gateway.
Upon investigation this was due to an empty reply and the gateway interpreting this as a timeout in MessagingGatewaySupport
if (reply == null && this.errorOnTimeout) {
This makes sense so I changed this to an http:inbound-channel-adapter and it solves this problem, but then the error handling doesn't behave as expected.
I previously had and error-channel on the gateway with
<int-http:inbound-gateway id="inboundGateway" request-channel="httpInChannel" reply-channel="httpResponseChannel" path="/**/status*" supported-methods="POST" error-channel="httpErrorChannel"/>
<int:chain input-channel="httpInChannel" output-channel="serviceChannel">
...
</int:chain>
<int:chain input-channel="httpErrorChannel">
<int:header-enricher>
<int:header name="http_statusCode" value="500" />
</int:header-enricher>
<int:transformer expression="payload.localizedMessage" />
</int:chain>
<int:service-activator input-channel="serviceChannel" ref="someController" method="someVoidMethod"/>
I suspected it may not work but I modified this slightly to
<int-http:inbound-channel-adapter id="inboundAdapter" channel="httpInChannel" path="/**/status*" supported-methods="POST" error-channel="httpErrorChannel"/>
<int:chain input-channel="httpInChannel" output-channel="serviceChannel">
...
</int:chain>
<int:chain input-channel="httpErrorChannel">
<int:header-enricher>
<int:header name="http_statusCode" value="500" />
</int:header-enricher>
<int:transformer expression="payload.localizedMessage" />
</int:chain>
<int:service-activator input-channel="serviceChannel" ref="someController" method="someVoidMethod"/>
Now, it works fine for a normal valid POST request, but if I send an invalid message that errors I get a 500 response with full error stack in response (have tried changing the status code in the header enricher too). The error is
org.springframework.messaging.core.DestinationResolutionException: no output-channel or replyChannel header available
which makes sense as the error-channel does not have an output (although it doesn't in the docs either http://docs.spring.io/spring-integration/docs/4.3.0.RELEASE/reference/htmlsingle/#http-response-statuscode).
Is there a way to change the error response for the inbound adapter in a similar way to that of the gateway?

I think it's a bug, please open a JIRA Issue.
As a work around, in the main flow, just after the adapter, add a mid-flow gateway...
<int:service-activator ref="gw" input-channel="httpInChannel" >
<int:gateway id="gw" error-channel="httpErrorChannel"
default-request-channel="nextChannelInMainFlow" default-reply-timeout="0" />
The gateway is like a try/catch block around the flow.
The reply timeout is important since you do not expect a reply.

Related

Spring Integration outbound gateway with poller

Below is outbound http gateway configured with headers but is not getting triggered continuously when I add poller. It just gets triggered once and stops.
<int:inbound-channel-adapter channel="fooinfotrigger.channel" expression="''">
<int:poller fixed-delay="5000"></int:poller>
</int:inbound-channel-adapter>
<int:channel id="fooinfo.channel">
<int:queue capacity="10"/>
</int:channel>
<int:channel id="fooinfotrigger.channel"></int:channel>
<int:chain input-channel="fooinfotrigger.channel" output-channel="fooinfo.channel">
<int:header-enricher>
<int:header name="Authorization" value="...." />
<int:header name="Content-Type" value="...." />
</int:header-enricher>
<int-http:outbound-gateway id="fooHttpGateway"
url="https://foo.com/v1/services/foo?status=active"
http-method="GET"
expected-response-type="java.lang.String"
charset="UTF-8"
reply-timeout="5000">
</int-http:outbound-gateway>
<int:transformer method="transform" ref="fooResourcesTransformer"/>
</int:chain>
<bean id="fooResourcesTransformer" class="com.foo.FooTransformer" />
The fixed-delay is an option to determine the time after the finish of the previous task. In your case the poll.
Since you affirm that it
gets triggered once and stops.
Looks like you don't finish your work somehow on the dealinfo.channel and don't return the control to the TaskScheduler and, therefore, don't free the thread for something else.
We really should see and understand your logic after that <chain> and with a subscribers on that dealinfo.channel.
Or... maybe your REST Service just doesn't return response at all. Independently of that reply-timeout="5000".

Appending X to Custom Request Headers in Spring-Integration

I found that when I want to make a REST call using Spring-Integration, it automatically appends 'x' in case its a custom header.
For example in Spring-integration while sending custom request headers such as API-KEY, the actual request header name in the API call becomes X-API-KEY and so it fails.
It seems like Spring is standardizing by enforcing the Custom request headers to start with X, is there a work around?
<int:channel id="requestChannel"/>
<int:channel id="httpHeaderEnricherChannel"/>
<int-http:outbound-gateway request-channel="requestChannel"
url="http://localhost:9090/balance"
http-method="GET"
mapped-request-headers="Api-Key"
expected-response-type="java.lang.String"/>
<int:header-enricher input-channel="httpHeaderEnricherChannel"
output-channel="requestChannel">
<int:header name="Api-Key" value="pass"/>
</int:header-enricher>
You should declare DefaultHttpHeaderMapper.outboundMapper() bean with the setUserDefinedHeaderPrefix(null) and including that your custom Api-Key header mapping. After that you should replace mapped-request-headers attribute with the header-mapper reference.
We have revised the feature and decided to remove "X-" default prefix in the next version.
For more info please, see here Custom HTTP headers : naming conventions and here https://jira.spring.io/browse/INT-3903.
Thanks to #Artem for clarifying, and Gary's post here Spring Integration Http Outbound Gateway Header Mapper
I was able to solve the issue
<int:channel id="requestChannel"/>
<int:gateway id="requestGateway"
service-interface="org.springframework.integration.samples.http.RequestGateway"
default-request-channel="requestChannel">
<int:default-header name="Api-Key" value="pass" />
</int:gateway>
<int-http:outbound-gateway request-channel="requestChannel"
header-mapper="headerMapper"
url="http://localhost:9090/balance"
http-method="GET"
expected-response-type="java.lang.String"/>
<beans:bean id="headerBean"
class="org.springframework.integration.samples.http.HeaderBean" />
<bean id="headerMapper"
class="org.springframework.integration.http.support.DefaultHttpHeaderMapper">
<property name="inboundHeaderNames" value="*" />
<property name="outboundHeaderNames" value="HTTP_REQUEST_HEADERS, Api-Key" />
<property name="userDefinedHeaderPrefix" value="" />
</bean>

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>

spring integration http outbound gateway timeout handling

I have http outbound gateway that post json message to rest service, now the rest will response with http error status with json message type in case if there is any error which should captured by our application. in happy scenario which post json message to that rest service and got http success status and json message also should captured with our application.
Now what I achieved through spring integration I was able to send message and got success response and capture it but in error status the spring behavior it throw an exception how can I change the behavior?
also how can make retry if there is any timeout ?
below the http outbound gateway configuration
<int-http:outbound-gateway request-channel="aggregatorChannel" reply-channel="responseChannel" charset="UTF-8"
url="http://localhost:8090/receiveGateway" http-method="POST" reply-timeout="180000">
<int-http:request-handler-advice-chain >
<int:retry-advice max-attempts="5" recovery-channel="aggregatorChannel" >
<int:exponential-back-off initial="1000" multiplier="5.0" maximum="600000" />
</int:retry-advice>
</int-http:request-handler-advice-chain>
</int-http:outbound-gateway>
the above configuration will retry on the error message which I don't want retry on that, I want to retry if there is only timeout.
What do you want to change the behavior to (when there's an error)?
If you wire up the RetryTemplate for the retry interceptor manually, as a <bean/>, you can specify in the RetryPolicy which exceptions are retryable.
EDIT:
It's not entirely clear what you are trying to do, but maybe this will point you in the right direction...
<int-http:outbound-gateway request-channel="requestChannel"
url="http://localhost:8080/http/receiveGateway"
http-method="POST"
request-factory="requestFactory"
expected-response-type="java.lang.String">
<int-http:request-handler-advice-chain >
<int:retry-advice max-attempts="5" recovery-channel="foo">
<int:exponential-back-off initial="1000" multiplier="1.1" maximum="600000" />
</int:retry-advice>
<bean class="foo.MyExceptionAdvice" />
</int-http:request-handler-advice-chain>
</int-http:outbound-gateway>
<bean id="requestFactory" class="org.springframework.http.client.SimpleClientHttpRequestFactory">
<property name="connectTimeout" value="5000"/>
<property name="readTimeout" value="5000"/>
</bean>
If the custom exception advice throws an exception, the message will be retried and eventually sent to he recovery channel. If the custom advice consumes the error, it can send a return value. I have put a simple on this gist.

Bi-directional messaging with spring integration

I'm relatively new to spring integration but I have been tasked with implementing a tcp gateway that needs to:
Listen for messages on a socket
Receive a message
Process the message and write some data to a queue
Return a response message to the original socket.
In my experience with spring integration, the message flow has not been bi-directional. I've only configured routers to listen, handle messages, and output to queue/topic. In this case, though, I need to accept messages and return a response while also forwarding on some message to a queue. Suggestions?
This is my integration xml so far.
<int:chain input-channel="tcpChannel">
<int:service-activator ref="tcpHandler" method="handleInput" />
</int:chain>
<int-ip:tcp-inbound-gateway
id="tcpGateway"
connection-factory="tcpServer"
request-channel="tcpChannel" />
How can I have the output of handleInput be forwarded to a queue but also have some response sent back from the gateway?
Edit: After the conversation below with Gary, this seems to be the pattern we want to follow:
<int-ip:tcp-inbound-gateway id="tcpGateway"
connection-factory="tcpServer"
request-channel="tcpChannel"
reply-channel="tcpReplyChannel"/>
<int:publish-subscribe-channel id="tcpChannel" />
<int:chain input-channel="tcpChannel">
<!-- int:json-to-object-transformer type="com.heb.revo.events.RxPosCredit" /-->
<int:service-activator ref="tcpHandler" method="handleInputToQueue" />
<jms:outbound-channel-adapter destination-name="${queue.response}" />
</int:chain>
<int:service-activator id="tcpResponseHandler"
ref="tcpHandler" method="replyToSocket"
input-channel="tcpChannel"
output-channel="tcpReplyChannel" />
<int:publish-subscribe-channel id="tcpReplyChannel" />
Since your chain has no output-channel the framework will route the return value of the handleInput method back to the gateway automatically.
If you want to capture the result and send it somewhere else (as well as a reply), create a <int:publish-subscribe-channel id="foo"/>, set the output-channel of the chain to foo, set the reply-channel on the gateway to foo, and subscribe another endpoint to foo (as an input-channel.

Resources