Appending X to Custom Request Headers in Spring-Integration - spring

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>

Related

Missing soap action :: Spring Integration

I am working on a spring integration component where I posting data to external third-party URL. and Its is working fine with the below code.
<!-- language: lang-xml -->
<int:chain id="channe.id"
input-channel="request.in"
output-channel="reply.channel">
<int-ws:header-enricher>
<int-ws:soap-action
value="${service.soapaction}" />
</int-ws:header-enricher>
<int-ws:outbound-gateway
id="invoker.ws.outbound.gateway"
ignore-empty-responses="true" message-sender="message.sender"
interceptors="${SecurityInterceptor}"
message-factory="${mmessageFactory}"
uri="${protocol}://${host}:${port}/{endpoint}">
<int-ws:uri-variable name="endpoint"
expression="headers.endpoint" />
<int-ws:request-handler-advice-chain>
<ref bean="commonRetryAdviceBean" />
</int-ws:request-handler-advice-chain>
</int-ws:outbound-gateway>
</int:chain>
Below is payload received by third part api.
<MessageLogTraceRecord>
<HttpRequest xmlns="http://schemas.microsoft.com/2004/06/ServiceModel/Management/MessageTrace">
<Method>POST</Method>
<QueryString></QueryString>
<WebHeaders>
<Content-Length>9381</Content-Length>
<Content-Type>text/xml; charset=UTF-8</Content-Type>
<Accept>text/xml</Accept>
<Accept-Encoding>gzip</Accept-Encoding>
<Host>myhost</Host>
<User-Agent>Jakarta Commons-HttpClient/3.1</User-Agent>
<SOAPAction>"http://www.mysoap.com/action/update"</SOAPAction>
</WebHeaders>
Now, I have to add an additional security feature and send the API key in the HTTP header or soap header. SO I modified my code as below. Now I can see API key is sent as soap header but some how SOAPAction is going empty, not sure why.
below is the modified code to send api ket as part of soap header.
<int:chain id="channe.id"
input-channel="request.in"
output-channel="reply.channel">
<int-ws:header-enricher>
<int-ws:soap-action
value="${service.soapaction}" />
</int-ws:header-enricher>
<int-ws:outbound-gateway
id="invoker.ws.outbound.gateway"
ignore-empty-responses="true" message-sender="message.sender"
interceptors="${SecurityInterceptor}"
message-factory="${mmessageFactory}"
mapped-request-headers="soapHeaderMapper"
uri="${protocol}://${host}:${port}/{endpoint}">
<int-ws:uri-variable name="endpoint"
expression="headers.endpoint" />
<int-ws:request-handler-advice-chain>
<ref bean="commonRetryAdviceBean" />
</int-ws:request-handler-advice-chain>
</int-ws:outbound-gateway>
</int:chain>
<bean id="soapHeaderMapper"
class="org.springframework.integration.ws.DefaultSoapHeaderMapper">
<property name="requestHeaderNames">
<list>
<value>api-key</value>
</list>
</property>
</bean>
After adding mapped-request-headers now I am getting
org.springframework.messaging.MessagingException: The message could not be processed because the action '' is invalid or unrecognized.; nested exception is org.springframework.ws.soap.client.SoapFaultClientException: The message could not be processed because the action '' is invalid or unrecognized., failedMessage=GenericMessage
when I checked the payload received by thirdparty api I can see SOAP action is empty I am not sure why.
Please help me.
Thanks.
<QueryString></QueryString>
<WebHeaders>
<Content-Length>9463</Content-Length>
<Content-Type>text/xml; charset=UTF-8</Content-Type>
<Accept>text/xml</Accept>
<Accept-Encoding>gzip</Accept-Encoding>
<Host>myhost</Host>
<User-Agent>Jakarta Commons-HttpClient/3.1</User-Agent>
<SOAPAction>""</SOAPAction>
</WebHeaders>
</HttpRequest>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Header api-key="dummy-123455555uuuuuuuuuuuqwert">
The mapped-request-headers="soapHeaderMapper" is wrong configuration. It is exactly about names, but in your case you try to make a reference to the DefaultSoapHeaderMapper bean definition.
Consider to use:
<xsd:attribute name="header-mapper">
<xsd:annotation>
<xsd:documentation>
Reference to a SoapHeaderMapper implementation
that this gateway will use to map between Spring Integration
MessageHeaders and the SoapHeader.
</xsd:documentation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:expected-type type="org.springframework.integration.ws.SoapHeaderMapper"/>
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
instead.
Also there is the with your header names to map: when you configure some custom header names, all the standard headers are missed. So, alongside with the api-key, you need to consider include the mentioned ws_soapAction name as well.

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

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.

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".

