This commit is contained in:
parent
cdd322d628
commit
5f2abbd2d9
14 changed files with 243 additions and 19 deletions
|
|
@ -8,6 +8,7 @@ import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.context.annotation.Scope;
|
import org.springframework.context.annotation.Scope;
|
||||||
import ru.spcex.clearing.account.config.settings.AccountServiceSettings;
|
import ru.spcex.clearing.account.config.settings.AccountServiceSettings;
|
||||||
|
import ru.spcex.clearing.imdg.IMDGDistributedNames;
|
||||||
import ru.spcex.clearing.platform.messaging.config.KafkaConsumerFactory;
|
import ru.spcex.clearing.platform.messaging.config.KafkaConsumerFactory;
|
||||||
import ru.spcex.clearing.platform.messaging.config.KafkaProducerFactory;
|
import ru.spcex.clearing.platform.messaging.config.KafkaProducerFactory;
|
||||||
import ru.spcex.clearing.platform.messaging.service.RequestInfo;
|
import ru.spcex.clearing.platform.messaging.service.RequestInfo;
|
||||||
|
|
@ -41,7 +42,7 @@ public class KafkaConfig {
|
||||||
.producer(kafkaProducer)
|
.producer(kafkaProducer)
|
||||||
.idGenerator(imdgIdGenerator::nextId)
|
.idGenerator(imdgIdGenerator::nextId)
|
||||||
.imdgProvider(s -> {
|
.imdgProvider(s -> {
|
||||||
Imdg<RequestInfo> imdg = imdgProvider.getImdg(s, RequestInfo.class);
|
Imdg<RequestInfo> imdg = imdgProvider.getImdg(IMDGDistributedNames.Map_RequestInfo, RequestInfo.class);
|
||||||
return imdg::insert;
|
return imdg::insert;
|
||||||
})
|
})
|
||||||
.build();
|
.build();
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ public class QueueExceptionHandler extends ResponseEntityExceptionHandler {
|
||||||
@ResponseStatus(HttpStatus.BAD_REQUEST)
|
@ResponseStatus(HttpStatus.BAD_REQUEST)
|
||||||
@ResponseBody
|
@ResponseBody
|
||||||
public BasicSpcexResponse handleValidationException(ActionValidationException e) {
|
public BasicSpcexResponse handleValidationException(ActionValidationException e) {
|
||||||
log.error("Default scoring exception handler: {}", ExceptionUtils.getStackTrace(e));
|
log.error("Default exception handler: {}", ExceptionUtils.getStackTrace(e));
|
||||||
EnumMessage firstError = e.getErrors().iterator().next();
|
EnumMessage firstError = e.getErrors().iterator().next();
|
||||||
BasicSpcexResponse errorResponse = new BasicSpcexResponse();
|
BasicSpcexResponse errorResponse = new BasicSpcexResponse();
|
||||||
errorResponse.setCode(firstError.getSubject().getId());
|
errorResponse.setCode(firstError.getSubject().getId());
|
||||||
|
|
@ -68,7 +68,7 @@ public class QueueExceptionHandler extends ResponseEntityExceptionHandler {
|
||||||
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
|
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
|
||||||
@ResponseBody
|
@ResponseBody
|
||||||
public BasicSpcexResponse handleDefault(Throwable e) {
|
public BasicSpcexResponse handleDefault(Throwable e) {
|
||||||
log.error("Default scoring exception handler: {}", ExceptionUtils.getStackTrace(e));
|
log.error("Default exception handler: {}", ExceptionUtils.getStackTrace(e));
|
||||||
BasicSpcexResponse errorResponse = new BasicSpcexResponse();
|
BasicSpcexResponse errorResponse = new BasicSpcexResponse();
|
||||||
errorResponse.setCode(-1);
|
errorResponse.setCode(-1);
|
||||||
errorResponse.setMessage("internal server error");
|
errorResponse.setMessage("internal server error");
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,51 @@
|
||||||
|
package ru.spcex.clearing.backendapi.controller.response.system;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import ru.spcex.clearing.backendapi.controller.response.BasicSpcexResponse;
|
||||||
|
import ru.spcex.clearing.platform.messaging.domain.json.serialize.EnumSerializer;
|
||||||
|
import ru.spcex.clearing.platform.messaging.service.Status;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Банковские реквизиты для перечисления денежных средств
|
||||||
|
* @ApiModel(description = "Ответ в результате отправки операции в топик Kafka.")
|
||||||
|
* @ApiModelProperty(value = "Информация о принятом запросе")
|
||||||
|
**/
|
||||||
|
@ApiModel(description = "Ответ при получении статуса запроса.")
|
||||||
|
public class RequestInfoResponse extends BasicSpcexResponse {
|
||||||
|
|
||||||
|
@JsonProperty
|
||||||
|
@ApiModelProperty(value = "Поля объекта")
|
||||||
|
private RequestInfoPayload payload;
|
||||||
|
|
||||||
|
public RequestInfoPayload getPayload() {
|
||||||
|
return payload;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStatus(Status status) {
|
||||||
|
this.payload = new RequestInfoPayload();
|
||||||
|
payload.setStatus(status);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPayload(RequestInfoPayload payload) {
|
||||||
|
this.payload = payload;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class RequestInfoPayload {
|
||||||
|
@JsonProperty
|
||||||
|
@JsonSerialize(using = EnumSerializer.class)
|
||||||
|
private Status status;
|
||||||
|
|
||||||
|
public Status getStatus() {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStatus(Status status) {
|
||||||
|
this.status = status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,48 @@
|
||||||
|
package ru.spcex.clearing.backendapi.controller.system;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiOperation;
|
||||||
|
import io.swagger.annotations.ApiParam;
|
||||||
|
import io.swagger.annotations.ApiResponse;
|
||||||
|
import io.swagger.annotations.ApiResponses;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Controller;
|
||||||
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMethod;
|
||||||
|
import org.springframework.web.bind.annotation.ResponseBody;
|
||||||
|
import ru.spcex.clearing.backendapi.controller.response.BasicSpcexResponse;
|
||||||
|
import ru.spcex.clearing.backendapi.controller.response.system.RequestInfoResponse;
|
||||||
|
import ru.spcex.clearing.imdg.IMDGDistributedNames;
|
||||||
|
import ru.spcex.clearing.platform.messaging.service.RequestInfo;
|
||||||
|
import ru.spcex.platform.imdg.api.Imdg;
|
||||||
|
import ru.spcex.platform.imdg.api.ImdgProvider;
|
||||||
|
|
||||||
|
@Controller
|
||||||
|
@RequestMapping("/requests")
|
||||||
|
public class RequestStatusController {
|
||||||
|
|
||||||
|
private final Imdg<RequestInfo> imdg;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public RequestStatusController(ImdgProvider imdgProvider) {
|
||||||
|
this.imdg = imdgProvider.getImdg(IMDGDistributedNames.Map_RequestInfo, RequestInfo.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation(value = "get request status.")
|
||||||
|
@ApiResponses(value = {@ApiResponse(code = 200, message = "OK", response = RequestInfoResponse.class), @ApiResponse(code = 400, message = "Ошибка валидации", response = BasicSpcexResponse.class)})
|
||||||
|
@RequestMapping(value = "/{id}", method = RequestMethod.GET)
|
||||||
|
@ResponseBody
|
||||||
|
public RequestInfoResponse getById(@ApiParam(value = "Идентификатор объекта", required = true, example = "1234")
|
||||||
|
@PathVariable("id") Long id) {
|
||||||
|
RequestInfo singleObjectByID;
|
||||||
|
if (id == null || (singleObjectByID = imdg.getSingleObjectByID(id)) == null) {
|
||||||
|
RequestInfoResponse response = new RequestInfoResponse();
|
||||||
|
response.setCode(-1L);
|
||||||
|
response.setMessage("cannot find request with id='" + id + "'.");
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
RequestInfoResponse response = new RequestInfoResponse();
|
||||||
|
response.setStatus(singleObjectByID.getStatus());
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -8,6 +8,7 @@ import ru.spcex.clearing.backendapi.controller.response.cud.QueueSuccessResponse
|
||||||
import ru.spcex.clearing.backendapi.domain.actions.IAction;
|
import ru.spcex.clearing.backendapi.domain.actions.IAction;
|
||||||
import ru.spcex.clearing.backendapi.errors.ActionValidationException;
|
import ru.spcex.clearing.backendapi.errors.ActionValidationException;
|
||||||
import ru.spcex.clearing.backendapi.service.IOperator;
|
import ru.spcex.clearing.backendapi.service.IOperator;
|
||||||
|
import ru.spcex.clearing.imdg.IMDGDistributedNames;
|
||||||
import ru.spcex.clearing.platform.messaging.domain.BaseRequest;
|
import ru.spcex.clearing.platform.messaging.domain.BaseRequest;
|
||||||
import ru.spcex.clearing.platform.messaging.service.RequestInfo;
|
import ru.spcex.clearing.platform.messaging.service.RequestInfo;
|
||||||
import ru.spcex.platform.imdg.api.Imdg;
|
import ru.spcex.platform.imdg.api.Imdg;
|
||||||
|
|
@ -46,7 +47,7 @@ public class OperatorImpl implements IOperator {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void saveRequestToStorage(String destination, BaseRequest<Object> request) {
|
private void saveRequestToStorage(String destination, BaseRequest<Object> request) {
|
||||||
Imdg<RequestInfo> requestStorage = imdgProvider.getImdg(destination, RequestInfo.class);
|
Imdg<RequestInfo> requestStorage = imdgProvider.getImdg(IMDGDistributedNames.Map_RequestInfo, RequestInfo.class);
|
||||||
RequestInfo requestInfo = RequestInfo.create(request.getId());
|
RequestInfo requestInfo = RequestInfo.create(request.getId());
|
||||||
requestStorage.insert(requestInfo);
|
requestStorage.insert(requestInfo);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import org.apache.kafka.clients.producer.Producer;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import ru.spcex.clearing.imdg.IMDGDistributedNames;
|
||||||
import ru.spcex.clearing.platform.messaging.service.RequestInfo;
|
import ru.spcex.clearing.platform.messaging.service.RequestInfo;
|
||||||
import ru.spcex.clearing.platform.messaging.service.sender.KafkaSender;
|
import ru.spcex.clearing.platform.messaging.service.sender.KafkaSender;
|
||||||
import ru.spcex.platform.imdg.api.Imdg;
|
import ru.spcex.platform.imdg.api.Imdg;
|
||||||
|
|
@ -22,7 +23,7 @@ public class KafkaSenderConfig {
|
||||||
.producer(kafkaProducer)
|
.producer(kafkaProducer)
|
||||||
.idGenerator(imdgIdGenerator::nextId)
|
.idGenerator(imdgIdGenerator::nextId)
|
||||||
.imdgProvider(s -> {
|
.imdgProvider(s -> {
|
||||||
Imdg<RequestInfo> imdg = imdgProvider.getImdg(s, RequestInfo.class);
|
Imdg<RequestInfo> imdg = imdgProvider.getImdg(IMDGDistributedNames.Map_RequestInfo, RequestInfo.class);
|
||||||
return imdg::insert;
|
return imdg::insert;
|
||||||
})
|
})
|
||||||
.build();
|
.build();
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import ru.spcex.clearing.dbf.importer.config.settings.ImportDBFServiceSettings;
|
import ru.spcex.clearing.dbf.importer.config.settings.ImportDBFServiceSettings;
|
||||||
|
import ru.spcex.clearing.imdg.IMDGDistributedNames;
|
||||||
import ru.spcex.clearing.platform.messaging.config.KafkaProducerFactory;
|
import ru.spcex.clearing.platform.messaging.config.KafkaProducerFactory;
|
||||||
import ru.spcex.clearing.platform.messaging.service.RequestInfo;
|
import ru.spcex.clearing.platform.messaging.service.RequestInfo;
|
||||||
import ru.spcex.clearing.platform.messaging.service.sender.KafkaSender;
|
import ru.spcex.clearing.platform.messaging.service.sender.KafkaSender;
|
||||||
|
|
@ -28,7 +29,7 @@ public class KafkaConfig {
|
||||||
.producer(kafkaProducer)
|
.producer(kafkaProducer)
|
||||||
.idGenerator(imdgIdGenerator::nextId)
|
.idGenerator(imdgIdGenerator::nextId)
|
||||||
.imdgProvider(s -> {
|
.imdgProvider(s -> {
|
||||||
Imdg<RequestInfo> imdg = imdgProvider.getImdg(s, RequestInfo.class);
|
Imdg<RequestInfo> imdg = imdgProvider.getImdg(IMDGDistributedNames.Map_RequestInfo, RequestInfo.class);
|
||||||
return imdg::insert;
|
return imdg::insert;
|
||||||
})
|
})
|
||||||
.build();
|
.build();
|
||||||
|
|
|
||||||
|
|
@ -101,6 +101,7 @@ public final class IMDGDistributedNames {
|
||||||
public static final String Map_AccountStatusDictionary = "Map_AccountStatusDictionary";
|
public static final String Map_AccountStatusDictionary = "Map_AccountStatusDictionary";
|
||||||
public static final String Map_KeyRate = "Map_KeyRate";
|
public static final String Map_KeyRate = "Map_KeyRate";
|
||||||
public static final String Map_MoneyMarketSecurity = "Map_MoneyMarketSecurity";
|
public static final String Map_MoneyMarketSecurity = "Map_MoneyMarketSecurity";
|
||||||
|
public static final String Map_RequestInfo = "Map_RequestInfo";
|
||||||
public static final String MAP_SEQUENCE_NAME = "MAP_SEQUENCE_NAME"; // todo вынести idGenerator отдельно и завернуть в метод, чтобы не напрямую обращаться.
|
public static final String MAP_SEQUENCE_NAME = "MAP_SEQUENCE_NAME"; // todo вынести idGenerator отдельно и завернуть в метод, чтобы не напрямую обращаться.
|
||||||
|
|
||||||
private IMDGDistributedNames() {
|
private IMDGDistributedNames() {
|
||||||
|
|
|
||||||
|
|
@ -33,4 +33,6 @@ public interface Consts {
|
||||||
String ACCOUNT_NEW = "account-new";
|
String ACCOUNT_NEW = "account-new";
|
||||||
String BALANCE_ACCOUNT_NEW = "balance-account-new";
|
String BALANCE_ACCOUNT_NEW = "balance-account-new";
|
||||||
|
|
||||||
|
String REQUEST_INFO_UPDATE = "request-info-update";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
package ru.spcex.clearing.platform.messaging.domain.json.serialize;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.core.JsonGenerator;
|
||||||
|
import com.fasterxml.jackson.databind.JsonSerializer;
|
||||||
|
import com.fasterxml.jackson.databind.SerializerProvider;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
|
||||||
|
public class EnumSerializer extends JsonSerializer<Enum<?>> {
|
||||||
|
private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void serialize(Enum<?> value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
|
||||||
|
if (value == null) return;
|
||||||
|
gen.writeString(value.name());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -3,7 +3,9 @@ package ru.spcex.clearing.platform.messaging.logic.functional;
|
||||||
import ru.spcex.clearing.platform.messaging.domain.BaseRequest;
|
import ru.spcex.clearing.platform.messaging.domain.BaseRequest;
|
||||||
|
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
public interface BuilderConsumerStep<T1> {
|
public interface BuilderConsumerStep<T1> {
|
||||||
BuilderDestinationStep setConsumer(Consumer<BaseRequest<T1>> consumer);
|
BuilderDestinationStep setConsumer(Consumer<BaseRequest<T1>> consumer);
|
||||||
|
BuilderDestinationStep setFunction(Function<BaseRequest<T1>, Object> function);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import ru.spcex.clearing.platform.messaging.domain.BaseRequest;
|
||||||
|
|
||||||
import java.util.function.BiConsumer;
|
import java.util.function.BiConsumer;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* вспомогательный класс
|
* вспомогательный класс
|
||||||
|
|
@ -18,6 +19,7 @@ public class ConsumerSpecificClass<T> implements BuilderConsumerStep<T>, Builder
|
||||||
* действие-обработчик реквеста (метод из конкретного менеджера)
|
* действие-обработчик реквеста (метод из конкретного менеджера)
|
||||||
*/
|
*/
|
||||||
private java.util.function.Consumer<BaseRequest<T>> consumer;
|
private java.util.function.Consumer<BaseRequest<T>> consumer;
|
||||||
|
private java.util.function.Function<BaseRequest<T>, Object> function;
|
||||||
|
|
||||||
private ConsumerSpecificClass(Class<T> clazz) {
|
private ConsumerSpecificClass(Class<T> clazz) {
|
||||||
this.clazz = clazz;
|
this.clazz = clazz;
|
||||||
|
|
@ -29,7 +31,17 @@ public class ConsumerSpecificClass<T> implements BuilderConsumerStep<T>, Builder
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BuilderDestinationStep setConsumer(Consumer<BaseRequest<T>> consumer) {
|
public BuilderDestinationStep setConsumer(Consumer<BaseRequest<T>> consumer) {
|
||||||
this.consumer = consumer;
|
if (this.consumer == null) {
|
||||||
|
this.consumer = consumer;
|
||||||
|
} else {
|
||||||
|
this.consumer = this.consumer.andThen(consumer);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BuilderDestinationStep setFunction(Function<BaseRequest<T>, Object> function) {
|
||||||
|
this.function = function;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -38,10 +50,18 @@ public class ConsumerSpecificClass<T> implements BuilderConsumerStep<T>, Builder
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public void acceptRaw(Object obj) {
|
public Object acceptRaw(Object obj) {
|
||||||
this.consumer.accept((BaseRequest<T>) obj);
|
if (this.consumer != null) {
|
||||||
|
this.consumer.accept((BaseRequest<T>) obj);
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
return this.function.apply((BaseRequest<T>) obj);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Consumer<BaseRequest<T>> getConsumer() {
|
||||||
|
return consumer;
|
||||||
|
}
|
||||||
public Class<T> getClazz() {
|
public Class<T> getClazz() {
|
||||||
return clazz;
|
return clazz;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,10 +5,14 @@ import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import org.apache.kafka.clients.consumer.Consumer;
|
import org.apache.kafka.clients.consumer.Consumer;
|
||||||
import org.apache.kafka.clients.consumer.ConsumerRecord;
|
import org.apache.kafka.clients.consumer.ConsumerRecord;
|
||||||
import org.apache.kafka.clients.consumer.ConsumerRecords;
|
import org.apache.kafka.clients.consumer.ConsumerRecords;
|
||||||
|
import org.apache.kafka.clients.producer.Producer;
|
||||||
|
import org.apache.kafka.clients.producer.ProducerRecord;
|
||||||
|
import org.apache.kafka.clients.producer.RecordMetadata;
|
||||||
import org.apache.kafka.common.errors.WakeupException;
|
import org.apache.kafka.common.errors.WakeupException;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import ru.spcex.clearing.platform.messaging.domain.BaseRequest;
|
import ru.spcex.clearing.platform.messaging.domain.BaseRequest;
|
||||||
|
import ru.spcex.clearing.platform.messaging.domain.Consts;
|
||||||
import ru.spcex.clearing.platform.messaging.logic.functional.BuilderConsumerStep;
|
import ru.spcex.clearing.platform.messaging.logic.functional.BuilderConsumerStep;
|
||||||
import ru.spcex.clearing.platform.messaging.logic.functional.ConsumerSpecificClass;
|
import ru.spcex.clearing.platform.messaging.logic.functional.ConsumerSpecificClass;
|
||||||
import ru.spcex.platform.utils.log.ExceptionUtils;
|
import ru.spcex.platform.utils.log.ExceptionUtils;
|
||||||
|
|
@ -19,6 +23,7 @@ import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.Future;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -28,33 +33,40 @@ public class QueueConsumer implements AutoCloseable {
|
||||||
private final Logger log = LoggerFactory.getLogger(getClass());
|
private final Logger log = LoggerFactory.getLogger(getClass());
|
||||||
private final AtomicBoolean closed = new AtomicBoolean(false);
|
private final AtomicBoolean closed = new AtomicBoolean(false);
|
||||||
private final Consumer<String, Object> consumer;
|
private final Consumer<String, Object> consumer;
|
||||||
private final ExecutorService executor;
|
private Producer<String, Object> producer;
|
||||||
|
private final ExecutorService inputExecutor;
|
||||||
|
private final ExecutorService outputExecutor;
|
||||||
protected final Map<String, ConsumerSpecificClass<?>> callbacks;
|
protected final Map<String, ConsumerSpecificClass<?>> callbacks;
|
||||||
private final ObjectMapper json;
|
private final ObjectMapper json;
|
||||||
|
protected boolean supportStartOffsetTimeWindow;
|
||||||
|
|
||||||
public QueueConsumer(Consumer<String, Object> kafkaQueue) {
|
public QueueConsumer(Consumer<String, Object> kafkaQueue) {
|
||||||
this.consumer = kafkaQueue;
|
this.consumer = kafkaQueue;
|
||||||
this.callbacks = new HashMap<>();
|
this.callbacks = new HashMap<>();
|
||||||
this.executor = Executors.newSingleThreadExecutor();
|
this.inputExecutor = Executors.newSingleThreadExecutor();
|
||||||
|
this.outputExecutor = Executors.newSingleThreadExecutor();
|
||||||
this.json = new ObjectMapper();
|
this.json = new ObjectMapper();
|
||||||
|
this.supportStartOffsetTimeWindow = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public QueueConsumer(Consumer<String, Object> kafkaQueue, Producer<String, Object> kafkaResponseQueue) {
|
||||||
|
this(kafkaQueue);
|
||||||
|
this.producer = kafkaResponseQueue;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean needsProcessing(String topicName, BaseRequest<?> request) {
|
protected boolean needsProcessing(String topicName, BaseRequest<?> request) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean supportStartOffsetTimeWindow() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void init() {
|
public void init() {
|
||||||
executor.submit(() -> {
|
inputExecutor.submit(() -> {
|
||||||
try {
|
try {
|
||||||
if (supportStartOffsetTimeWindow()) {
|
if (supportStartOffsetTimeWindow) {
|
||||||
consumer.subscribe(callbacks.keySet(), new OffsetChanger(consumer, callbacks.keySet()));
|
consumer.subscribe(callbacks.keySet(), new OffsetChanger(consumer, callbacks.keySet()));
|
||||||
} else {
|
} else {
|
||||||
consumer.subscribe(callbacks.keySet());
|
consumer.subscribe(callbacks.keySet());
|
||||||
}
|
}
|
||||||
|
Object o = null;
|
||||||
while (!closed.get()) {
|
while (!closed.get()) {
|
||||||
try {
|
try {
|
||||||
ConsumerRecords<String, Object> records = consumer.poll(Duration.of(10, ChronoUnit.SECONDS));
|
ConsumerRecords<String, Object> records = consumer.poll(Duration.of(10, ChronoUnit.SECONDS));
|
||||||
|
|
@ -62,13 +74,19 @@ public class QueueConsumer implements AutoCloseable {
|
||||||
ConsumerSpecificClass<?> callback = callbacks.get(next.topic());
|
ConsumerSpecificClass<?> callback = callbacks.get(next.topic());
|
||||||
Class<?> clazz = callback.getClazz();
|
Class<?> clazz = callback.getClazz();
|
||||||
JavaType payloadType = json.getTypeFactory().constructParametricType(BaseRequest.class, clazz);
|
JavaType payloadType = json.getTypeFactory().constructParametricType(BaseRequest.class, clazz);
|
||||||
Object o = json.readValue((String) next.value(), payloadType);
|
o = json.readValue((String) next.value(), payloadType);
|
||||||
if (needsProcessing(next.topic(), (BaseRequest<?>) o)) {
|
if (needsProcessing(next.topic(), (BaseRequest<?>) o)) {
|
||||||
callback.acceptRaw(o);
|
Object topicResponse = callback.acceptRaw(o);
|
||||||
|
if (producer != null) {
|
||||||
|
sendResponse((BaseRequest<?>) o, topicResponse);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
log.error(ExceptionUtils.getStackTrace(e));
|
log.error(ExceptionUtils.getStackTrace(e));
|
||||||
|
if (producer != null) {
|
||||||
|
sendErrorResponse((BaseRequest<?>) o);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (WakeupException e) {
|
} catch (WakeupException e) {
|
||||||
|
|
@ -81,6 +99,43 @@ public class QueueConsumer implements AutoCloseable {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//мб перенести в другой класс
|
||||||
|
private void sendErrorResponse(BaseRequest<?> o) {
|
||||||
|
outputExecutor.submit(() -> {
|
||||||
|
try {
|
||||||
|
Future<RecordMetadata> send;
|
||||||
|
//default response
|
||||||
|
RequestInfoUpdate success = new RequestInfoUpdate();
|
||||||
|
success.setId(o.getId());
|
||||||
|
success.setStatus(Status.Error);
|
||||||
|
send = producer.send(new ProducerRecord<>(Consts.REQUEST_INFO_UPDATE, success));
|
||||||
|
send.get();
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error(ExceptionUtils.getStackTrace(e));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendResponse(BaseRequest<?> o, Object response) {
|
||||||
|
outputExecutor.submit(() -> {
|
||||||
|
try {
|
||||||
|
Future<RecordMetadata> send;
|
||||||
|
if (response != null) {
|
||||||
|
send = producer.send(new ProducerRecord<>(Consts.REQUEST_INFO_UPDATE, response));
|
||||||
|
} else {
|
||||||
|
//default response
|
||||||
|
RequestInfoUpdate success = new RequestInfoUpdate();
|
||||||
|
success.setId(o.getId());
|
||||||
|
success.setStatus(Status.Success);
|
||||||
|
send = producer.send(new ProducerRecord<>(Consts.REQUEST_INFO_UPDATE, success));
|
||||||
|
}
|
||||||
|
send.get();
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error(ExceptionUtils.getStackTrace(e));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
protected <T> BuilderConsumerStep<T> callback(Class<T> clazz) {
|
protected <T> BuilderConsumerStep<T> callback(Class<T> clazz) {
|
||||||
return ConsumerSpecificClass.build(clazz);
|
return ConsumerSpecificClass.build(clazz);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
package ru.spcex.clearing.platform.messaging.service;
|
||||||
|
|
||||||
|
public class RequestInfoUpdate {
|
||||||
|
private Long id;
|
||||||
|
private Status status;
|
||||||
|
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Status getStatus() {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStatus(Status status) {
|
||||||
|
this.status = status;
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Reference in a new issue