How to config post parameters in http:outbound-gateway - spring-integration

We have an case that retrieve orders from our customers system by using http post call, post request include username and password, and we can get order contents response then.
We want to call customer's service every 10 minutes, and then process the response in our service activator, however, I don't know how to config username and password as post parameters in spring integration configuration, anyone can help?
my current configuration
<int:inbound-channel-adapter channel="inChannel" expression="''">
<int:poller fixed-delay="60000"></int:poller>
</int:inbound-channel-adapter>
<int:channel id="inChannel"/>
<int:channel id="outChannel"/>
<http:outbound-gateway
url="http://****/vendorServer/order"
request-channel="inChannel" reply-channel="outChannel" http-method="GET" expected-response-type="java.lang.String">
</http:outbound-gateway>
<int:service-activator input-channel="outChannel" ref="orderService"/>
how to config username and password as post parameters in above configuration?

The HTTP POST method implies the body. The organic way to provide the body in Spring Integration is message payload. Therefore you should consider to build a Map payload with required properties before sending to the http:outbound-Gateway

Related

Spring Integration Outbound Gate way for Synchronous REST Calls

Previously i was able to develop a little framework using the Spring Integration Where developers can specify the URLs, HTTP methods and Request Body and invoke any external REST API.
This is the configuration for my Spring Integration
<int:channel id='reply.channel'>
<int:queue capacity='10' />
</int:channel>
<int:channel id='request.channel'/>
<int:channel id='outbound.Channel'/>
<int:gateway id="outboundGateway"
service-interface="com.bst.pm.PostGateway"
default-request-channel="outbound.Channel">
</int:gateway>
<int:object-to-json-transformer input-channel="outbound.Channel" output-channel="request.channel"/>
<int-http:outbound-gateway id="outbound.gateway"
request-channel="request.channel" url-expression="headers.bstUrl"
http-method-expression="headers.bstHttpMethod" expected-response-type-expression="headers.bstExpectedResponseType"
charset="UTF-8" reply-timeout="5000" reply-channel="reply.channel"
mapped-request-headers="bst*, HTTP_REQUEST_HEADERS">
</int-http:outbound-gateway>
Then Developers can invoke external rest API calls using the above infrastruture as below
#Autowired #Qualifier("reply.channel") PollableChannel receivedChannel;
#Autowired #Qualifier("request.channel") MessageChannel getRequestChannel;
#Autowired #Qualifier("outbound.Channel") MessageChannel httpOutboundGateway;
Post post = new Post();
post.setTitle("Spring INtegration Test");
post.setBody("This is a sample request body to test Spring Integration HTTP Outbound gateway");
post.setUserId(Long.valueOf(1));
Message<?> message = MessageBuilder.withPayload(post)
.setHeader("bstUrl", "https://jsonplaceholder.typicode.com/posts")
.setHeader("bstHttpMethod", "POST")
.setHeader("bstExpectedResponseType", "com.bst.pages.crm.web.Post")
.build();
httpOutboundGateway.send(message);
Message<?> receivedMsg = receivedChannel.receive();
Post post = (Post) receivedMsg.getPayload();
System.out.println("############## ServerMsg ##############");
System.out.println(o);
System.out.println("############## Done! ##############");
In here i want to make all the REST calls via this integration infrastructure to be Synchronous. However i have used a QUEUE channel as the reply-channel for the http:outbound-gateway. Therefore as per my understanding the reply can be received by a wrong sender as any one can pool the channel for the messages.
How can we make sure the the correct sender will always receive the correct response?
Thanks,
Keth
Your is correct. Really having a global reply channel and several concurrent processes you may end up with work stealing situation.
To fix your problem you need to get rid of the reply-channel on your HTTP Gateway and just rely on your the replyChannel header populated by the Messaging Gateway. However your Gateway method should really be as a request-reply signature: it has to return Object.
See more info about replyChannel header in the Reference Manual: https://docs.spring.io/spring-integration/docs/5.0.6.RELEASE/reference/html/messaging-endpoints-chapter.html#gateway

Using QueueChannel in Spring Integration