http outbound gateway is sending only one request at a time

I have a http outbound gateway that is connecting to one URL. Below is the code snippet. I am dropping around 100 files on the folder. The URL connects localhost:8080/index.jsp. In the JSP i have added Thread.sleep(60000).
When I run the code I see that only one call is made to JSP every 60 seconds. However my pool manager to have 25 connections per route.
Not sure why it is not working. Anyone has faced similar problem?
<int:poller default="true" fixed-delay="50"/>
<int:channel id="inputChannel">
<int:queue capacity="5"/>
</int:channel>
<int:channel id="httpInputChannel">
<int:queue capacity="5"/>
</int:channel>
<int-http:outbound-gateway id="simpleHttpGateway"
request-channel="httpInputChannel"
url="${app.webservice.url}"
http-method="GET"
extract-request-payload="false"
expected-response-type="java.lang.String"
charset="UTF-8"
reply-timeout="1234"
request-factory="requestFactory"
reply-channel="wsResponseChannel">
</int-http:outbound-gateway>
<bean id="requestFactory"
class="org.springframework.http.client.HttpComponentsClientHttpRequestFactory">
<constructor-arg ref="httpClient"/>
</bean>
<bean id="httpClient" class="org.apache.http.impl.client.DefaultHttpClient">
<constructor-arg ref="poolManager"/>
</bean>
<bean id="poolManager" class="org.apache.http.impl.conn.PoolingClientConnectionManager">
<property name="defaultMaxPerRoute" value="25"/>
<property name="maxTotal" value="250"/>
</bean>
<int:channel id="wsResponseChannel">
<int:queue capacity="5"/>
</int:channel>
<int:service-activator ref="clientServiceActivator" method="handleServiceResult" input-channel="wsResponseChannel" />
<bean id="clientServiceActivator" class="com.spijb.serviceactivator.ClientServiceActivator"/>
<int-file:inbound-channel-adapter id="producer-file-adapter" channel="inputChannel" directory="file:c://Temp//throttling" prevent-duplicates="true">
<int:poller fixed-rate="100" />
</int-file:inbound-channel-adapter>
<int-file:file-to-string-transformer
id="file-2-string-transformer" input-channel="inputChannel"
output-channel="httpInputChannel" charset="UTF-8" />
You have a single poller thread on your file inbound channel adapter. You need to add a task-executor to the poller, with a pool size set the number of concurrent requests you want to handle.
You also need to set max-messages-per-poll, which defaults to 1.
I changed the configuration to add executor as below.
<int-file:inbound-channel-adapter id="producer-file-adapter" channel="inputChannel" directory="file:c://Temp//throttling" prevent-duplicates="true">
<int:poller fixed-rate="100" task-executor="executor" max-messages-per-poll="25"/>
</int-file:inbound-channel-adapter>
<task:executor id="executor" pool-size="25"/>
Still it was only sending one request to my tomcat server listening for index.jsp. My understanding was if there are multiple messages present in the channel queue which is the case now on httpInputChannel, the http outbound gateway would process multiple requests. However this is not happening. I further changed my default poller as below.
<int:poller default="true" fixed-delay="50" task-executor="executor"/>
After above change, the http outbound gateway started sending multiple requests to the URL. Now I am confused. Do we need to explicitly assign executor for outbound gateway to process multiple messages at the same time? Can someone please direct me to the documentation for the same?
Thank you.

about spring social xml configuration

i wonder "#{request.userPrincipal.name}" in configuration blow. when I run my spring social project it always has error at "#{request.userPrincipal.name}", if I set a value such as "123" my project runs well. what's wrong and is there any other configuration instead of "#{request.userPrincipal.name}" ?
<bean id="connectionRepository" factory-method="createConnectionRepository" factory-bean="usersConnectionRepository" scope="request">
<constructor-arg value="#{request.userPrincipal.name}" />
<aop:scoped-proxy proxy-target-class="false" />
</bean>
This is a Spring EL expression, which means getting the user identity from the Http request. Once you apply your own User Management component, you can replace #{request.userPrincipal.name} with your own way.

Resources