diff --git a/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/controller/queue/misc/SessionHistoryController.java b/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/controller/queue/misc/SessionHistoryController.java index b1d2031cc..8562e2986 100644 --- a/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/controller/queue/misc/SessionHistoryController.java +++ b/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/controller/queue/misc/SessionHistoryController.java @@ -4,6 +4,8 @@ import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiParam; import io.swagger.annotations.ApiResponse; import io.swagger.annotations.ApiResponses; +import java.util.Collection; +import java.util.Map; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; @@ -14,15 +16,20 @@ import ru.spcex.clearing.backendapi.controller.queue.AbstractQueueController; import ru.spcex.clearing.backendapi.controller.response.entity.CommonGetAllResponse; import ru.spcex.clearing.backendapi.service.IOperator; import ru.spcex.clearing.backendapi.service.IStateLoader; +import ru.spcex.platform.imdg.api.ImdgProvider; @Controller @RequestMapping("/sessionHistory") public class SessionHistoryController extends AbstractQueueController { private final IStateLoader stateLoader; + private final ImdgProvider imdgProvider; @Autowired - public SessionHistoryController(IOperator operator, IStateLoader stateLoader) { + public SessionHistoryController(IOperator operator, + ImdgProvider imdgProvider, + IStateLoader stateLoader) { super(operator); + this.imdgProvider = imdgProvider; this.stateLoader = stateLoader; } @@ -35,7 +42,9 @@ public class SessionHistoryController extends AbstractQueueController { @RequestParam(name = "id") Long id ) { + Collection> sessionHistories = stateLoader.getSessionHistoryById(id); CommonGetAllResponse response = new CommonGetAllResponse(); + response.fromEntity(sessionHistories); return response; } } diff --git a/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/service/IStateLoader.java b/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/service/IStateLoader.java index ac8442ffc..868ec2138 100644 --- a/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/service/IStateLoader.java +++ b/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/service/IStateLoader.java @@ -23,4 +23,5 @@ public interface IStateLoader { String mapName, Class clazz, ImdgPredicate conditions); + Collection> getSessionHistoryById(Long sessionId); } diff --git a/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/service/impl/StateLoaderImpl.java b/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/service/impl/StateLoaderImpl.java index eaa7dbf73..6fb9ac2cb 100644 --- a/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/service/impl/StateLoaderImpl.java +++ b/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/service/impl/StateLoaderImpl.java @@ -9,12 +9,15 @@ import java.util.concurrent.ConcurrentHashMap; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Service; +import ru.clearing.classes.statics.data.misc.SessionHistory; import ru.spcex.clearing.backendapi.meta.GetResponseFactory; import ru.spcex.clearing.backendapi.service.IStateLoader; +import ru.spcex.clearing.imdg.IMDGDistributedNames; 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.imdg.api.predicate.ImdgPredicate; +import ru.spcex.platform.imdg.api.predicate.ImdgPredicateBuilder; @Service public class StateLoaderImpl implements IStateLoader { @@ -108,4 +111,17 @@ public class StateLoaderImpl implements IStateLoader { .map(o -> responseFactory.responseFromObject(o, clazz)) .toList(); } + + @Override + public Collection> getSessionHistoryById(Long sessionId) { + Imdg imdgSearch = getHistImdg(IMDGDistributedNames.Map_SearchSessionHistory, SpcexObjectBase.class); + ImdgPredicateBuilder predicateBuilder = imdgSearch.predicateBuilder(); + ImdgPredicate imdgPredicate = predicateBuilder.equals("sessionId", sessionId); + Imdg sessionHistoryImdg = getHistImdg(IMDGDistributedNames.Map_SessionHistory, SessionHistory.class); + return imdgSearch.getCollectionIdsByPredicate(imdgPredicate).stream() + .map(sessionHistoryImdg::getSingleObjectByID) + .filter(Objects::nonNull) + .map(sessionHistory -> responseFactory.responseFromObject(sessionHistory, SessionHistory.class)) + .toList(); + } } diff --git a/clearing-parent/backend-api/src/main/resources/meta/meta.json b/clearing-parent/backend-api/src/main/resources/meta/meta.json index 8ee112f49..ecaeb671b 100644 --- a/clearing-parent/backend-api/src/main/resources/meta/meta.json +++ b/clearing-parent/backend-api/src/main/resources/meta/meta.json @@ -6274,55 +6274,55 @@ } , {"code": "sessionId", - "type": 1,"name": "Идентификатор записи","shortname": "ID","searchable": true,"sortable": true + "field": "object.id","type": 1,"name": "Идентификатор сессии","shortname": "ID сессии","searchable": true,"sortable": true } , {"code": "eventTime", - "type": 1,"name": "Идентификатор записи","shortname": "ID","searchable": true,"sortable": true + "type": 4,"name": "Дата и время изменения","shortname": "Дата и время изменения","searchable": true,"sortable": true } , {"code": "eventType", - "type": 1,"name": "Идентификатор записи","shortname": "ID","searchable": true,"sortable": true + "type": 12,"name": "Тип изменения","shortname": "Тип изменения","searchable": true,"sortable": true } , {"code": "createdAt", - "field": "created","type": 4,"webtype": "5","dbname": "Дата-время создания записи","name": "Время создания записи","shortname": "Создано","searchable": true,"sortable": true + "field": "object.created","type": 4,"webtype": "5","dbname": "Дата-время создания записи","name": "Время создания записи","shortname": "Создано","searchable": true,"sortable": true } , {"code": "updatedAt", - "field": "updated","type": 4,"webtype": "5","dbname": "Дата-время изменения записи","name": "Время изменения записи","shortname": "Завершено","searchable": true,"sortable": true + "field": "object.updated","type": 4,"webtype": "5","dbname": "Дата-время изменения записи","name": "Время изменения записи","shortname": "Завершено","searchable": true,"sortable": true } , {"code": "clearingDate", - "type": 6,"name": "Дата","shortname": "Дата","searchable": true,"sortable": true,"visible": true + "field": "object.clearingDate","type": 6,"name": "Дата","shortname": "Дата","searchable": true,"sortable": true,"visible": true } , {"code": "sessionStatus", - "type": 12,"dbname": "Код статуса клиринговой сессии","name": "Статус клиринговой сессии","shortname": "Шаг","searchable": true,"sortable": true,"visible": true,"link": "sessionStatus" + "field": "object.sessionStatus","type": 12,"dbname": "Код статуса клиринговой сессии","name": "Статус клиринговой сессии","shortname": "Шаг","searchable": true,"sortable": true,"visible": true,"link": "sessionStatus" } , {"code": "companyId", - "type": 1,"dbname": "Идентификатор инициатора торгов","name": "Наименование инициатора торгов","shortname": "Инициатор","visible": false,"searchable": true,"sortable": true,"link": "company","linkCode": "shortName" + "field": "object.companyId","type": 1,"dbname": "Идентификатор инициатора торгов","name": "Наименование инициатора торгов","shortname": "Инициатор","visible": false,"searchable": true,"sortable": true,"link": "company","linkCode": "shortName" } , {"code": "securityId", - "type": 1,"dbname": "Идентификатор инструмента","name": "Наименование инструмента","shortname": "Инструмент","searchable": false,"sortable": true,"visible": true,"link": "security","linkCode": "shortName" + "field": "object.securityId","type": 1,"dbname": "Идентификатор инструмента","name": "Наименование инструмента","shortname": "Инструмент","searchable": false,"sortable": true,"visible": true,"link": "security","linkCode": "shortName" } , {"code": "userId", - "type": 1,"dbname": "Идентификатор пользователя","name": "Наименование пользователя","shortname": "Пользователь","searchable": true,"sortable": true,"visible": true,"link": "userCls","linkCode": "identifier" + "field": "object.userId","type": 1,"dbname": "Идентификатор пользователя","name": "Наименование пользователя","shortname": "Пользователь","searchable": true,"sortable": true,"visible": true,"link": "userCls","linkCode": "identifier" } , {"code": "section", - "type": 12,"dbname": "Код наименования секции","name": "Наименование секции","shortname": "Секция","searchable": true,"sortable": true,"visible": true,"link": "section" + "field": "object.section","type": 12,"dbname": "Код наименования секции","name": "Наименование секции","shortname": "Секция","searchable": true,"sortable": true,"visible": true,"link": "section" } , {"code": "sessionType", - "type": 12,"dbname": "Код типа клиринговой сессии","name": "Тип клиринговой сессии","shortname": "Тип","searchable": true,"sortable": true,"visible": true,"link": "sessionType" + "field": "object.sessionType","type": 12,"dbname": "Код типа клиринговой сессии","name": "Тип клиринговой сессии","shortname": "Тип","searchable": true,"sortable": true,"visible": true,"link": "sessionType" } , {"code": "workflowStatus", - "type": 12,"dbname": "Код статуса","name": "Наименование статуса","shortname": "Статус","searchable": true,"sortable": true,"visible": true,"link": "workflowStatus" + "field": "object.workflowStatus","type": 12,"dbname": "Код статуса","name": "Наименование статуса","shortname": "Статус","searchable": true,"sortable": true,"visible": true,"link": "workflowStatus" } ] diff --git a/clearing-parent/backend-api/src/main/resources/meta/meta.xml b/clearing-parent/backend-api/src/main/resources/meta/meta.xml index 6437c8a53..12f11cdc9 100644 --- a/clearing-parent/backend-api/src/main/resources/meta/meta.xml +++ b/clearing-parent/backend-api/src/main/resources/meta/meta.xml @@ -1453,19 +1453,19 @@ - - - - - - - - - - -
- - + + + + + + + + + + +
+ + diff --git a/clearing-parent/imdg-hist/src/main/java/ru/spcex/clearing/historyimdg/index/SearchProxySessionHistory.java b/clearing-parent/imdg-hist/src/main/java/ru/spcex/clearing/historyimdg/index/SearchProxySessionHistory.java new file mode 100644 index 000000000..1419209cc --- /dev/null +++ b/clearing-parent/imdg-hist/src/main/java/ru/spcex/clearing/historyimdg/index/SearchProxySessionHistory.java @@ -0,0 +1,18 @@ +package ru.spcex.clearing.historyimdg.index; + +import ru.spcex.clearing.historyimdg.index.field.SearchWithSessionId; + +public class SearchProxySessionHistory extends SearchProxy implements SearchWithSessionId { + + private Long sessionId; + + @Override + public Long getSessionId() { + return sessionId; + } + + @Override + public void setSessionId(Long sessionId) { + this.sessionId = sessionId; + } +} diff --git a/clearing-parent/imdg-hist/src/main/java/ru/spcex/clearing/historyimdg/index/field/SearchWithSessionId.java b/clearing-parent/imdg-hist/src/main/java/ru/spcex/clearing/historyimdg/index/field/SearchWithSessionId.java new file mode 100644 index 000000000..d2ce7b831 --- /dev/null +++ b/clearing-parent/imdg-hist/src/main/java/ru/spcex/clearing/historyimdg/index/field/SearchWithSessionId.java @@ -0,0 +1,7 @@ +package ru.spcex.clearing.historyimdg.index.field; + +public interface SearchWithSessionId { + Long getSessionId(); + + void setSessionId(Long sessionId); +} diff --git a/clearing-parent/imdg-hist/src/main/java/ru/spcex/clearing/historyimdg/mapstores/SearchSessionHistoryMapStore.java b/clearing-parent/imdg-hist/src/main/java/ru/spcex/clearing/historyimdg/mapstores/SearchSessionHistoryMapStore.java new file mode 100644 index 000000000..0f77afea1 --- /dev/null +++ b/clearing-parent/imdg-hist/src/main/java/ru/spcex/clearing/historyimdg/mapstores/SearchSessionHistoryMapStore.java @@ -0,0 +1,48 @@ +package ru.spcex.clearing.historyimdg.mapstores; + +import java.util.Collection; +import java.util.Collections; +import java.util.Map; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.stereotype.Component; +import ru.spcex.clearing.historyimdg.index.SearchProxySessionHistory; +import ru.spcex.clearing.imdg.IMDGDistributedNames; + +@Component +public class SearchSessionHistoryMapStore extends AbstractSliceMapLoader { + public SearchSessionHistoryMapStore(JdbcTemplate jdbcTemplate) { + super(jdbcTemplate); + } + + @Override + protected String getTableName() { + return "session_history"; + } + + @Override + protected String fieldOfDay() { + return "session_id"; + } + + @Override + public Collection load(Collection keys) { + Map> paramMap = Collections.singletonMap("ids", keys); + return namedParameterJdbcTemplate.query("select * from " + getTableName() + " where id in (:ids)", paramMap, + (rs, rowNum) -> { + SearchProxySessionHistory proxySessionHistory = new SearchProxySessionHistory(); + proxySessionHistory.setId(rs.getObject("id", Long.class)); + proxySessionHistory.setSessionId(rs.getObject("session_id", Long.class)); + return proxySessionHistory; + }); + } + + @Override + public String getMapName() { + return IMDGDistributedNames.Map_SearchSessionHistory; + } + + @Override + public String[] getIndexingField() { + return new String[]{"sessionId"}; + } +} diff --git a/clearing-parent/imdg-hist/src/main/java/ru/spcex/clearing/historyimdg/mapstores/SessionHistoryOnlyLoadMapStore.java b/clearing-parent/imdg-hist/src/main/java/ru/spcex/clearing/historyimdg/mapstores/SessionHistoryOnlyLoadMapStore.java new file mode 100644 index 000000000..f0c2ca780 --- /dev/null +++ b/clearing-parent/imdg-hist/src/main/java/ru/spcex/clearing/historyimdg/mapstores/SessionHistoryOnlyLoadMapStore.java @@ -0,0 +1,119 @@ +package ru.spcex.clearing.historyimdg.mapstores; + +import com.hazelcast.config.EvictionConfig; +import com.hazelcast.config.MaxSizeConfig; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import org.springframework.dao.support.DataAccessUtils; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.stereotype.Component; +import ru.clearing.classes.statics.data.misc.Session; +import ru.clearing.classes.statics.data.misc.SessionHistory; +import ru.spcex.clearing.imdg.businessevent.SessionHistoryMapStore; +import ru.spcex.clearing.imdg.config.element.ImdgHzEvictionConfig; + +@Component +public class SessionHistoryOnlyLoadMapStore extends SessionHistoryMapStore { + + public SessionHistoryOnlyLoadMapStore(JdbcTemplate jdbcTemplate) { + super(jdbcTemplate); + } + + @Override + public Optional evictionConfig() { + ImdgHzEvictionConfig evctCfg = new ImdgHzEvictionConfig(); + evctCfg.setSize(5000); + evctCfg.setMaxSizePolicy(MaxSizeConfig.MaxSizePolicy.PER_NODE); + evctCfg.setEvictionPolicy(EvictionConfig.DEFAULT_EVICTION_POLICY); + evctCfg.setTimeToLiveSeconds(1800); + return Optional.of(evctCfg); + } + + + @Override + public SessionHistory load(Long id) { + if (!isLoadable(id)) return null; + Collection rows; + List list = Collections.singletonList(id); + try { + rows = load(list); + } catch (Throwable e) { // one retry + rows = load(list); + } + SessionHistory obj = DataAccessUtils.singleResult(rows); + if (obj != null && isLoadable(obj)) + return obj; + else + return null; + } + + @Override + public Map loadAll(Collection keys) { + log.debug("loadAll from " + getTableName() + " " + keys.size() + " keys"); + Map result = new HashMap<>(); + long start = System.currentTimeMillis(); + + // загрузить данные по ключам частями, чтобы не выйти за ограничения базы по кол-ву элементов в in clause + List keysSubList = new ArrayList<>(MAX_IN_CLAUSE_SIZE); + for (Iterator iterator = keys.iterator(); iterator.hasNext(); ) { + Long key = iterator.next(); + keysSubList.add(key); + if (keysSubList.size() == MAX_IN_CLAUSE_SIZE || !iterator.hasNext()) { + Collection rows = load(keysSubList); + for (SessionHistory row : rows) { + result.put(row.getId(), row); + } + keysSubList.clear(); + } + } + + log.debug("loadAll from " + getTableName() + " " + keys.size() + " keys done in " + (System.currentTimeMillis() - start) + "ms"); + + return result; + } + + @Override + public Collection load(Collection keys) { + Map> paramMap = Collections.singletonMap("ids", keys); + return namedParameterJdbcTemplate.query("select * from " + getTableName() + " where id in (:ids)", paramMap, + (resultSet, i) -> objectReader(resultSet)); + } + + protected SessionHistory objectReader(ResultSet resultSet) throws SQLException { + SessionHistory sessionHistory = new SessionHistory(); + Session object = new Session(); + + sessionHistory.setId(resultSet.getObject("ID", Long.class)); + sessionHistory.setEventTime(getInstantFromTimestamp(resultSet, "EVENT_TIME")); + sessionHistory.setUserId(resultSet.getObject("EVENT_USER_ID", Long.class)); + sessionHistory.setEventType(resultSet.getObject("EVENT_TYPE", String.class)); + + object.setId(resultSet.getObject("SESSION_ID", Long.class)); + object.setCreated(getInstantFromTimestamp(resultSet, "CREATED_AT")); + object.setUpdated(getInstantFromTimestamp(resultSet, "UPDATED_AT")); + object.setClearingDate(getLocalDateFromSqlDate(resultSet, "CLEARING_DATE")); + object.setSessionStatus(resultSet.getObject("SESSION_STATUS", String.class)); + object.setCompanyId(resultSet.getObject("COMPANY_ID", Long.class)); + object.setSecurityId(resultSet.getObject("SECURITY_ID", Long.class)); + object.setUserId(resultSet.getObject("USER_ID", Long.class)); + object.setSection(resultSet.getObject("SECTION", String.class)); + object.setSessionType(resultSet.getObject("SESSION_TYPE", String.class)); + object.setWorkflowStatus(resultSet.getObject("WORKFLOW_STATUS", String.class)); + + sessionHistory.setObject(object); + return sessionHistory; + } + + @Override + public void store(Map map) { + //do nothing + } +} \ No newline at end of file diff --git a/clearing-parent/imdg/src/main/java/ru/spcex/clearing/imdg/businessevent/SessionHistoryMapStore.java b/clearing-parent/imdg/src/main/java/ru/spcex/clearing/imdg/businessevent/SessionHistoryMapStore.java index 983861037..6fb7d589c 100644 --- a/clearing-parent/imdg/src/main/java/ru/spcex/clearing/imdg/businessevent/SessionHistoryMapStore.java +++ b/clearing-parent/imdg/src/main/java/ru/spcex/clearing/imdg/businessevent/SessionHistoryMapStore.java @@ -2,9 +2,9 @@ package ru.spcex.clearing.imdg.businessevent; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Component; -import ru.spcex.clearing.imdg.IMDGDistributedNames; import ru.clearing.classes.statics.data.misc.Session; import ru.clearing.classes.statics.data.misc.SessionHistory; +import ru.spcex.clearing.imdg.IMDGDistributedNames; import ru.spcex.clearing.imdg.base.TemplateEventMapStore; import ru.spcex.platform.utils.time.TimeUtil; diff --git a/platform-parent/platform-imdg-api/src/main/java/ru/spcex/clearing/imdg/IMDGDistributedNames.java b/platform-parent/platform-imdg-api/src/main/java/ru/spcex/clearing/imdg/IMDGDistributedNames.java index 23d82a81c..c584104b3 100644 --- a/platform-parent/platform-imdg-api/src/main/java/ru/spcex/clearing/imdg/IMDGDistributedNames.java +++ b/platform-parent/platform-imdg-api/src/main/java/ru/spcex/clearing/imdg/IMDGDistributedNames.java @@ -241,6 +241,7 @@ public final class IMDGDistributedNames { public static final String Map_SearchLiabilitiesRegister = "Map_SearchLiabilitiesRegister"; public static final String Map_SearchExecutionRegister = "Map_SearchExecutionRegister"; public static final String Map_SearchSession = "Map_SearchSession"; + public static final String Map_SearchSessionHistory = "Map_SearchSessionHistory"; public static final String MAP_SEQUENCE_NAME = "MAP_SEQUENCE_NAME"; private IMDGDistributedNames() {