Added state flow

This commit is contained in:
Inal Arsanukaev 2019-06-17 13:30:29 +03:00
parent 579cb78455
commit e3fd0aa352
24 changed files with 245 additions and 47 deletions

View File

@ -5,7 +5,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>com.rbkmoney</groupId>
<artifactId>adapter-bank-payout-spring-boot-starter</artifactId>
<version>0.0.3-SNAPSHOT</version>
<version>0.0.4-SNAPSHOT</version>
<packaging>jar</packaging>
<name>Adapter-bank-payout-spring-boot-starter</name>
@ -16,9 +16,8 @@
<java.version>8</java.version>
<spring-boot.version>2.1.1.RELEASE</spring-boot.version>
<damsel-utils.version>2.1.9</damsel-utils.version>
<damsel.version>1.256-2afe121</damsel.version>
<damsel.version>1.303-d99319c</damsel.version>
<serializer.version>0.6.7</serializer.version>
<hellgate-adapter-client.version>2.1.9</hellgate-adapter-client.version>
<error-mapping.version>1.0.2</error-mapping.version>
</properties>

View File

@ -1,7 +0,0 @@
package com.rbkmoney.adapter.bank.payout.spring.boot.starter.client;
public interface RemoteClient<T, R> {
R payout(T request);
}

View File

@ -0,0 +1,21 @@
package com.rbkmoney.adapter.bank.payout.spring.boot.starter.config.properties;
import lombok.Getter;
import lombok.Setter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.validation.annotation.Validated;
import javax.validation.constraints.NotEmpty;
@Getter
@Setter
@Configuration
@ConfigurationProperties("adapter")
@Validated
public class AdapterProperties {
@NotEmpty
private String url;
}

View File