I am working on the below case study.
Create a Rest Service to accept Reference id.
Use the Reference Id to get data (CLOB) from Database.
Put the data(CLOB) in a channel(queue) for further processing.
Reply to the rest client with response data in JSON format {"status": true,"message": "RECEIVED"}
I have the Rest Service created and using the Ref Id am getting the data from database but I am unable to send the response back to the rest client after putting the message in a channel(queue).
The output received by Rest Client is : No reply received within timeout
Basically I want the request thread to be returned immediately after the data (CLOB) is pushed to the channel(queue).
Below is the configuration.
<int:channel id="responseChannel"/>
<int:channel id="initCalculation">
<int:queue/>
</int:channel>
<!-- GET -->
<int-http:inbound-gateway
request-channel="httpGetChannel"
reply-channel="responseChannel"
supported-methods="GET"
path="/init/{refId}"
payload-expression="#pathVariables.refId">
<int-http:request-mapping produces="application/json"/>
</int-http:inbound-gateway>
<int:chain input-channel="httpGetChannel" output-channel="initCalculation">
<int-jdbc:stored-proc-outbound-gateway
id="outbound-gateway-storedproc-get-forma" data-source="dataSource"
is-function="false"
stored-procedure-name="XX_EMPROC.GET_FRMA"
ignore-column-meta-data="true"
expect-single-result="true">
<int-jdbc:sql-parameter-definition name="V_REF_ID" direction="IN" />
<int-jdbc:sql-parameter-definition name="V_FRMA" direction="OUT" type="#{T(oracle.jdbc.OracleTypes).CLOB}"/>
<int-jdbc:parameter name="V_REF_ID" expression="payload" />
</int-jdbc:stored-proc-outbound-gateway>
<!- Convert to JSON Format -->
<int:service-activator ref="brInitGateway" method="getResponse"/>
</int:chain>
<int:outbound-channel-adapter channel="initCalculation" ref="brInitGateway" method="process"/>
Kindly advise on the corrections needed in the above.
Thanks
Look, there is no body who sends message as a reply to the <int-http:inbound-gateway>. You have declared responseChannel, but who is going to use it as an output-channel?
I'd suggest you to do this:
<publish-subscribe-channel id="responseChannel"/>
<int:chain input-channel="httpGetChannel" output-channel="responseChannel">
<int:bridge input-channel="responseChannel" output-channel="initCalculation"/>
So, what happens here:
The publish-subscribe-channel for the reply-channel makes an internal bridge to the replyChannel header as one of the subscribers.
You send a result from the <chain> to that channel. Therefore the <int-http:inbound-gateway> gets its reply.
Having that <int:bridge> from response to the initCalculation you have a second subscriber and, therefore, send a message to the required queue.
If you are not interested in the brInitGateway.getResponse() as a reply for the HTTP request, you should consider do not have that reply-channel="responseChannel" at all, but still use some <publish-subscribe-channel> to send to the queue and some transformer to prepare a reply, e.g.:
<transformer input-channel="prepareProcess" expression="' {"status": true,"message": "RECEIVED"}'"/>
This transformer is without output-channel because it is going to send its result into the replyChannel header, therefore to the <int-http:inbound-gateway> initiator.

Overloading MessageHistory object for auditing purpouses

