Search code examples
springspring-integrationspring-integration-dsl

What is good way to register adjacent HTTP requests with the Spring integration flow


What is good way to register adjacent HTTP requests with the Spring integration flow?

My application is:

For the every customer (has it's own flow, which start is scheduled by the poller)

  • GET operation 1 in the source application and the result is JSON_1
  • POST JSON_1 to the remote system and the result is JSON_1B
  • POST JSON_1B to the source application and the result is JSON_1C
  • GET operation 2 in the source application and the result is JSON_2
  • POST JSON_2 to the remote system and the result is JSON_2B
  • POST JSON_2B to the source application and the result is JSON_2C

...

  • GET operation n in the source application and the result is JSON_N
  • POST JSON_N to the remote system and the result is JSON_NB
  • POST JSON_NB to the source application and the result is JSON_NC

The operations 1, 2, ..., n must be in the order

Here is my example program (for the simplicity all the REST calls are for the same class)

@Configuration
public class ApplicationConfiguration {

@Autowired
private IntegrationFlowContext flowContext;

@Bean
public MethodInvokingMessageSource integerMessageSource() {
    final MethodInvokingMessageSource source = new MethodInvokingMessageSource();
    source.setObject(new AtomicInteger());
    source.setMethodName("getAndIncrement");
    return source;
}

@PostConstruct
public void createAndRegisterFlows() {
    IntegrationFlowBuilder integrationFlowBuilder = createFlowBuilder();
    for (int i = 1; i <= 2; i++) {
        integrationFlowBuilder = flowBuilder(integrationFlowBuilder, i);
    }
    integrationFlowBuilder.handle(CharacterStreamWritingMessageHandler.stdout());
    flowContext.registration(integrationFlowBuilder.get()).register();
}

private IntegrationFlowBuilder createFlowBuilder() {
    return IntegrationFlows.from(this.integerMessageSource(), c -> c.poller(Pollers.fixedRate(5000)));
}

private IntegrationFlowBuilder flowBuilder(final IntegrationFlowBuilder integrationFlowBuilder, final int number) {
    return integrationFlowBuilder
            .handle(Http.outboundGateway("http://localhost:8055/greeting" + number).httpMethod(HttpMethod.GET)
                    .expectedResponseType(String.class))
            .channel("getReceive" + number)
            .handle(Http.outboundGateway("http://localhost:8055/greeting" + number).httpMethod(HttpMethod.POST)
                    .expectedResponseType(String.class))
            .channel("postReceive" + number)
            .handle(Http.outboundGateway("http://localhost:8055/greeting-final" + number)
                    .httpMethod(HttpMethod.POST).expectedResponseType(String.class))
            .channel("postReceiveFinal" + number);
}
}

This program runs the integration flow

GET http://localhost:8055/greeting1
POST http://localhost:8055/greeting1 (previous result as an input)
POST http://localhost:8055/greeting-final1 (previous result as an input)
GET http://localhost:8055/greeting2
POST http://localhost:8055/greeting2 (previous result as an input)
POST http://localhost:8055/greeting-final2 (previous result as an input)

This is working as expected. But I'm wondering is this good way to do this, because the response from the call POST http://localhost:8055/greeting-final1 is not used in the call GET http://localhost:8055/greeting2. I only want that these calls are in this order.


Solution

  • Actually you have everything you needed with that loop to create to sub-flow calls to the REST services. Only what you are missing is a payload as a result from the greeting-final1 which is going to be published with the message to the .channel("postReceiveFinal" + number). The second iteration will subscribe the greeting2" to that channel and the payload is available for processing here. Not sure how to rework your flowBuilder() method, but you just need to use a payload from the message for whatever is your requirements, e.g. you can use it as an:

    /**
     * Specify an {@link Expression} to evaluate a value for the uri template variable.
     * @param variable the uri template variable.
     * @param expression the expression to evaluate value for te uri template variable.
     * @return the current Spec.
     * @see AbstractHttpRequestExecutingMessageHandler#setUriVariableExpressions(Map)
     * @see ValueExpression
     * @see org.springframework.expression.common.LiteralExpression
     */
    public S uriVariable(String variable, Expression expression) {
    

    to inject a payload to some request param since it is just HttpMethod.GET:

    handle(Http.outboundGateway("http://localhost:8055/greeting2?param1={param1}")
            .httpMethod(HttpMethod.GET)
            .uriVariable("param1", "payload")
            .expectedResponseType(String.class))