Routing based on REST method with Spring integration - spring-integration

I have several "int-http:inbound-gateway" and I need one of them to point at different services based on http method provided by the request.
<int-http:inbound-gateway path="....." supported-methods="POST,PUT"/>
At this moment I have 2 different endpoints and I was looking for some rest-method-based router but I have found nothing about this topic.
Any help?

you can use a header-value-router for this one as the http method is automatically set in the message header.
something like this
<int-http:inbound-channel-adapter channel="input.channel"
path="/log" supported-methods="PUT,POST" request-payload-type="java.lang.String"/>
<int:channel id="input.channel"/>
<int:header-value-router input-channel="input.channel" header-name="#{T(org.springframework.integration.http.HttpHeaders).REQUEST_METHOD">
<int:mapping value="PUT" channel="put.input.channel"/>
<int:mapping value="POST" channel="post.input.channel"/>
</int:header-value-router>
hope that helps

Related

Spring Integration - Processing Pipeline - Design

I am trying to design a message processing pipeline that needs to process a message using multiple end-points. At each stage, the endpoints returns either the payload (could be transformed) or an error message. Here's a generic example of what I have in my mind:
<int:payload-type-router input-channel="preprocessing-output">
<int:mapping type="com.example.Error" channel="error" />
<int:mapping type="com.example.PreprocessedDomainObject" channel="validation-input"/>
</int:payload-type-router>
<int:service-activator input-channel="validation-input"
ref="validationService" method="validate" output-channel="validation-output"/>
<int:payload-type-router input-channel="validation-output">
<int:mapping type="com.example.Error" channel="error" />
<int:mapping type="com.example.CouldBeAnotherObject" channel="processor-input"/>
</int:payload-type-router>
So on, this processing chain can be quite long... Is there a better way to design this instead of a payload type router after every stage? Kinda feels redundant.
Well, I'd make it based on the exceptions. The validation service should just throw exception and all you need is to catch it on the caller or have an errorChannel if it is Inbound Channel Adapter.
That way you don't need those routers definitions at all and just plain services calling chain.

adding a Router in spring integration application

I need to add a router in Spring integration application. The requirement is to either to send the message by the router to both the channel or to a single channel based on the return string sent by the router class. please tell me how to route the message to both the channels.
You can use the combination of a Splitter and a Header Value Router to duplicate and route messages.
<!-- Clone message -->
<int:splitter ref="messageDuplicator" method="duplicateMessage"
input-channel="incomingMessage" output-channel="duplicateMessageChannel" id="messageSplitter"/>
<int:header-value-router input-channel="duplicateMessageChannel" header-name="DESTINATION" id="messageDestinationRouter">
<int:mapping value="DEST_1" channel="dest1Channel" />
<int:mapping value="DEST_2" channel="dest2Channel" />
</int:header-value-router>
In your messageDuplicator implementation, you can add code to clone your message and add custom headers for routing the message to different destinations.

Spring Integration HTTP

