mirror of
https://github.com/valitydev/adapter-common-lib.git
synced 2024-11-06 02:05:18 +00:00
remove spring annatations (#27)
This commit is contained in:
parent
f6a55bae8b
commit
66c87c8352
430
docs/common.md
430
docs/common.md
@ -1,430 +0,0 @@
|
||||
# Общие данные по проекту при написании адаптера
|
||||
|
||||
### Оглавление:
|
||||
|
||||
- [Структура проекта](#Структура-проекта)
|
||||
- [Конфигурация](#configuration)
|
||||
- [AppConfiguration](#appconfiguration)
|
||||
- [HandlerConfiguration](#handlerconfiguration)
|
||||
- [ProcessorConfiguration](#processorconfiguration)
|
||||
- [Конвертеры](#converter)
|
||||
- [entry](#entry)
|
||||
- [exit](#exit)
|
||||
- [request](#request)
|
||||
- [flow](#flow)
|
||||
- [handler](#handler)
|
||||
- [processor](#processor)
|
||||
|
||||
### Структура проекта
|
||||
|
||||
```
|
||||
├── src
|
||||
│ ├── main
|
||||
│ │ ├── java
|
||||
│ │ │ └── dev
|
||||
│ │ │ └── vality
|
||||
│ │ │ └── adapter
|
||||
│ │ │ └── provider
|
||||
│ │ │ ├── AdapterProviderApplication.java
|
||||
│ │ │ ├── client - клиент для обращения к провайдеру
|
||||
│ │ │ │ ├── ProviderClient.java
|
||||
│ │ │ │ ├── ProviderClientException.java
|
||||
│ │ │ │ ├── constant
|
||||
│ │ │ │ └── model
|
||||
│ │ │ ├── configuration - конфигурационные файлы
|
||||
│ │ │ │ ├── AppConfiguration.java - основные конфигурации приложения
|
||||
│ │ │ │ ├── HandlerConfiguration.java - описание handler-ов
|
||||
│ │ │ │ ├── ProcessorConfiguration.java - описание processor-ов, они вкладываются друг в друга
|
||||
│ │ │ │ ├── RestTemplateConfiguration.java
|
||||
│ │ │ │ ├── TomcatEmbeddedConfiguration.java
|
||||
│ │ │ │ └── properties - параметры
|
||||
│ │ │ │ ├── IPayProperties.java
|
||||
│ │ │ │ └── RestTemplateProperties.java
|
||||
│ │ │ ├── converter
|
||||
│ │ │ │ ├── entry - конвертация входящих объектов в модель общего входа
|
||||
│ │ │ │ │ ├── CtxToEntryModelConverter.java
|
||||
│ │ │ │ │ └── RecCtxToEntryModelConverter.java
|
||||
│ │ │ │ ├── exit - конвертация исходящих объектов в модель общего выхода
|
||||
│ │ │ │ │ ├── ExitModelToProxyResultConverter.java
|
||||
│ │ │ │ │ └── ExitModelToRecTokenProxyResultConverter.java
|
||||
│ │ │ │ └── request - конвертация из модели общего входа в модели запросов к провайдеру
|
||||
│ │ │ │ ├── EntryStateToCancelRequestConverter.java
|
||||
│ │ │ │ ├── EntryStateToCaptureHandler.java
|
||||
│ │ │ │ ├── EntryStateToRefundRequestConverter.java
|
||||
│ │ │ │ ├── EntryStateToRegisterPreAuthRequestConverter.java
|
||||
│ │ │ │ ├── EntryStateToStatusRequestConverter.java
|
||||
│ │ │ ├── flow
|
||||
│ │ │ │ └── StepResolverImpl.java - определяет, какой шаг будет на входе и на выходе
|
||||
│ │ │ ├── handler - Обработчики шагов. Выполняют роль конвертации общей модели в запрос и его дальнейшее выполнение с обработкой полученного ответа
|
||||
│ │ │ │ ├── CancelHandler.java
|
||||
│ │ │ │ ├── CapturedHandler.java
|
||||
│ │ │ │ ├── PaymentOrderHandler.java
|
||||
│ │ │ │ ├── RefundHandler.java
|
||||
│ │ │ │ ├── RegisterPreAuthHandler.java
|
||||
│ │ │ │ ├── StatusHandler.java
|
||||
│ │ │ │ └── StepHandler.java
|
||||
│ │ │ ├── processor - процессоры отвечают за подготовку к общей модели выхода, описываются в ProcessorConfiguration
|
||||
│ │ │ │ ├── CommonErrorProcessor.java
|
||||
│ │ │ │ └── CommonProcessor.java
|
||||
│ │ │ ├── service
|
||||
│ │ │ │ └── AdapterIPayServerHandler.java - в нем описывается общая логика имплементирующая интерфейс для работы с провайдерами
|
||||
│ │ │ ├── servlet
|
||||
│ │ │ │ └── IPayAdapterServlet.java
|
||||
│ │ │ └── validator - необходимые проверки, например, что в опциях пришли ожидаемые параметры
|
||||
│ │ │ ├── PaymentContextValidator.java
|
||||
│ │ │ └── RecurrentTokenContextValidator.java
|
||||
│ │ └── resources
|
||||
│ │ ├── application.yml
|
||||
│ │ └── fixture
|
||||
│ │ └── errors.json - маппинг ошибок
|
||||
```
|
||||
|
||||
### configuration
|
||||
|
||||
#### AppConfiguration
|
||||
|
||||
основные конфигурации приложения, там находятся общие `beans`, например:
|
||||
|
||||
```
|
||||
@Bean
|
||||
@ConfigurationProperties("time.config")
|
||||
public CommonTimerProperties commonTimerProperties() {
|
||||
return new CommonTimerProperties();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ExponentialBackOffPollingService<PollingInfo> exponentialBackOffPollingService() {
|
||||
return new ExponentialBackOffPollingService<>();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public PaymentCallbackHandler paymentCallbackHandler(
|
||||
AdapterDeserializer adapterDeserializer,
|
||||
AdapterSerializer adapterSerializer,
|
||||
CallbackDeserializer callbackDeserializer
|
||||
) {
|
||||
return new PaymentCallbackHandler(adapterDeserializer, adapterSerializer, callbackDeserializer);
|
||||
}
|
||||
```
|
||||
|
||||
#### HandlerConfiguration
|
||||
|
||||
Конфигурация каждого описанного раннее обработчика. В примере ниже описан обработчик для шага PRE_AUTH
|
||||
|
||||
```
|
||||
@Configuration
|
||||
@RequiredArgsConstructor
|
||||
public class HandlerConfiguration {
|
||||
|
||||
private final ProviderClient providerClient;
|
||||
|
||||
private final EntryStateToRegisterPreAuthRequestConverter entryStateToRegisterPreAuthRequestConverter;
|
||||
|
||||
@Bean
|
||||
public RegisterPreAuthHandler registerPreAuthHandler(Processor<GeneralExitStateModel, Response, GeneralEntryStateModel> processor) {
|
||||
return new RegisterPreAuthHandler(providerClient, entryStateToRegisterPreAuthRequestConverter, processor);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
#### ProcessorConfiguration
|
||||
|
||||
Описывается в цепочку вызовов, матрешечный метод
|
||||
|
||||
```
|
||||
@Configuration
|
||||
public class ProcessorConfiguration {
|
||||
@Bean
|
||||
public Processor<GeneralExitStateModel, Response, GeneralEntryStateModel> commonErrorProcessor(ProviderClient providerClient) {
|
||||
Processor<GeneralExitStateModel, Response, GeneralEntryStateModel> commonProcessor = new CommonProcessor(providerClient);
|
||||
return new CommonErrorProcessor(commonProcessor);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Converter
|
||||
|
||||
#### entry
|
||||
|
||||
Содержит в себе классы, которые конвертируют входящие модели и структуры в общую модель входа GeneralEntryStateModel с
|
||||
которой далее и работаем.
|
||||
|
||||
```
|
||||
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class CtxToEntryModelConverter implements Converter<PaymentContext, GeneralEntryStateModel> {
|
||||
|
||||
private final CdsClientStorage cdsStorage;
|
||||
private final AdapterDeserializer adapterDeserializer;
|
||||
|
||||
@Override
|
||||
public GeneralEntryStateModel convert(PaymentContext context) {
|
||||
// any code
|
||||
return GeneralEntryStateModel.builder()
|
||||
.trxId(payment.getTrx() != null ? payment.getTrx().getId() : adapterContext.getTrxId())
|
||||
.trxExtra(payment.getTrx() != null ? payment.getTrx().getExtra() : new HashMap<>())
|
||||
.orderId(orderId)
|
||||
.amount(cash.getAmount())
|
||||
.refundAmount(cash.getAmount())
|
||||
.currencySymbolCode(payment.getCost().getCurrency().getSymbolicCode())
|
||||
.currencyCode(payment.getCost().getCurrency().getNumericCode())
|
||||
.createdAt(createdAt)
|
||||
.pan(cardData != null ? cardData.getPan() : null)
|
||||
.cvv2(CardDataUtils.extractCvv2(sessionData))
|
||||
.expYear(cardData != null ? cardData.getExpYear() : null)
|
||||
.expMonth(cardData != null ? cardData.getExpMonth() : null)
|
||||
.cardHolder(cardData != null ? cardData.getCardholderName() : null)
|
||||
.email(PaymentDataConverter.extractEmail(context.getPaymentInfo()))
|
||||
.options(paymentContext.getOptions())
|
||||
.makeRecurrent(payment.make_recurrent)
|
||||
.callbackUrl(redirectUrl)
|
||||
.ip(ipAddress)
|
||||
.trxExtra(extra)
|
||||
.adapterContext(adapterContext)
|
||||
.targetStatus(targetStatus)
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
#### exit
|
||||
|
||||
Содержит в себе классы, которые конвертируют из общей модели выхода в PaymentProxyResult, в них производится анализ на
|
||||
основании шага (step), какой intent подготовить
|
||||
|
||||
```
|
||||
@Slf4j
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class ExitModelToProxyResultConverter implements Converter<GeneralExitStateModel, PaymentProxyResult> {
|
||||
|
||||
private final CommonTimerProperties timerProperties;
|
||||
private final ErrorMapping errorMapping;
|
||||
private final AdapterSerializer adapterSerializer;
|
||||
private final ExponentialBackOffPollingService<PollingInfo> exponentialBackOffPollingService;
|
||||
|
||||
@Override
|
||||
public PaymentProxyResult convert(GeneralExitStateModel exitStateModel) {
|
||||
log.info("PaymentProxy exit state model: {}", exitStateModel);
|
||||
if (!StringUtils.isEmpty(exitStateModel.getErrorCode())) {
|
||||
log.info("Exit error code={}, message={}", exitStateModel.getErrorCode(), exitStateModel.getErrorMessage());
|
||||
Failure failure = errorMapping.mapFailure(exitStateModel.getErrorCode());
|
||||
return createProxyResultFailure(failure);
|
||||
}
|
||||
|
||||
AdapterContext adapterContext = exitStateModel.getAdapterContext();
|
||||
Step nextStep = exitStateModel.getAdapterContext().getStep();
|
||||
|
||||
Intent intent;
|
||||
switch (nextStep) {
|
||||
case AUTH:
|
||||
intent = createIntentWithSleepIntent(0);
|
||||
break;
|
||||
case FINISH_THREE_DS:
|
||||
intent = createIntentWithSuspendIntent(exitStateModel);
|
||||
break;
|
||||
case CHECK_STATUS:
|
||||
case CAPTURE:
|
||||
case REFUND:
|
||||
case CANCEL:
|
||||
case DO_NOTHING:
|
||||
intent = createFinishIntentSuccess();
|
||||
break;
|
||||
default:
|
||||
throw new IllegalStateException("Wrong next step: " + nextStep);
|
||||
}
|
||||
|
||||
PaymentProxyResult paymentProxyResult = new PaymentProxyResult(intent).setNextState(adapterSerializer.writeByte(adapterContext));
|
||||
paymentProxyResult.setTrx(createTransactionInfo(adapterContext.getTrxId(), exitStateModel.getTrxExtra()));
|
||||
log.info("Payment proxy result: {}", paymentProxyResult);
|
||||
return paymentProxyResult;
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
#### request
|
||||
|
||||
Содержит классы, которые из общей модели заполняют структуру для подготовки запроса к провайдеру
|
||||
|
||||
Например:
|
||||
|
||||
```
|
||||
@Component
|
||||
public class EntryStateToCancelRequestConverter implements Converter<GeneralEntryStateModel, Request> {
|
||||
|
||||
@Override
|
||||
public Request convert(GeneralEntryStateModel entryStateModel) {
|
||||
Map<String, String> options = entryStateModel.getOptions();
|
||||
String userName = options.get(OptionField.LOGIN.getField());
|
||||
String password = options.get(OptionField.PASSWORD.getField());
|
||||
|
||||
return Request.builder()
|
||||
.userName(userName)
|
||||
.password(password)
|
||||
.orderId(entryStateModel.getTrxId())
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## flow
|
||||
|
||||
StepResolverImpl - определяет шаг в самом начале и устанавливает шаг на выходе
|
||||
|
||||
```
|
||||
@Slf4j
|
||||
@Component
|
||||
public class StepResolverImpl implements StepResolver<GeneralEntryStateModel, GeneralExitStateModel> {
|
||||
|
||||
@Override
|
||||
public Step resolveEntry(GeneralEntryStateModel entryStateModel) {
|
||||
TargetStatus targetStatus = entryStateModel.getTargetStatus();
|
||||
AdapterContext adapterContext = entryStateModel.getAdapterContext();
|
||||
Step step = adapterContext.getStep();
|
||||
|
||||
if (targetStatus == null) {
|
||||
return Objects.requireNonNullElse(step, Step.PRE_AUTH);
|
||||
}
|
||||
|
||||
log.info("Entry resolver. Target status: {}. Step: {}", targetStatus, step);
|
||||
switch (targetStatus) {
|
||||
case PROCESSED:
|
||||
return Objects.requireNonNullElse(step, Step.PRE_AUTH);
|
||||
case CAPTURED:
|
||||
return Step.CAPTURE;
|
||||
case CANCELLED:
|
||||
return Step.CANCEL;
|
||||
case REFUNDED:
|
||||
return Step.REFUND;
|
||||
default:
|
||||
throw new IllegalStateException("Unknown target status: " + targetStatus);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Step resolveExit(GeneralExitStateModel exitStateModel) {
|
||||
GeneralEntryStateModel entryStateModel = exitStateModel.getGeneralEntryStateModel();
|
||||
Step step = entryStateModel.getAdapterContext().getStep();
|
||||
log.info("Exit resolver. Step: {}", step);
|
||||
switch (step) {
|
||||
case PRE_AUTH:
|
||||
return Step.AUTH;
|
||||
case AUTH:
|
||||
return Step.FINISH_THREE_DS;
|
||||
case CAPTURE:
|
||||
return Step.CAPTURE;
|
||||
case FINISH_THREE_DS:
|
||||
return Step.CHECK_STATUS;
|
||||
case CHECK_STATUS:
|
||||
return Step.DO_NOTHING;
|
||||
default:
|
||||
return step;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
#### handler
|
||||
|
||||
Обработчики шагов.
|
||||
|
||||
Выполняют роль конвертации общей модели в запрос и его дальнейшее выполнение с обработкой полученного ответа Handler'ы
|
||||
описываются в CommonHandler, то есть если не использовать CommonHandler, можно и не использовать processor и converter
|
||||
|
||||
В примере ниже видно, что данный класс будет использован, если удовлетворит условию `step == Step.CANCEL`, т.е. в данном
|
||||
случае будет выбран обработчик для вызова отмены платежа, после того, как будет известен обработчик, у него будет вызван
|
||||
метод handle(GeneralEntryStateModel entryStateModel) находящийся в `StepHandler`
|
||||
|
||||
Передаем в `StepHandler<Request, Response>`(который имплементирует CommonHandler) объекты, которые ожидаем в качестве
|
||||
запроса и ответа от провайдера
|
||||
|
||||
Видно, что в качестве объекта для запроса используется класс Request, в качестве ожидаемого ответа Response
|
||||
|
||||
Для обращения к провайдеру используется клиент `ProviderClient` с вызовом метода `reverse`.
|
||||
|
||||
Конвертор заполнит модель Request данными из модели GeneralEntryStateModel
|
||||
|
||||
Процессор на основании полученного `Response` и `GeneralEntryStateModel` заполнит `GeneralExitStateModel`
|
||||
|
||||
```
|
||||
public class CancelHandler extends StepHandler<Request, Response> {
|
||||
|
||||
public CancelHandler(
|
||||
ProviderClient providerClient,
|
||||
Converter<GeneralEntryStateModel, Request> converter,
|
||||
Processor<GeneralExitStateModel, Response, GeneralEntryStateModel> processor
|
||||
) {
|
||||
super(providerClient::reverse, converter, processor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isHandle(GeneralEntryStateModel entryStateModel) {
|
||||
Step step = entryStateModel.getAdapterContext().getStep();
|
||||
return step == Step.CANCEL;
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
ps важно помнить, что после добавлении нового handler-а, нужно его прописать
|
||||
в [HandlerConfiguration](#handlerconfiguration), но до этого, придется еще
|
||||
написать [entry](#entry) [converter-ы](#converter) для [handler-а](#handler), описать [processor](#processor) и модель
|
||||
ответа, нашем случае это Response
|
||||
|
||||
#### Processor
|
||||
|
||||
Процессоры отвечают за подготовку к общей модели выхода (GeneralExitStateModel), описываются в папке `processor`, а
|
||||
матрешочное поведение описывается в конфигурации `ProcessorConfiguration`.
|
||||
|
||||
Важно помнить, что после создания процессора, его необходимо добавить в [конфигурацию](#processorconfiguration).
|
||||
|
||||
Пример processor-а:
|
||||
|
||||
```
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
public class CommonErrorProcessor implements Processor<GeneralExitStateModel, Response, GeneralEntryStateModel> {
|
||||
|
||||
private final Processor<GeneralExitStateModel, Response, GeneralEntryStateModel> nextProcessor;
|
||||
|
||||
@Override
|
||||
public GeneralExitStateModel process(Response response, GeneralEntryStateModel entryStateModel) {
|
||||
log.info("Order response: {}", response);
|
||||
AdapterContext adapterContext = entryStateModel.getAdapterContext();
|
||||
|
||||
if(response.getErrorCode() != null) {
|
||||
ErrorCode errorCode = ErrorCode.findByCode(response.getErrorCode());
|
||||
return GeneralExitStateModel.builder()
|
||||
.errorCode(response.getErrorCode())
|
||||
.errorMessage(errorCode.getDescription())
|
||||
.adapterContext(adapterContext)
|
||||
.generalEntryStateModel(entryStateModel)
|
||||
.trxExtra(new HashMap<>(entryStateModel.getTrxExtra()))
|
||||
.build();
|
||||
} else if (nextProcessor != null) {
|
||||
return nextProcessor.process(response, entryStateModel);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Таким образом видно, что, если условие с ошибкой не отработало
|
||||
|
||||
```
|
||||
if(response.getErrorCode() != null)
|
||||
```
|
||||
|
||||
то, будет вызван следующий processor
|
||||
|
||||
```
|
||||
return nextProcessor.process(response, entryStateModel);
|
||||
```
|
||||
|
||||
Что, собственно, и описывается в конфигурации, см. раздел [конфигурации](#processorconfiguration)
|
2
pom.xml
2
pom.xml
@ -12,7 +12,7 @@
|
||||
</parent>
|
||||
|
||||
<artifactId>adapter-common-lib</artifactId>
|
||||
<version>1.0.5</version>
|
||||
<version>1.0.6</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>adapter-common-lib</name>
|
||||
|
@ -7,10 +7,8 @@ import dev.vality.msgpack.Value;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.thrift.TException;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class BenderClient {
|
||||
|
||||
|
@ -6,9 +6,7 @@ import dev.vality.damsel.identity_document_storage.IdentityDocumentStorageSrv;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.thrift.TException;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
public class CdsClientIDStorage {
|
||||
|
@ -10,7 +10,7 @@ import java.nio.ByteBuffer;
|
||||
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
public class HellgateAdapterClient {
|
||||
public class HellgateClient {
|
||||
|
||||
private final ProviderProxyHostSrv.Iface providerProxyHostSrv;
|
||||
|
Loading…
Reference in New Issue
Block a user