Skip to content

Commit

Permalink
feat: [SRTP-132] forward send to epc mock (#58)
Browse files Browse the repository at this point in the history
  • Loading branch information
and-mora authored Jan 23, 2025
1 parent 06e0878 commit 0f2e665
Show file tree
Hide file tree
Showing 13 changed files with 298 additions and 180 deletions.
1 change: 1 addition & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ tasks.compileJava {
dependsOn("generateOpenAPISend")
dependsOn("generateOpenAPIEPC")
dependsOn("generateOpenAPIActivateClient")
dependsOn("generateOpenAPIEPCClient")
}

sourceSets {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
package it.gov.pagopa.rtp.activator;

import it.gov.pagopa.rtp.activator.configuration.ActivationPropertiesConfig;
import it.gov.pagopa.rtp.activator.configuration.ServiceProviderConfig;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.ConfigurationPropertiesScan;

import org.springframework.boot.context.properties.EnableConfigurationProperties;
import reactor.core.publisher.Hooks;

@SpringBootApplication
@ConfigurationPropertiesScan()
@EnableConfigurationProperties({ActivationPropertiesConfig.class, ServiceProviderConfig.class})
public class RtpActivatorApplication {

public static void main(String[] args) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import it.gov.pagopa.rtp.activator.activateClient.api.ReadApi;
import it.gov.pagopa.rtp.activator.activateClient.invoker.ApiClient;
import it.gov.pagopa.rtp.activator.epcClient.api.DefaultApi;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.function.client.WebClient;
Expand All @@ -23,4 +24,11 @@ public ApiClient apiClient(WebClient webClient) {
public ReadApi readApi(ApiClient apiClient) {
return new ReadApi(apiClient);
}

@Bean
public DefaultApi defaultApi(ServiceProviderConfig serviceProviderConfig) {
var httpClient = new DefaultApi();
httpClient.getApiClient().setBasePath(serviceProviderConfig.send().epcMockUrl());
return httpClient;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,26 @@
import org.springframework.boot.context.properties.ConfigurationProperties;

@ConfigurationProperties(prefix = "service-provider")
public record ServiceProviderConfig(String apiVersion) {
public record ServiceProviderConfig(
Activation activation,
Send send
) {

}
public record Activation(String apiVersion) {

}

public record Send(
String epcMockUrl,
Retry retry
) {

public record Retry(
long maxAttempts,
long backoffMinDuration,
double backoffJitter
) {

}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import it.gov.pagopa.rtp.activator.domain.errors.PayerNotActivatedException;
import it.gov.pagopa.rtp.activator.domain.rtp.Rtp;
import it.gov.pagopa.rtp.activator.domain.rtp.RtpRepository;
import it.gov.pagopa.rtp.activator.epcClient.api.DefaultApi;
import it.gov.pagopa.rtp.activator.model.generated.epc.ActiveOrHistoricCurrencyAndAmountEPC25922V30DS02WrapperDto;
import it.gov.pagopa.rtp.activator.model.generated.epc.ExternalOrganisationIdentification1CodeEPC25922V30DS022WrapperDto;
import it.gov.pagopa.rtp.activator.model.generated.epc.ExternalPersonIdentification1CodeEPC25922V30DS02WrapperDto;
Expand All @@ -23,12 +24,15 @@
import it.gov.pagopa.rtp.activator.model.generated.epc.OrganisationIdentification29EPC25922V30DS022WrapperDto;
import it.gov.pagopa.rtp.activator.model.generated.epc.PersonIdentification13EPC25922V30DS02WrapperDto;
import it.gov.pagopa.rtp.activator.model.generated.epc.SepaRequestToPayRequestResourceDto;
import java.time.Duration;
import java.util.UUID;
import lombok.extern.slf4j.Slf4j;
import org.springframework.aot.hint.annotation.RegisterReflectionForBinding;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClientResponseException;
import reactor.core.publisher.Mono;
import reactor.util.retry.Retry;
import reactor.util.retry.RetryBackoffSpec;

@Service
@Slf4j
Expand All @@ -49,33 +53,53 @@ public class SendRTPServiceImpl implements SendRTPService {
private final ObjectMapper objectMapper;
private final ServiceProviderConfig serviceProviderConfig;
private final RtpRepository rtpRepository;
private final DefaultApi sendApi;

public SendRTPServiceImpl(SepaRequestToPayMapper sepaRequestToPayMapper, ReadApi activationApi,
ServiceProviderConfig serviceProviderConfig, RtpRepository rtpRepository) {
ServiceProviderConfig serviceProviderConfig, RtpRepository rtpRepository,
DefaultApi sendApi) {
this.sepaRequestToPayMapper = sepaRequestToPayMapper;
this.activationApi = activationApi;
this.serviceProviderConfig = serviceProviderConfig;
this.rtpRepository = rtpRepository;
this.sendApi = sendApi;
this.objectMapper = new ObjectMapper().enable(SerializationFeature.INDENT_OUTPUT);
}

@Override
public Mono<Rtp> send(Rtp rtp) {

return activationApi.findActivationByPayerId(UUID.randomUUID(), rtp.payerId(),
serviceProviderConfig.apiVersion())
serviceProviderConfig.activation().apiVersion())
.onErrorMap(WebClientResponseException.class, this::mapActivationResponseToException)
.map(act -> act.getPayer().getRtpSpId())
.map(rtp::toRtpWithActivationInfo)
.flatMap(rtpRepository::save)
// replace log with http request to external service
.flatMap(this::logRtpAsJson)
.flatMap(rtpToSend ->
// response is ignored atm
sendApi.postRequestToPayRequests(UUID.randomUUID(), UUID.randomUUID().toString(),
sepaRequestToPayMapper.toEpcRequestToPay(rtpToSend))
.retryWhen(sendRetryPolicy())
.onErrorMap(Throwable::getCause)
.map(response -> rtpToSend)
.defaultIfEmpty(rtpToSend)
)
.map(rtp::toRtpSent)
.flatMap(rtpRepository::save)
.doOnSuccess(rtpSaved -> log.info("RTP saved with id: {}", rtpSaved.resourceID().getId()))
.onErrorMap(WebClientResponseException.class, this::mapResponseToException)
.onErrorMap(WebClientResponseException.class, this::mapExternalSendResponseToException)
.switchIfEmpty(Mono.error(new PayerNotActivatedException()));
}

private Throwable mapActivationResponseToException(WebClientResponseException exception) {
return switch (exception.getStatusCode()) {
case NOT_FOUND -> new PayerNotActivatedException();
case BAD_REQUEST -> new MessageBadFormed(exception.getResponseBodyAsString());
default -> new RuntimeException("Internal Server Error");
};
}

private Mono<Rtp> logRtpAsJson(Rtp rtp) {
log.info(rtpToJson(rtp));
return Mono.just(rtp);
Expand All @@ -84,19 +108,22 @@ private Mono<Rtp> logRtpAsJson(Rtp rtp) {
private String rtpToJson(Rtp rtpToLog) {
try {
return objectMapper.writeValueAsString(
sepaRequestToPayMapper.toRequestToPay(rtpToLog));
sepaRequestToPayMapper.toEpcRequestToPay(rtpToLog));
} catch (JsonProcessingException e) {
log.error("Problem while serializing SepaRequestToPayRequestResourceDto object", e);
return "";
}
}

private Throwable mapResponseToException(WebClientResponseException exception) {
return switch (exception.getStatusCode()) {
case NOT_FOUND -> new PayerNotActivatedException();
case BAD_REQUEST -> new MessageBadFormed(exception.getResponseBodyAsString());
default -> new RuntimeException("Internal Server Error");
};
private RetryBackoffSpec sendRetryPolicy() {
return Retry.backoff(serviceProviderConfig.send().retry().maxAttempts(),
Duration.ofMillis(serviceProviderConfig.send().retry().backoffMinDuration()))
.jitter(serviceProviderConfig.send().retry().backoffJitter())
.doAfterRetry(signal -> log.info("Retry number {}", signal.totalRetries()));
}

private Throwable mapExternalSendResponseToException(WebClientResponseException exception) {
return new UnsupportedOperationException("Unsupported exception handling for epc response");
}

}
Loading

0 comments on commit 0f2e665

Please sign in to comment.