Spring Integration HTTP support.
Hi I am trying channel routing based on the path attribute.
For example if the configuration is as follow
I would like to send the message to different channel based on path that is path="gateway/search" value. Had a look at header based routing and payloadtype routing. Can u please suggest the way to implement.
<!-- Inbound/Outbound Channels -->
<int:channel id="ServiceSearchRequest" />
<int:channel id="ServiceSearchResponse" />
<int-http:inbound-gateway id="inboundEmployeeSearchRequestGateway"
supported-methods="GET, POST" request-channel="ServiceSearchRequest"
reply-channel="ServiceSearchResponse"
mapped-response-headers="Content-Type"
path="ieg/Service/search" request-payload-type="java.lang.String"
reply-timeout="5000">
</int-http:inbound-gateway>
<int-http:outbound-gateway request-channel="ServiceSearchRequest"
reply-channel="ServiceSearchResponse"
url="http://localhost:8080/proj/Service/avgWaitTime123.json"
http-method="POST" expected-response-type="java.lang.String"
mapped-response-headers="Content-Type" />
It's not clear what you are asking for; you only have a single path (ieg/dataService/search) so all messages would go to a single channel if you routed on the path.
If you mean you want to route based on some query string parameter ..?foo=bar then you can add a <header/> element to the inbound gateway to capture it as a header; e.g.
<int-http:header name="foo" expression="#requestParams.foo.get(0)" />
You can then use a header value router. For a full list of variables available for header expressions, see the reference documentation (scroll down to URI Template Variables and Expressions.

error-channel and reply-channel vanishes during header aggregation

I have the following workflow.
inbound-channel
splitter
task executor for split channels - all the threads execute the same workflow.
3.a. construct the request
3.b. service activator wrapper for a gateway message endpoint.
3.c. gateway wrapper over the http-outbound-gateway with the configuration of error-channel (to handle exceptions while invoking http-outbound-gateway)
3.d. http-outbound-gateway
aggregator
response out of spring integration workflow.
If an exception occurs in 3.d, the control goes to the service-activator configured for the gateway error channel.
I copy just the following from the failed message to the new header to the header passed to the error channel.
a. correlationId
b. sequenceNumber
c. sequenceSize
But while aggregating the splitter response, the DefaultAggregatingMessageGroupProcessor.java removes the conflicting headers and by that it removes the error-channel and reply-channel before providing the control to aggregator.
So once the aggregator completes it's operation it is unable to find the reply or error channel and it results in an exception.
I'm using spring-integration-core version 2.2.1 and I'm not sure why the reply-channel and error-channel is being removed during header aggregation.
Any input on resolving this issue will be of great help.
Thank You :)
EDIT 1:
Thank You very much Gary for helping me out with this scenario. I'm sharing my current configuration
<!-- SPLITTER -->
<int:splitter id="dentalSplitter" ref="dentalServiceSplitter"
method="getDentalServiceList" input-channel="dentalServiceSplitterChannel"
output-channel="dentalSplitterTaskChannel" />
<int:channel id="dentalSplitterTaskChannel">
<int:dispatcher task-executor="dentalTaskExecutor" />
</int:channel>
<int:chain input-channel="dentalSplitterTaskChannel" output-channel="dentalGatewayChannel">
<int:header-enricher>
<int:header name="CHAIN_START_TIME" expression="T(System).currentTimeMillis()" overwrite="true" />
<int:object-to-json-transformer content-type="application/json"/>
</int:chain>
<int:service-activator input-channel="dentalGatewayChannel" ref="dentalGatewayWrapper" output-channel="dentalReplyChannel" />
<int:gateway id="dentalGatewayWrapper" default-request-channel="dentalCostEstimateRequestChannel" error-channel="dentalErrorChannel"/>
<int-http:outbound-gateway id="dentalGateway"
url-expression="#urlBuilder.build('${service.endpoint}')"
http-method="POST" request-factory="clientHttpRequestFactory"
request-channel="dentalCostEstimateRequestChannel" extract-request-payload="true"
expected-response-type="com.dental.test.DentalResponse">
<int-http:request-handler-advice-chain>
<ref bean="logChainTimeInterceptor" />
</int-http:request-handler-advice-chain>
</int-http:outbound-gateway>
<!-- EXCEPTION -->
<int:chain input-channel="dentalErrorChannel" output-channel="dentalAggregatorChannel">
<int:transformer ref="commonErrorTransformer" method="dentalGracefulReturn"/>
</int:chain>
<!-- SUCCESS -->
<int:chain input-channel="dentalReplyChannel" output-channel="dentalAggregatorChannel">
<int:filter discard-channel="dentalErrorChannel"
expression="T(com.dental.util.InvocationOutcomeHelper).isOutcomeSuccess(payload?.metadata?.outcome?.code,payload?.metadata?.outcome?.message)" />
</int:chain>
<!-- AGGREGATION -->
<int:chain input-channel="dentalAggregatorChannel" output-channel="wsDentalServiceOutputChannel" >
<int:aggregator ref="dentalServiceAggregator" />
<int:service-activator ref="dentalResponseServiceActivator" />
</int:chain>
What I noticed was this, every split channel when passing through the gateway creates a new temporary channel for error and reply and after getting the response back from the gateway, it retains the preserved (original inbound) error and reply channel header. And as you had mentioned, after the control gets to the error transformer that flow of retaining the preserved headers gets broken and the aggregating message group processor receives three different instances of temporary channel and hence removes them.
I was planning to have a custom message group processor and modify the conflict resolution strategy for aggregating the header and came up with this config.
<bean id="channelPreservingAggregatingMessageHandler" class="org.springframework.integration.aggregator.AggregatingMessageHandler">
<constructor-arg name="processor" ref="channelPreservingMessageGroupProcessor"/>
</bean>
I'm yet to test this out though. But based on this discussion, this does not look like a viable solution.
And looks like my configuration for error handling in gateway is incorrect.
However, I'm confused on this statement of yours "Instead of forwarding the message directly, simply handle the error on your error flow and return the result normally to the gateway "wrapper"". If I remove the error channel how will I get the control back when an exception occurs? May be I'm missing to understand something here. Can you elaborate more on this please?
When asking questions about scenarios such as this, you generally need to show your configuration. However, I suspect you are forwarding the message from the error flow directly to the aggregator.
This is like doing a GOTO in code and breaks the scoping.
It won't work because the replyChannel header in the error message is for the gateway "wrapper", not the original upstream inbound gateway. When the aggregator gets conflicting headers, it has no choice but to drop the headers (you will see a DEBUG log message to that effect).
Instead of forwarding the message directly, simply handle the error on your error flow and return the result normally to the gateway "wrapper" (simply omit the error channel on the last element on the error flow).
The gateway will then fix up the reply so it is consistent with other messages (good and bad) and forward it to the aggregator.
You don't need to mess with headers in your error flow, just return the value you want to be aggregated along with the good results.
You should really update to a current release, or at least the latest in the 2.2.x line (2.2.6).

