I'm using Spring-integration in my project and the pattern used is scatter-gather. Here three parallel processes are being carried out. The flow2 is a outbound gateway method and if that service is down then I want to handle the Httpstatus exception and want to send null. Actually if that service is down then the whole flow is getting stopped. But I want to handle that exception and send null and then want to continue with the aggregate method and end the flow.
Below is the code - -
//Config file
@Configuration
public class IntegrationConfiguration {
@Autowired LionsServiceImpl lionsService;
long dbId = new SequenceGenerator().nextId();
// Main flow
@Bean
public IntegrationFlow flow() {
return flow ->
flow.handle(validatorService, "validateRequest")
.split()
.channel(c -> c.executor(Executors.newCachedThreadPool()))
.scatterGather(
scatterer ->
scatterer
.applySequence(true)
.recipientFlow(flow1())
.recipientFlow(flow2())
.recipientFlow(flow3()),
gatherer ->
gatherer
.releaseLockBeforeSend(true)
.releaseStrategy(group -> group.size() == 2))
.aggregate(prepareSomeRequest())
.to(getDec());
}
// Saving the request to the database
@Bean
public IntegrationFlow flow1() {
return integrationFlowDefinition ->
integrationFlowDefinition
.channel(c -> c.executor(Executors.newCachedThreadPool()))
.handle(
(payload, header) -> {
ObjectMapper mapper = new ObjectMapper();
try {
String jsonString = mapper.writeValueAsString(payload);
JsonNode request = mapper.readTree(jsonString);
JsonNode csID = request.get("ApplicationDetails").get("CustomerId");
int customerID = mapper.treeToValue(csID, Integer.class);
return lionService.saveRequest(
payload,
String.valueOf(dbId),
customerID,
((SourceSystem) Objects.requireNonNull(header.get("sourceSystem")))
.getSourceSystemCode());
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
}
)
.nullChannel();
}
//
@Bean
public IntegrationFlow flow3() {
return integrationFlowDefinition ->
integrationFlowDefinition
.channel(c -> c.executor(Executors.newCachedThreadPool()))
.transform(
message ->
loansService.someMethod(
(LionRequest) message));
}
//Here I'm calling a service through HTTPOUTBOUNDGATEWAY and if that called service is down then it throws HTTP STAtus error so I want to handle that and want to send null from this flow.
@Bean
public IntegrationFlow flow2() {
return integrationFlowDefinition ->
integrationFlowDefinition
.channel(c -> c.executor(Executors.newCachedThreadPool()))
.handle(
(payload, header) ->
loansService.someMethod2(
(LionRequest) payload,
(SourceSystem) (Objects.requireNonNull(header.get("sourceSystem")))))
.handle(
Http.outboundGateway(someurl)
.httpMethod(HttpMethod.POST)
.expectedResponseType(String.class)
);
}
@Bean
public IntegrationFlow getDec() {
return flow ->
flow.handle(
Http.outboundGateway(ServiceURL)
.httpMethod(HttpMethod.POST)
.expectedResponseType(CrResponse.class));
}
@Bean
public MessageChannel replyChannel() {
return MessageChannels.executor("output-flow", outputExecutor()).get();
}
@Bean
public ThreadPoolTaskExecutor outputExecutor() {
ThreadPoolTaskExecutor pool = new ThreadPoolTaskExecutor();
pool.setCorePoolSize(4);
pool.setMaxPoolSize(4);
return pool;
}
//here I want to take out null from messages which is sent by flow2 if the called service is down and then I want to send null to someMethod2 method.
public MessageGroupProcessor prepareSomeRequest() {
return group -> {
String cData;
Object CDReq;
List<Message<?>> messages = group.streamMessages().collect(Collectors.toList());
ArrayList<Object> payloads = (ArrayList<Object>) messages.get(0).getPayload();
if (payloads.get(0).toString().contains("tribv")) {
cData= payloads.get(0).toString();
logger.atInfo().log("Customer data from Data Sourcing Service : " + cData);
CDReq= payloads.get(1);
} else {
cData= payloads.get(1).toString();
logger.atInfo().log("Customer data from Data Sourcing Service : " + cData);
CDReq = payloads.get(0);
}
Object fReq =
lionservice.someMethod2(cData, CDReq);
SomeRequest somreq= new SomeRequest();
ObjectMapper mapper = new ObjectMapper();
JsonNode req = mapper.valueToTree(freq);
creditDecisionRequest.setfsfgg(req);
creditDecisionRequest.setR("234565432");
creditDecisionRequest.setD(String.valueOf(dbId));
creditDecisionRequest.setCID("33333333");
creditDecisionRequest.setSourceSystemCode(SourceSystem.ONE.getSourceSystemCode());
return somreq;
};
}
Gateway
@Gateway(requestChannel = "flow.input")
void processLionRequest(
@Payload Message lionRequest, @Header("sourceSystem") SourceSystem sourceSystem);
Can I use something like .errorHandler()
in the outboundgateway? But how do I use that?
@Bean
public IntegrationFlow flow2() {
return integrationFlowDefinition ->
integrationFlowDefinition
.channel(c -> c.executor(Executors.newCachedThreadPool()))
.handle(
(payload, header) ->
lionService.prepareSomeRequest(
(LionRequest) payload,
(SourceSystem) (Objects.requireNonNull(header.get("sourceSystem")))))
.handle(
Http.outboundGateway(someurl)
.httpMethod(HttpMethod.POST)
.expectedResponseType(String.class),
c -> c.advice(expressionAdvice()));
}
@Bean
public Advice expressionAdvice() {
ExpressionEvaluatingRequestHandlerAdvice advice =
new ExpressionEvaluatingRequestHandlerAdvice();
advice.setSuccessChannelName("success.input");
advice.setOnSuccessExpressionString("payload + ' was successful'");
advice.setFailureChannelName("failure.input");
advice.setOnFailureExpressionString("Failed");
advice.setReturnFailureExpressionResult(true);
advice.setTrapException(true);
return advice;
}
@Bean
public IntegrationFlow success() {
return f -> f.handle(System.out::println);
}
@Bean
public IntegrationFlow failure() {
return f -> f.handle(System.out::println);
}
public String adviceOnFailure() {
return "Failed";
}
I'm doing something like that but getting error as below -
[GenericMessage [payload=[org.springframework.expression.spel.SpelEvaluationException: EL1008E: Property or field 'Failed' cannot be found on object of type 'org.springframework.messaging.support.GenericMessage' - maybe not public or not valid?], headers={sequenceNumber=1, sequenceDetails=[[f596d446-9816-e13b-240c-f365338a5eb4, 1, 1]], replyChannel=nullChannel, sourceSystem=ONE, sequenceSize=1, correlationId=f596d446-9816-e13b-240c-f365338a5eb4, id=5592b1da-19fd-0567-c728-71b47d46b2d5, timestamp=1658382273446}]]
I want String "Failed" to be in the message, so that I can take that string and process further. Kindly help.