I need to audit every message that pass throught an spring-integration flow, very basic one.
The application reads from an int-redis:queue-inbound-channel-adapter and writes in an int-http:outbound-gateway.
The output gateway has a reply-channel in order to receive the response of the http method, is in this exact moment when I want to register de audit information, including the initial message and http response.
If the http method fails, the message goes to errorHandler and I can obtain the history object with timestamps and payload, what's perfect for audit.
But if the http method works (Code 200,201 ...), I get a message including the ResponseEntity object with the status code, but I've no the initial payload from redis.
So, is there any way to corelate the two messages (before sending http outbound and after http response) in order to get the full info for auditing?
Thanks in advance!
Here the integration flow:
<int:message-history/>
<int:channel id="responseChannel"/>
<int:channel id="responseError"/>
<int:logging-channel-adapter channel="responseChannel" level="INFO"
expression="#messageHandlerSpel.handle( #this )" id="logger"/>
<int:logging-channel-adapter channel="responseError"
level="ERROR" expression="#errorHandlerSpel.handle( #this )"
id="LogingERROR"/>
<int-redis:queue-inbound-channel-adapter id="inputRedis" connection-factory="redisCF"
channel="redisInput" queue="redis-input" serializer="" error-channel="responseError"/>
<int:channel id="redisInput" />
<int-http:outbound-gateway id="HttpOutbound" request-channel="redisInput"
url="http://{server}:{port}/{index}/{type}/{id}"
http-method="PUT" extract-request-payload="true" charset="UTF-8"
reply-channel="responseChannel" request-factory="requestFactory"/>
And the handler class:
#Component
public class MessageHandlerSpel {
public String handle(Message<byte[]> message) {
MessageHeaders msgH = message.getHeaders();
MessageHistory msgHistory =
message.getHeaders().get(MessageHistory.HEADER_NAME, MessageHistory.class);
... // Do whatever
return "";
}
One trick is to store the request payload in the custom header before performing the HTTP request.
After receiving response, the request headers will be merged with that response payload. Therefore in the downstream you will have both: the request in the header, and reply in the payload.
The MessageHistory remains the same and there is no reason to hack there somehow.
Another approach is based on the <aggregator> to correlate request and reply. But this one is for more complex or distributed scenario.
The simple copy/paste to header via:
<header-enricher>
<header name="requestPayload" expressio="payload"/>
</header-enricher>
should be enough for you.

How do I get the request URL for message headers

I have an inbound gateway to process JSON payloads. Since we utilize the same backend service as our SOAP endpoints, I need to have an inbound gateway that maps to all paths. I can see the default HTTP headers come across the into the message, but I specifically need the request URL so I can parse it and route to the appropriate serve as needed.
My inbound-gateway:
<int-http:inbound-gateway id="JSONGateway"
path="*" request-channel="JSONRequestChannel" supported-methods="POST"
reply-timeout="5000"
header-mapper="headerMapper"
request-payload-type="java.lang.String" >
</int-http:inbound-gateway>
I tried adding a header-enricher like I do for SOAP, but the TransportContextListener is null.
<int:header-enricher input-channelJSONequestChannel"
output-channel="JSONRequestChannelWithHeaders">
<int:header name="service"
expression="T(org.springframework.ws.transport.context.TransportContextHolder).transportContext.connection.uri.toString().substring(T(org.springframework.ws.transport.context.TransportContextHolder).transportContext.connection.uri.toString().lastIndexOf('/')+1)" />
</int:header-enricher>
I need a way to get the URL of the request so I can parse out the service into the message headers for my downstream router.
/json/ContactService = "ContactService"
/json/ContactService/insert = "ContactService"
/json/ContactService/get/234 = "ContactService"
I also tried adding a header-mapper class, but still run into the same problem. How can I get a handle to the HTTPServletRequest in code? Once I get that I can get all the headers I need.
Well, you didn't check the message headers.
After converting ServletServerHttpRequest to the Message it gets these headers by default:
Message<?> message = messageBuilder
.setHeader(org.springframework.integration.http.HttpHeaders.REQUEST_URL,
request.getURI().toString())
.setHeader(org.springframework.integration.http.HttpHeaders.REQUEST_METHOD,
request.getMethod().toString())
.setHeader(org.springframework.integration.http.HttpHeaders.USER_PRINCIPAL,
servletRequest.getUserPrincipal())
.build();
So, http_requestUrl is for you to go ahead and parse it appropriately.

spring integration inbound email with custom header

I have a spring app that sends emails through and reads emails from a GMail inbox and handles any undelivered mail messages that have been sent through the account but then returned as the recipient address is not recognised.
I have this all configured and working but I am also setting a custom header on the outbound message that I would like to retrieve when the returned mail is read. Debugging the app shows that the message is being read correctly but it is missing the custom header value.
Here is my config:
<mail:inbound-channel-adapter id="imapAdapter"
store-uri="#{mailIntegrationProperties['mail.imap.url']}"
java-mail-properties="mailIntegrationProperties"
channel="receiveEmailChannel"
should-delete-messages="false"
should-mark-messages-as-read="true"
auto-startup="true"
max-fetch-size="#{mailIntegrationProperties['mail.max.fetch.size']}">
<int:poller time-unit="SECONDS" fixed-rate="#{mailIntegrationProperties['mail.poller.seconds']}" />
</mail:inbound-channel-adapter>
<int:channel id="receiveEmailChannel" />
<bean id="mailMessageReceiver" class="com.myapp.integration.mail.EmailMessageReceiver" />
<int:service-activator input-channel="receiveEmailChannel" ref="mailMessageReceiver" output-channel="emailEventMessageQueue" method="receive" />
I have left the output-channel of the service-activator off for brevity but the system is working as expected, but just the custom header is missing when I am processing the message.
Any ideas on how to configure Spring to read that custom header?
Cheers!
I assume you mean you are setting some 'X-foo' header on an SMTP outbound message, and want to see it on the message received.
The payload of the message placed on the receiveEmailChannel is the mime message received; there is no filtering of the headers and all headers received will be included in it.
If you don't see the header, it means it wasn't in the message.
If you turn on debugging <prop key="mail.debug">true</prop> in your javamail properties, you'll see the message in the console as it is received (including all the headers).

Resources