Spring integration-Service activator getting called twice

Hi this is my spring integration configuration..When i hit my service using mozilla fire fox rest console two times its getting called.For example if i hit some service in service-activator (CA request activator),On certaion un predicatable scenarios it s getting called twice.I dont know whetther it is mozilla issue or configuration issue.I tried using new window but this problem persists.In first case my service activator returning xml response properly but immediately it s getting called again.Only on rare scenarios its calling twice.
<int:channel id="accountRequest" />
<int:channel id="accountResponse" />
<int:channel id="catRequestChannel" />
<int:channel id="mataccountRequest" />
<int:channel id="errorChannel"/>
<int-http:inbound-gateway id="cwebAccountManagementGateway"
supported-methods="GET, POST"
request-channel="accountRequest"
reply-channel="accountResponse"
mapped-request-headers="*"
mapped-response-headers="*"
view-name="/policies"
path="/services/{class}/{method}"
reply-timeout="50000"
error-channel="errorChannel">
<int-http:header name="serviceClass" expression="#pathVariables.class"/>
<int-http:header name="serviceMethod" expression="#pathVariables.method"/>
</int-http:inbound-gateway>
<int:header-value-router input-channel="accountRequest"
header-name="state"
default-output-channel="accountRequest" resolution-required="false">
<int:mapping value="MA"
channel="mataccountRequest" />
<int:mapping value="CA"
channel="catRequestChannel" />
</int:header-value-router>
<int:service-activator id="accountServiceActivator"
input-channel="mataccountRequest"
output-channel="accountResponse"
ref="serviceGatewayAdapter"
method="requestHandler"
send-timeout="60000"/>
<int:service-activator id="caRequestActivator"
input-channel="catRequestChannel"
output-channel="accountResponse"
ref="caServiceGatewayAdapter"
method="requestHandler"
send-timeout="60000"/>
<int:service-activator id="errorRequestActivator"
input-channel="errorChannel"
output-channel="accountResponse"
ref="errorGatewayAdapter"
method="errorHandler"
send-timeout="60000"/>
for eg:This is my url
http://localhost:9085/springintegrationsample/create?mail=15999999#mail.com&idNumber=80010600010
if i edit the mail to some other values it ll get called twice
if i change agan it s working fine.I dont understand on what scenarios its getting called twice
You are using the same "requestHandler" for both of your service activators, so its obvious it will be called twice.
You can't know which activator is called for the handler method as when you debug you can only check for the handler method being called.
To better handle this, use different a handler method for each of your service activators. Even if they are using similar operations, it will be more clear and easy to debug.
I would suggest to add channel interceptors for logging of incoming and outgoing messages just to get a better idea.
cheers

Resources