diff --git a/clearing-parent/backend-api/pom.xml b/clearing-parent/backend-api/pom.xml index 18b29f7d1..4a809e05a 100644 --- a/clearing-parent/backend-api/pom.xml +++ b/clearing-parent/backend-api/pom.xml @@ -53,6 +53,10 @@ ru.spcex.clearing classes + + ru.spcex.clearing + dictionary + diff --git a/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/controller/response/entity/dictionary/DictionaryBackendGetAll.java b/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/controller/response/entity/dictionary/DictionaryBackendGetAll.java new file mode 100644 index 000000000..3d6c11aeb --- /dev/null +++ b/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/controller/response/entity/dictionary/DictionaryBackendGetAll.java @@ -0,0 +1,49 @@ +package ru.spcex.clearing.backendapi.controller.response.entity.dictionary; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import ru.clearing.platform.dictionary.AbstractDictionary; +import ru.spcex.clearing.backendapi.controller.response.BasicSpcexResponse; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +@ApiModel(description = "Ответ при получении объектов словаря.") +public class DictionaryBackendGetAll extends BasicSpcexResponse { + + @JsonProperty + @ApiModelProperty(value = "Полезная нагрузка") + private DictionaryBackendPayload payload = new DictionaryBackendPayload(); + + public void fromEntity(Collection dictionaryValues) { + var payload = this.getPayload(); + for (AbstractDictionary dictionaryValue : dictionaryValues) { + var singleItem = new DictionaryBackendGetFields(); + singleItem.fromEntity(dictionaryValue); + payload.getItems().add(singleItem); + } + } + + + private static class DictionaryBackendPayload { + private List items = new ArrayList<>(); + + public List getItems() { + return items; + } + + public void setItems(List items) { + this.items = items; + } + } + + public DictionaryBackendPayload getPayload() { + return payload; + } + + public void setPayload(DictionaryBackendPayload payload) { + this.payload = payload; + } +} \ No newline at end of file diff --git a/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/controller/response/entity/dictionary/DictionaryBackendGetFields.java b/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/controller/response/entity/dictionary/DictionaryBackendGetFields.java new file mode 100644 index 000000000..fa27898c9 --- /dev/null +++ b/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/controller/response/entity/dictionary/DictionaryBackendGetFields.java @@ -0,0 +1,48 @@ +package ru.spcex.clearing.backendapi.controller.response.entity.dictionary; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.annotations.ApiModelProperty; +import ru.clearing.platform.dictionary.AbstractDictionary; + +public class DictionaryBackendGetFields { + @JsonProperty + @ApiModelProperty(value = "Идентификатор", example = "1234") + private Long id; + @JsonProperty + @ApiModelProperty(value = "", example = "") + private String code; + @JsonProperty + @ApiModelProperty(value = "Имя банка", example = "Сбербанк") + private String name; + + public void fromEntity(AbstractDictionary dictionaryValue) { + this.id = dictionaryValue.getId(); + this.code = dictionaryValue.getCode(); + this.name = dictionaryValue.getName(); + } + + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getCode() { + return code; + } + + public void setCode(String code) { + this.code = code; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/controller/response/entity/dictionary/DictionaryBackendGetSingleValue.java b/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/controller/response/entity/dictionary/DictionaryBackendGetSingleValue.java new file mode 100644 index 000000000..b58ccd807 --- /dev/null +++ b/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/controller/response/entity/dictionary/DictionaryBackendGetSingleValue.java @@ -0,0 +1,30 @@ +package ru.spcex.clearing.backendapi.controller.response.entity.dictionary; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import ru.clearing.platform.dictionary.AbstractDictionary; +import ru.spcex.clearing.backendapi.controller.response.BasicSpcexResponse; + +@ApiModel(description = "Ответ при получении объекта BankAccount.") +public class DictionaryBackendGetSingleValue extends BasicSpcexResponse { + + @JsonProperty + @ApiModelProperty(value = "Поля объекта") + private DictionaryBackendGetFields payload; + + public DictionaryBackendGetFields getPayload() { + return payload; + } + + public void fromEntity(AbstractDictionary dictionaryValue) { + var payload = new DictionaryBackendGetFields(); + this.setPayload(payload); + payload.fromEntity(dictionaryValue); + } + + + public void setPayload(DictionaryBackendGetFields payload) { + this.payload = payload; + } +} \ No newline at end of file diff --git a/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/controller/system/DictionaryController.java b/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/controller/system/DictionaryController.java new file mode 100644 index 000000000..ebbf91f79 --- /dev/null +++ b/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/controller/system/DictionaryController.java @@ -0,0 +1,139 @@ +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.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.*; +import ru.clearing.platform.dictionary.AbstractDictionary; +import ru.spcex.clearing.backendapi.controller.response.BasicSpcexResponse; +import ru.spcex.clearing.backendapi.controller.response.entity.dictionary.DictionaryBackendGetAll; +import ru.spcex.clearing.backendapi.controller.response.entity.dictionary.DictionaryBackendGetSingleValue; +import ru.spcex.clearing.backendapi.errors.ActionValidationException; +import ru.spcex.clearing.backendapi.errors.BackEndError; +import ru.spcex.clearing.backendapi.errors.NotFound404Exception; +import ru.spcex.platform.classes.base.SpcexObjectBase; +import ru.spcex.platform.imdg.api.Imdg; +import ru.spcex.platform.imdg.api.ImdgProvider; +import ru.spcex.platform.utils.enumeration.EnumMessage; +import ru.spcex.platform.utils.enumeration.IMessageResolver; + +import java.util.Collection; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +@Controller +@RequestMapping("/dictionary") +public class DictionaryController { + private final Logger log = LoggerFactory.getLogger(getClass()); + private final Map> allDictionaryMaps; + private final ImdgProvider imdgProvider; + + @Autowired + public DictionaryController(ImdgProvider imdgProvider) { + this.imdgProvider = imdgProvider; + this.allDictionaryMaps = new ConcurrentHashMap<>(); + } + + @ApiOperation(value = "get all dictionary value.") + @ApiResponses(value = {@ApiResponse(code = 200, message = "OK", response = DictionaryBackendGetAll.class)}) + @RequestMapping(value = "/{dictionary-name}", method = RequestMethod.GET) + @ResponseBody + public DictionaryBackendGetAll getAll(@ApiParam(value = "Название словаря", required = true, example = "moneyFlowSide") + @PathVariable("dictionary-name") String dictionaryName) { + Imdg dictionary = extractDictionaryImdgFromUrlParameter(dictionaryName, AbstractDictionary.class); + Collection allValues = dictionary.getAllValues(); + DictionaryBackendGetAll response = new DictionaryBackendGetAll(); + response.fromEntity(allValues); + return response; + } + + @ApiOperation(value = "get dictionary value by id.") + @ApiResponses(value = {@ApiResponse(code = 200, message = "OK", response = DictionaryBackendGetSingleValue.class), @ApiResponse(code = 400, message = "Ошибка валидации", response = BasicSpcexResponse.class)}) + @RequestMapping(value = "/{dictionary-name}/{id}", method = RequestMethod.GET) + @ResponseBody + public DictionaryBackendGetSingleValue getById(@ApiParam(value = "Название словаря", required = true, example = "moneyFlowSide") + @PathVariable("dictionary-name") String dictionaryName, + @ApiParam(value = "Идентификатор объекта", required = true, example = "1234") + @PathVariable("id") Long id) { + Imdg dictionary = extractDictionaryImdgFromUrlParameter(dictionaryName, AbstractDictionary.class); + AbstractDictionary value = dictionary.getSingleObjectByID(id); + if (value == null) throw new NotFound404Exception(dictionaryName + " id='" + id + "'"); + DictionaryBackendGetSingleValue response = new DictionaryBackendGetSingleValue(); + response.fromEntity(value); + return response; + } + + @ApiOperation(value = "get dictionary value by code.") + @ApiResponses(value = {@ApiResponse(code = 200, message = "OK", response = DictionaryBackendGetSingleValue.class), @ApiResponse(code = 400, message = "Ошибка валидации", response = BasicSpcexResponse.class)}) + @RequestMapping(value = "/{dictionary-name}/{code}", method = RequestMethod.GET) + @ResponseBody + public DictionaryBackendGetSingleValue getByCode(@ApiParam(value = "Название словаря", required = true, example = "moneyFlowSide") + @PathVariable("dictionary-name") String dictionaryName, + @ApiParam(value = "Код словаря", required = true, example = "1234") + @PathVariable("code") String code) { + Imdg dictionary = extractDictionaryImdgFromUrlParameter(dictionaryName, AbstractDictionary.class); + AbstractDictionary value = dictionary.getSingleObjectByFieldValues(Map.of("code", code)); + if (value == null) throw new NotFound404Exception(dictionaryName + " code='" + code + "'"); + DictionaryBackendGetSingleValue response = new DictionaryBackendGetSingleValue(); + response.fromEntity(value); + return response; + } + + @SuppressWarnings("unchecked") + private Imdg extractDictionaryImdgFromUrlParameter(String dictionaryNameFromUrl, Class clazz) { + if (dictionaryNameFromUrl == null || dictionaryNameFromUrl.length() < 1) { + throw new ActionValidationException(BackEndError.ValidationError, "dictionary-name"); + } + + String actualDictionaryName = "Map_" + + dictionaryNameFromUrl.substring(0, 1).toUpperCase() + + dictionaryNameFromUrl.substring(1) + + "Dictionary"; + + Imdg dictionary = (Imdg) allDictionaryMaps.computeIfAbsent(actualDictionaryName, (mapName1) -> { + Imdg potentialImdg = imdgProvider.getImdg(actualDictionaryName, clazz); + if (potentialImdg.size() == 0) { + log.warn("coudln't find dictionary {}", actualDictionaryName); + return null; + } + return potentialImdg; + }); + + if (dictionary == null) { + throw new ActionValidationException(BackEndError.DictionaryNotFound, dictionaryNameFromUrl); + } + + return dictionary; + } + + @Autowired + private IMessageResolver errorResolver; + + @ResponseStatus(value = HttpStatus.BAD_REQUEST) + @ResponseBody + @ExceptionHandler(ActionValidationException.class) + public BasicSpcexResponse conflict(ActionValidationException ex) { + BasicSpcexResponse response = new BasicSpcexResponse(); + EnumMessage message = ex.getErrors().stream().findFirst().orElseThrow(); + response.setCode(message.getSubject().getId()); + response.setMessage(errorResolver.resolve(message)); + return response; + } + + @ResponseStatus(value = HttpStatus.NOT_FOUND) + @ResponseBody + @ExceptionHandler(NotFound404Exception.class) + public BasicSpcexResponse conflict(NotFound404Exception ex) { + BasicSpcexResponse response = new BasicSpcexResponse(); + EnumMessage message = ex.getError(); + response.setCode(message.getSubject().getId()); + response.setMessage(errorResolver.resolve(message)); + return response; + } +} diff --git a/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/errors/ActionValidationException.java b/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/errors/ActionValidationException.java index 251695991..b117f4c11 100644 --- a/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/errors/ActionValidationException.java +++ b/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/errors/ActionValidationException.java @@ -1,6 +1,7 @@ package ru.spcex.clearing.backendapi.errors; import ru.spcex.platform.utils.enumeration.EnumMessage; +import ru.spcex.platform.utils.enumeration.IEnumId; import java.util.Collection; import java.util.List; @@ -16,6 +17,10 @@ public class ActionValidationException extends RuntimeException { this.errors = List.of(error); } + public ActionValidationException(IEnumId subject, Object... args) { + this.errors = List.of(new EnumMessage(subject, args)); + } + public Collection getErrors() { return errors; } diff --git a/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/errors/BackEndError.java b/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/errors/BackEndError.java index 5808d3e7e..e84aeba69 100644 --- a/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/errors/BackEndError.java +++ b/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/errors/BackEndError.java @@ -6,7 +6,10 @@ public enum BackEndError implements IEnumId { ValidationError(3000L), UnknownJsonProperty(3001L), FailedToReadHttpMessage(3002L), - KeycloakRepeatedRoles(3003L); + KeycloakRepeatedRoles(3003L), + DictionaryNotFound(3004L), + ResourceNotFound(404L) + ; private final Long id; BackEndError(Long id) { diff --git a/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/errors/NotFound404Exception.java b/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/errors/NotFound404Exception.java new file mode 100644 index 000000000..1483749e5 --- /dev/null +++ b/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/errors/NotFound404Exception.java @@ -0,0 +1,16 @@ +package ru.spcex.clearing.backendapi.errors; + +import ru.spcex.platform.utils.enumeration.EnumMessage; + +public class NotFound404Exception extends RuntimeException { + + private final EnumMessage error; + + public NotFound404Exception(String comment) { + this.error = new EnumMessage(BackEndError.ResourceNotFound, comment); + } + + public EnumMessage getError() { + return error; + } +} diff --git a/clearing-parent/backend-api/src/main/resources/messages/error.properties b/clearing-parent/backend-api/src/main/resources/messages/error.properties index bd5831476..52320a63a 100644 --- a/clearing-parent/backend-api/src/main/resources/messages/error.properties +++ b/clearing-parent/backend-api/src/main/resources/messages/error.properties @@ -1,4 +1,5 @@ 1=This is error example 1. 3000=validation error field '%s' 3001=unrecognized json property '%s' -3002=failed to read http message \ No newline at end of file +3002=failed to read http message +3004=couldn't find dictionary '%s' \ No newline at end of file diff --git a/clearing-parent/dictionary/pom.xml b/clearing-parent/dictionary/pom.xml index cf6ecd958..323d95a0f 100644 --- a/clearing-parent/dictionary/pom.xml +++ b/clearing-parent/dictionary/pom.xml @@ -55,6 +55,10 @@ junit-jupiter test + + ru.spcex.platform + platform-classes-base + diff --git a/clearing-parent/dictionary/src/main/java/ru/clearing/platform/dictionary/AbstractDictionary.java b/clearing-parent/dictionary/src/main/java/ru/clearing/platform/dictionary/AbstractDictionary.java index e5c970836..d7186440b 100644 --- a/clearing-parent/dictionary/src/main/java/ru/clearing/platform/dictionary/AbstractDictionary.java +++ b/clearing-parent/dictionary/src/main/java/ru/clearing/platform/dictionary/AbstractDictionary.java @@ -1,22 +1,12 @@ package ru.clearing.platform.dictionary; -public abstract class AbstractDictionary implements Dictionary { - static final long serialVersionUID = ConstDictionarySerializable.serialVersionUID; +import ru.spcex.platform.classes.base.SpcexObjectBase; - protected Long id; +public abstract class AbstractDictionary extends SpcexObjectBase implements Dictionary { + static final long serialVersionUID = ConstDictionarySerializable.serialVersionUID; protected String code; protected String name; - @Override - public Long getId() { - return id; - } - - @Override - public void setId(Long id) { - this.id = id; - } - @Override public String getCode() { return code; diff --git a/platform-parent/platform-imdg-api-hazelcast-impl/src/main/java/ru/spcex/platform/imdg/iml/hazelcast/adapter/ImdgHazelcast.java b/platform-parent/platform-imdg-api-hazelcast-impl/src/main/java/ru/spcex/platform/imdg/iml/hazelcast/adapter/ImdgHazelcast.java index cb848122f..940adedcb 100644 --- a/platform-parent/platform-imdg-api-hazelcast-impl/src/main/java/ru/spcex/platform/imdg/iml/hazelcast/adapter/ImdgHazelcast.java +++ b/platform-parent/platform-imdg-api-hazelcast-impl/src/main/java/ru/spcex/platform/imdg/iml/hazelcast/adapter/ImdgHazelcast.java @@ -29,6 +29,11 @@ public class ImdgHazelcast implements Imdg { return map.values(); } + @Override + public Integer size() { + return map.size(); + } + @Override public void insert(T paramT) { if (paramT.getId() == null) { diff --git a/platform-parent/platform-imdg-api/src/main/java/ru/spcex/platform/imdg/api/Imdg.java b/platform-parent/platform-imdg-api/src/main/java/ru/spcex/platform/imdg/api/Imdg.java index 845eeb86f..ca765d5b5 100644 --- a/platform-parent/platform-imdg-api/src/main/java/ru/spcex/platform/imdg/api/Imdg.java +++ b/platform-parent/platform-imdg-api/src/main/java/ru/spcex/platform/imdg/api/Imdg.java @@ -57,4 +57,8 @@ public interface Imdg { default Collection projectionsAttributeBySql(String paramString, String... paramVarArgs) { throw new UnsupportedOperationException("not implemented projectionsAttributeBySql"); } + + default Integer size() { + throw new UnsupportedOperationException("not implemented size"); + } }