@ -1,4 +1,4 @@
package com.rbkmoney.adapter.bank.payout.spring.boot.starter.config;
package com.rbkmoney.adapter.bank.payout.spring.boot.starter.config.properties;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.rbkmoney.adapter.common.mapper.SimpleErrorMapping;
@ -13,7 +13,7 @@ import java.io.IOException;
@Configuration
public class AppConfig {
public class ErrorMappingProperties {
@Value("${error-mapping.file}")
private Resource errorMappingFilePath;
@ -25,11 +25,4 @@ public class AppConfig {
public ErrorMapping errorMapping() throws IOException {
return new SimpleErrorMapping(errorMappingFilePath, errorMappingPattern).getErrorMapping();
}
@Bean
public ObjectMapper objectMapper(){
return new SimpleObjectMapper().getSimpleObjectMapper();
}
}

View File

@ -0,0 +1,24 @@
package com.rbkmoney.adapter.bank.payout.spring.boot.starter.config.properties;
import lombok.Getter;
import lombok.Setter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.validation.annotation.Validated;
import javax.validation.constraints.NotNull;
@Configuration
@ConfigurationProperties("time.config")
@Validated
@Getter
@Setter
public class TimerProperties {
@NotNull
private int maxTimePolling;
@NotNull
private int pollingDelay;
}

View File

@ -0,0 +1,8 @@
package com.rbkmoney.adapter.bank.payout.spring.boot.starter.converter;
import com.rbkmoney.adapter.bank.payout.spring.boot.starter.model.ExitStateModel;
import com.rbkmoney.damsel.withdrawals.provider_adapter.ProcessResult;
public interface ExitStateToProcessResultConverter<X extends ExitStateModel> {
ProcessResult convert(X exitStateModel);
}

View File

@ -1,11 +1,12 @@
package com.rbkmoney.adapter.bank.payout.spring.boot.starter.converter;
import com.rbkmoney.adapter.bank.payout.spring.boot.starter.model.EntryStateModel;
import com.rbkmoney.damsel.msgpack.Value;
import com.rbkmoney.damsel.withdrawals.provider_adapter.Withdrawal;
import java.util.Map;
public interface WithdrawalConverter<T> {
public interface WithdrawalToEntryStateConverter<T extends EntryStateModel> {
T convert(Withdrawal withdrawal, Value state, Map<String, String> options);

View File

@ -0,0 +1,4 @@
package com.rbkmoney.adapter.bank.payout.spring.boot.starter.exception;
public class ValidationException extends RuntimeException {
}

View File

@ -0,0 +1,10 @@
package com.rbkmoney.adapter.bank.payout.spring.boot.starter.flow;
import com.rbkmoney.adapter.bank.payout.spring.boot.starter.model.EntryStateModel;
import com.rbkmoney.adapter.bank.payout.spring.boot.starter.model.ExitStateModel;
import com.rbkmoney.adapter.bank.payout.spring.boot.starter.model.Step;
public interface StepResolver<T extends EntryStateModel, X extends ExitStateModel> {
Step resolveEntry(T entryStateModel);
Step resolveExit(X exitStateModel);
}

View File

@ -0,0 +1,9 @@
package com.rbkmoney.adapter.bank.payout.spring.boot.starter.handler;
import com.rbkmoney.adapter.bank.payout.spring.boot.starter.model.EntryStateModel;
import com.rbkmoney.adapter.bank.payout.spring.boot.starter.model.ExitStateModel;
public interface CommonHandler<T extends EntryStateModel, X extends ExitStateModel> {
boolean isHandle(T entryStateModel);
X handle(T entryStateModel);
}

View File

@ -0,0 +1,24 @@
package com.rbkmoney.adapter.bank.payout.spring.boot.starter.handler;
import com.rbkmoney.adapter.bank.payout.spring.boot.starter.model.EntryStateModel;
import com.rbkmoney.adapter.bank.payout.spring.boot.starter.model.ExitStateModel;
import com.rbkmoney.adapter.bank.payout.spring.boot.starter.processor.Processor;
import lombok.RequiredArgsConstructor;
import org.springframework.core.convert.converter.Converter;
import java.util.function.Function;
@RequiredArgsConstructor
public abstract class CommonHandlerImpl<P, R, T extends EntryStateModel, X extends ExitStateModel> implements CommonHandler<T, X> {
private final Function<P, R> requestFunction;
private final Converter<T, P> converter;
private final Processor<R, T, X> processor;
@Override
public X handle(T entryStateModel) {
P request = converter.convert(entryStateModel);
R response = requestFunction.apply(request);
return processor.process(response, entryStateModel);
}
}

View File

@ -0,0 +1,18 @@
package com.rbkmoney.adapter.bank.payout.spring.boot.starter.model;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.Instant;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class AdapterState {
private Step step;
private Instant maxDateTimePolling;
private TransactionInfo trxInfo;
}

View File

@ -0,0 +1,16 @@
package com.rbkmoney.adapter.bank.payout.spring.boot.starter.model;
import lombok.Data;
import java.util.Map;
@Data
public class EntryStateModel {
private String withdrawalId;
private Long amount;
private String currencyCode;
private String pan;
private Map<String, String> options;
private AdapterState state;
}

View File

@ -0,0 +1,12 @@
package com.rbkmoney.adapter.bank.payout.spring.boot.starter.model;
import lombok.Data;
@Data
public class ExitStateModel {
private String errCode;
private String errMessage;
private AdapterState nextState;
private EntryStateModel entryStateModel;
}

View File

@ -0,0 +1,6 @@
package com.rbkmoney.adapter.bank.payout.spring.boot.starter.model;
public enum Step {
PAYOUT,
CHECK
}

View File

@ -0,0 +1,13 @@
package com.rbkmoney.adapter.bank.payout.spring.boot.starter.model;
import lombok.Builder;
import lombok.Data;
import java.util.Map;
@Data
@Builder
public class TransactionInfo {
private String trxId;
private Map<String, String> trxExtra;
}

View File

@ -0,0 +1,8 @@
package com.rbkmoney.adapter.bank.payout.spring.boot.starter.processor;
import com.rbkmoney.adapter.bank.payout.spring.boot.starter.model.EntryStateModel;
import com.rbkmoney.adapter.bank.payout.spring.boot.starter.model.ExitStateModel;
public interface Processor<R, T extends EntryStateModel, X extends ExitStateModel> {
X process(R response, T entryStateModel);
}

View File

@ -1,7 +0,0 @@
package com.rbkmoney.adapter.bank.payout.spring.boot.starter.processor;
public interface ResultProcessor<T, R> {
R process(T t);
}

View File

@ -0,0 +1,26 @@
package com.rbkmoney.adapter.bank.payout.spring.boot.starter.serializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.rbkmoney.adapter.bank.payout.spring.boot.starter.model.AdapterState;
import com.rbkmoney.adapter.common.serializer.StateSerializer;
import java.io.IOException;
public class AdapterStateSerializer extends StateSerializer<AdapterState> {
public AdapterStateSerializer(ObjectMapper mapper) {
super(mapper);
}
@Override
public AdapterState read(byte[] data) {
if (data == null) {
return new AdapterState();
}
try {
return getMapper().readValue(data, AdapterState.class);
} catch (IOException e) {
throw new IllegalArgumentException(e);
}
}
}

View File

@ -1,32 +1,46 @@
package com.rbkmoney.adapter.bank.payout.spring.boot.starter.service;
import com.rbkmoney.adapter.bank.payout.spring.boot.starter.client.RemoteClient;
import com.rbkmoney.adapter.bank.payout.spring.boot.starter.converter.WithdrawalConverter;
import com.rbkmoney.adapter.bank.payout.spring.boot.starter.processor.ResultProcessor;
import com.rbkmoney.adapter.bank.payout.spring.boot.starter.converter.ExitStateToProcessResultConverter;
import com.rbkmoney.adapter.bank.payout.spring.boot.starter.converter.WithdrawalToEntryStateConverter;
import com.rbkmoney.adapter.bank.payout.spring.boot.starter.flow.StepResolver;
import com.rbkmoney.adapter.bank.payout.spring.boot.starter.handler.CommonHandler;
import com.rbkmoney.adapter.bank.payout.spring.boot.starter.model.EntryStateModel;
import com.rbkmoney.adapter.bank.payout.spring.boot.starter.model.ExitStateModel;
import com.rbkmoney.adapter.bank.payout.spring.boot.starter.validator.WithdrawalValidator;
import com.rbkmoney.adapter.common.exception.UnsupportedMethodException;
import com.rbkmoney.damsel.msgpack.Value;
import com.rbkmoney.damsel.withdrawals.provider_adapter.AdapterSrv;
import com.rbkmoney.damsel.withdrawals.provider_adapter.ProcessResult;
import com.rbkmoney.damsel.withdrawals.provider_adapter.Withdrawal;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.apache.thrift.TException;
import java.util.List;
import java.util.Map;
@Slf4j
@Component
@RequiredArgsConstructor
public class PayoutAdapterService<R, T> implements AdapterSrv.Iface {
public class PayoutAdapterService<T extends EntryStateModel, X extends ExitStateModel> implements AdapterSrv.Iface {
private final WithdrawalConverter<T> converter;
private final RemoteClient<T, R> client;
private final ResultProcessor<R, ProcessResult> resultProcessorChain;
private final WithdrawalToEntryStateConverter<T> withdrawalToEntryStateConverter;
private final ExitStateToProcessResultConverter<X> exitStateToProcessResultConverter;
private final List<CommonHandler<T, X>> handlers;
private final StepResolver resolver;
private final WithdrawalValidator validator;
@Override
public ProcessResult processWithdrawal(Withdrawal withdrawal, Value state, Map<String, String> options) {
T request = converter.convert(withdrawal, state, options);
R response = client.payout(request);
return resultProcessorChain.process(response);
public ProcessResult processWithdrawal(Withdrawal withdrawal, Value state, Map<String, String> options) throws TException {
validator.validate(withdrawal, state, options);
T entryStateModel = withdrawalToEntryStateConverter.convert(withdrawal, state, options);
entryStateModel.getState().setStep(resolver.resolveEntry(entryStateModel));
X exitStateModel = handlers.stream()
.filter(h -> h.isHandle(entryStateModel))
.findFirst()
.orElseThrow(UnsupportedMethodException::new)
.handle(entryStateModel);
exitStateModel.getNextState().setStep(resolver.resolveExit(exitStateModel));
return exitStateToProcessResultConverter.convert(exitStateModel);
}
}

View File

@ -7,8 +7,6 @@ import com.rbkmoney.damsel.withdrawals.provider_adapter.Withdrawal;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.thrift.TException;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
import java.util.Map;

View File

@ -0,0 +1,11 @@
package com.rbkmoney.adapter.bank.payout.spring.boot.starter.validator;
import com.rbkmoney.adapter.bank.payout.spring.boot.starter.exception.ValidationException;
import com.rbkmoney.damsel.msgpack.Value;
import com.rbkmoney.damsel.withdrawals.provider_adapter.Withdrawal;
import java.util.Map;
public interface WithdrawalValidator {
void validate(Withdrawal withdrawal, Value state, Map<String, String> options) throws ValidationException;
}

View File

@ -1,7 +1,5 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.rbkmoney.adapter.bank.payout.spring.boot.starter.config.ErrorMappingConfiguration,\
com.rbkmoney.adapter.bank.payout.spring.boot.starter.config.properties.TimerProperties,\
com.rbkmoney.adapter.bank.payout.spring.boot.starter.config.properties.ErrorMappingProperties,\
com.rbkmoney.adapter.bank.payout.spring.boot.starter.config.properties.AdapterProperties,\
com.rbkmoney.adapter.bank.payout.spring.boot.starter.service.PayoutAdapterService,\
com.rbkmoney.adapter.bank.payout.spring.boot.starter.config.FilterConfiguration
com.rbkmoney.adapter.bank.payout.spring.boot.starter.config.properties.TimerProperties

View File

@ -1,6 +1,5 @@
---
time.config:
redirectTimeout: 600
maxTimePolling: 600
pollingDelay: 10
---