From 3107f02dafa4b820d6e3382f922fe065caa0693c Mon Sep 17 00:00:00 2001 From: AKurakin Date: Mon, 8 Aug 2022 18:38:05 +0300 Subject: [PATCH] =?UTF-8?q?IMDG=20=D1=80=D0=B5=D1=84=D0=B0=D0=BA=D1=82?= =?UTF-8?q?=D0=BE=D1=80=D0=B8=D0=BD=D0=B3,=20=D0=BF=D0=BE=D0=B4=D0=B3?= =?UTF-8?q?=D0=BE=D1=82=D0=BE=D0=B2=D0=BA=D0=B0=20=D0=BA=20=D0=B7=D0=B0?= =?UTF-8?q?=D0=BC=D0=B5=D0=BD=D0=B5=20=D0=BD=D0=B0=20=D0=B0=D0=B2=D1=82?= =?UTF-8?q?=D0=BE=D0=B3=D0=B5=D0=BD=D0=B5=D1=80=D0=B0=D1=86=D0=B8=D1=8E=20?= =?UTF-8?q?=D0=BA=D0=BB=D0=B0=D1=81=D1=81=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- clearing-parent/imdg/pom.xml | 6 ++ .../clearing/imdg/base/AutoconfiguredMap.java | 7 ++ .../clearing/imdg/base/TemplateMapStore.java | 89 +++++++++++++++++++ .../imdg/base/TemplateUpdateMapStore.java | 87 ++++++++++++++++++ .../imdg/config/HazelcastConfiguration.java | 10 ++- .../clearing/imdg/config/PoolMapConfigs.java | 52 +++++++++-- .../imdg/object/CompanyRoleSetMapStore.java | 56 ++++++------ .../clearing/imdg/utils/DbUtilsHelper.java | 7 +- .../imdg/utils/DbUtilsHelperTest.java | 15 ++++ pom.xml | 8 ++ 10 files changed, 300 insertions(+), 37 deletions(-) create mode 100644 clearing-parent/imdg/src/main/java/ru/spcex/clearing/imdg/base/AutoconfiguredMap.java create mode 100644 clearing-parent/imdg/src/main/java/ru/spcex/clearing/imdg/base/TemplateMapStore.java create mode 100644 clearing-parent/imdg/src/main/java/ru/spcex/clearing/imdg/base/TemplateUpdateMapStore.java create mode 100644 clearing-parent/imdg/src/test/java/ru/spcex/clearing/imdg/utils/DbUtilsHelperTest.java diff --git a/clearing-parent/imdg/pom.xml b/clearing-parent/imdg/pom.xml index 2d54dc66f..81195787b 100644 --- a/clearing-parent/imdg/pom.xml +++ b/clearing-parent/imdg/pom.xml @@ -65,6 +65,12 @@ ${external_libraries.hazelcast.version} + + + org.testng + testng + test + jar/${project.artifactId} diff --git a/clearing-parent/imdg/src/main/java/ru/spcex/clearing/imdg/base/AutoconfiguredMap.java b/clearing-parent/imdg/src/main/java/ru/spcex/clearing/imdg/base/AutoconfiguredMap.java new file mode 100644 index 000000000..23eefe7b5 --- /dev/null +++ b/clearing-parent/imdg/src/main/java/ru/spcex/clearing/imdg/base/AutoconfiguredMap.java @@ -0,0 +1,7 @@ +package ru.spcex.clearing.imdg.base; + +public interface AutoconfiguredMap { + String getMapName(); + + String[] getIndexingField(); +} diff --git a/clearing-parent/imdg/src/main/java/ru/spcex/clearing/imdg/base/TemplateMapStore.java b/clearing-parent/imdg/src/main/java/ru/spcex/clearing/imdg/base/TemplateMapStore.java new file mode 100644 index 000000000..34120e399 --- /dev/null +++ b/clearing-parent/imdg/src/main/java/ru/spcex/clearing/imdg/base/TemplateMapStore.java @@ -0,0 +1,89 @@ +package ru.spcex.clearing.imdg.base; + +import org.springframework.jdbc.core.JdbcTemplate; +import ru.spcex.clearing.imdg.utils.DbUtilsHelper; +import ru.spcex.platform.classes.base.SpcexObjectBase; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.*; + +/** + * MapStore для шаблонных бизнес-объектов + * @Component + */ +public abstract class TemplateMapStore extends ObjectBaseMapStore implements AutoconfiguredMap { + + protected final int validateSize = getFields().length; + + protected final String insertStatement = DbUtilsHelper.createUpdateOrInsert(getTableName(), getFields(), "id"); + + public TemplateMapStore(JdbcTemplate jdbcTemplate) { + super(jdbcTemplate); + } + +// @Override +// public String getTableName() { +// return "COMPANY_ROLE_SET"; +// } +// +// @Override +// public String[] getFields() { +// return new String[]{"id", "roleid", "companyid"}; +// } + +// //todo TradingDay флаг +// protected boolean useTradingDay() { +// return false; +// } + + /** + * + * @return IMDGDistributedNames.* + */ + public abstract String getMapName(); + + /** + * Список индексируемых полей, для быстрого поиска + * @return + */ + public String[] getIndexingField() { + return null; + } + + /** + * Десериализатор + * @param resultSet + * @return + */ + protected abstract T objectReader(ResultSet resultSet) throws SQLException; + + @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)); + } + + /** + * Сериализатор + * @param resultSet + * @return Object[] args + */ + protected abstract Object[] objectToField(T resultSet); + + @Override + public void store(Map map) { + List batchArgs = new ArrayList<>(); + for (Map.Entry entry : map.entrySet()) { + T obj = entry.getValue(); + Object[] args = objectToField(obj); + if (args.length != validateSize) { + throw new IllegalArgumentException("objectToField return " + args.length + " arguments, but expected " + validateSize); + } + batchArgs.add(args); + } + batchInsertUpdate(insertStatement, batchArgs); + } + +} diff --git a/clearing-parent/imdg/src/main/java/ru/spcex/clearing/imdg/base/TemplateUpdateMapStore.java b/clearing-parent/imdg/src/main/java/ru/spcex/clearing/imdg/base/TemplateUpdateMapStore.java new file mode 100644 index 000000000..c809cbf32 --- /dev/null +++ b/clearing-parent/imdg/src/main/java/ru/spcex/clearing/imdg/base/TemplateUpdateMapStore.java @@ -0,0 +1,87 @@ +package ru.spcex.clearing.imdg.base; + +import org.springframework.jdbc.core.JdbcTemplate; +import ru.clearing.classes.objects.BusinessEvent; +import ru.clearing.classes.objects.BusinessObject; +import ru.spcex.clearing.imdg.utils.DbUtilsHelper; +import ru.spcex.clearing.imdg.utils.TimeUtil; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +//@Component +public abstract class TemplateUpdateMapStore> extends BusinessEventMapStore { + + protected final int validateSize = getFields().length; + protected final String insertStatement = DbUtilsHelper.createUpdateOrInsert(getTableName(), getFields(), "id"); + + public TemplateUpdateMapStore(JdbcTemplate jdbcTemplate) { + super(jdbcTemplate); + } + +// @Override +// public String getTableName() { +// return "COMPANY_UPDATE"; +// } +// +// @Override +// public String[] getFields() { +// return new String[]{ +// "id", "event_time", "event_user_id", +// "company_id", "created_at", "updated_at", "status", "clearing_code", "exchange_code" +// }; +// } + + /** + * Сериализатор + * @param object + * @return Object[] args + */ + protected abstract Object[] objectToField(T object); + + protected Object[] objectToField(TU updateObject, T object) { + ArrayList lst=new ArrayList<>(); + lst.add(updateObject.getId()); + lst.add(TimeUtil.fromInstant(updateObject.getEventTime())); + lst.add(updateObject.getUserId()); + lst.addAll(Arrays.asList(objectToField(object))); + //todo order? +// new Object[]{ +// companyUpdate, +// , +// companyUpdate.getUserId(), +// new Object[]{ +// companyUpdate.getId(), +// TimeUtil.fromInstant(companyUpdate.getEventTime()), +// companyUpdate.getUserId(), +// +// company.getId(), // company_id +// TimeUtil.fromInstant(company.getCreated()), +// TimeUtil.fromInstant(company.getUpdated()), +// company.getStatusId(), +// company.getClearingCode(), +// company.getExchangeCode() +// }; + return lst.toArray(); + } + + @Override + public void store(Map map) { + List batchArgs = new ArrayList<>(); + + for (Map.Entry entry : map.entrySet()) { + TU updateContainer = entry.getValue(); + T obj = updateContainer.getObject(); + + Object[] args = objectToField(updateContainer, obj); + if (args.length != validateSize) { + throw new IllegalArgumentException("objectToField return " + args.length + " arguments, but expected " + validateSize); + } + batchArgs.add(args); + } + batchInsertUpdate(insertStatement, batchArgs); + } + +} diff --git a/clearing-parent/imdg/src/main/java/ru/spcex/clearing/imdg/config/HazelcastConfiguration.java b/clearing-parent/imdg/src/main/java/ru/spcex/clearing/imdg/config/HazelcastConfiguration.java index ab36d0ad8..e537f32b3 100644 --- a/clearing-parent/imdg/src/main/java/ru/spcex/clearing/imdg/config/HazelcastConfiguration.java +++ b/clearing-parent/imdg/src/main/java/ru/spcex/clearing/imdg/config/HazelcastConfiguration.java @@ -7,6 +7,8 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import java.util.List; + @Configuration public class HazelcastConfiguration { @@ -53,13 +55,19 @@ public class HazelcastConfiguration { config.addMapConfig(poolMapConfigs.map_OrganizationTypeDictionary()); config.addMapConfig(poolMapConfigs.map_WorkflowStatusDictionary()); - config.addMapConfig(poolMapConfigs.map_CompanyRoleSet()); +// config.addMapConfig(poolMapConfigs.map_CompanyRoleSet()); todo протестировать автоконфигуратор конфигурации мапсторов config.addMapConfig(poolMapConfigs.map_CompanySymbols()); config.addMapConfig(poolMapConfigs.map_ProfileDocument()); config.addMapConfig(poolMapConfigs.map_Contact()); config.addMapConfig(poolMapConfigs.map_Company()); // config.addMapConfig(poolMapConfigs.map_CompanyUpdate()); + // Автоподключение мап + List autoMapCfg = poolMapConfigs.autoconfiguratorOfMapstorages(); + for (MapConfig cfg: autoMapCfg) { + config.addMapConfig(cfg); + } + return config; } diff --git a/clearing-parent/imdg/src/main/java/ru/spcex/clearing/imdg/config/PoolMapConfigs.java b/clearing-parent/imdg/src/main/java/ru/spcex/clearing/imdg/config/PoolMapConfigs.java index 4ce9f09bb..7b1bc9499 100644 --- a/clearing-parent/imdg/src/main/java/ru/spcex/clearing/imdg/config/PoolMapConfigs.java +++ b/clearing-parent/imdg/src/main/java/ru/spcex/clearing/imdg/config/PoolMapConfigs.java @@ -2,8 +2,13 @@ package ru.spcex.clearing.imdg.config; import com.hazelcast.config.*; import com.hazelcast.core.MapLoader; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Configuration; +import ru.spcex.clearing.imdg.base.TemplateMapStore; import ru.spcex.clearing.imdg.businessevent.CompanyUpdateMapStore; import ru.spcex.clearing.imdg.businessobject.CompanyMapStore; import ru.spcex.clearing.imdg.dictionary.*; @@ -13,8 +18,14 @@ import ru.spcex.clearing.imdg.object.ContactMapStore; import ru.spcex.clearing.imdg.object.ProfileDocumentMapStore; import ru.spcex.clearing.imdg.utils.IMDGDistributedNames; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; + @Configuration public class PoolMapConfigs { + private Logger log = LoggerFactory.getLogger(getClass()); private ConfigurationRootElement configRoot = DfaConfig.get().getRoot(); @@ -127,12 +138,43 @@ public class PoolMapConfigs { - @Autowired - private CompanyRoleSetMapStore companyRoleSetMapStore; +// @Autowired todo эксперимент с мапстором, см. ниже autoconfiguratorOfMapstorage. +// private CompanyRoleSetMapStore companyRoleSetMapStore; +// +// public MapConfig map_CompanyRoleSet() { +// return makeDefaultMapConfig(IMDGDistributedNames.Map_CompanyRoleSet, companyRoleSetMapStore) +// .addMapIndexConfig(makeMapIndexConfig("companyId")); +// } - public MapConfig map_CompanyRoleSet() { - return makeDefaultMapConfig(IMDGDistributedNames.Map_CompanyRoleSet, companyRoleSetMapStore) - .addMapIndexConfig(makeMapIndexConfig("companyId")); + @Autowired + private List> listOfAutopluginStores; + + // @Qualifier("AutoconfiguredMapStore") + public List autoconfiguratorOfMapstorages() { + List out = new ArrayList<>(); + HashSet existMapStores = new HashSet<>(); + for (TemplateMapStore mapStore : listOfAutopluginStores) { + log.debug("Link mapstore {} to map {}", mapStore.toString(), mapStore.getMapName()); + if (StringUtils.isEmpty(mapStore.getMapName())) { + throw new IllegalArgumentException("MapStore " + mapStore + " has empty mapName"); + } + if (existMapStores.contains(mapStore.getMapName())) { + throw new IllegalArgumentException("MapStore " + mapStore + " has wrong mapName=\"" + mapStore.getMapName() + "\" is duplicated"); + } + existMapStores.add(mapStore.getMapName()); // IMDGDistributedNames + MapConfig mapCfg = makeDefaultMapConfig(mapStore.getMapName(), mapStore); + if (mapStore.getIndexingField() != null && mapStore.getIndexingField().length > 0) { + if (log.isTraceEnabled()) { + log.trace("Create indexing filed on {}: {}", mapStore.getMapName(), Arrays.toString(mapStore.getIndexingField())); + } + for (String indexName : mapStore.getIndexingField()) { + mapCfg.addMapIndexConfig(makeMapIndexConfig(indexName)); + } + } + out.add(mapCfg); + } + log.debug("Configured {} mapStore's", out.size()); + return out; } diff --git a/clearing-parent/imdg/src/main/java/ru/spcex/clearing/imdg/object/CompanyRoleSetMapStore.java b/clearing-parent/imdg/src/main/java/ru/spcex/clearing/imdg/object/CompanyRoleSetMapStore.java index 2fa1c286b..a5cddd8a2 100644 --- a/clearing-parent/imdg/src/main/java/ru/spcex/clearing/imdg/object/CompanyRoleSetMapStore.java +++ b/clearing-parent/imdg/src/main/java/ru/spcex/clearing/imdg/object/CompanyRoleSetMapStore.java @@ -4,12 +4,16 @@ import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Component; import ru.clearing.classes.StaticData.Company.CompanyRoleSet; import ru.spcex.clearing.imdg.base.ObjectBaseMapStore; +import ru.spcex.clearing.imdg.base.TemplateMapStore; import ru.spcex.clearing.imdg.utils.DbUtilsHelper; +import ru.spcex.clearing.imdg.utils.IMDGDistributedNames; +import java.sql.ResultSet; +import java.sql.SQLException; import java.util.*; @Component -public class CompanyRoleSetMapStore extends ObjectBaseMapStore { +public class CompanyRoleSetMapStore extends TemplateMapStore { public CompanyRoleSetMapStore(JdbcTemplate jdbcTemplate) { super(jdbcTemplate); @@ -20,41 +24,39 @@ public class CompanyRoleSetMapStore extends ObjectBaseMapStore { return "COMPANY_ROLE_SET"; } + @Override + public String getMapName() { + return IMDGDistributedNames.Map_CompanyRoleSet; + } + + @Override + public String[] getIndexingField() { + return new String[]{};// список индексируемых полей + } + // IMDGDistributedNames.Map_CompanyRoleSet + @Override public String[] getFields() { return new String[]{"id", "roleid", "companyid"}; } - protected final String insertStatement = DbUtilsHelper.createUpdateOrInsert(getTableName(), getFields(), "id"); - @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) -> { - CompanyRoleSet companyRoleSet = new CompanyRoleSet(); - companyRoleSet.setId(resultSet.getObject("id", Long.class)); - companyRoleSet.setRoleId(resultSet.getObject("roleid", Long.class)); - companyRoleSet.setCompanyId(resultSet.getObject("companyid", Long.class)); - return companyRoleSet; - }); + protected CompanyRoleSet objectReader(ResultSet resultSet) throws SQLException { + CompanyRoleSet companyRoleSet = new CompanyRoleSet(); + companyRoleSet.setId(resultSet.getObject("id", Long.class)); + companyRoleSet.setRoleId(resultSet.getObject("roleid", Long.class)); + companyRoleSet.setCompanyId(resultSet.getObject("companyid", Long.class)); + return companyRoleSet; } @Override - public void store(Map map) { - List batchArgs = new ArrayList<>(); - - for (Map.Entry entry : map.entrySet()) { - CompanyRoleSet partnerList = entry.getValue(); - - Object[] args = new Object[]{ - partnerList.getId(), - partnerList.getRoleId(), - partnerList.getCompanyId(), - }; - batchArgs.add(args); - } - batchInsertUpdate(insertStatement, batchArgs); + protected Object[] objectToField(CompanyRoleSet partnerList) { + Object[] args = new Object[]{ + partnerList.getId(), + partnerList.getRoleId(), + partnerList.getCompanyId(), + }; + return args; } } diff --git a/clearing-parent/imdg/src/main/java/ru/spcex/clearing/imdg/utils/DbUtilsHelper.java b/clearing-parent/imdg/src/main/java/ru/spcex/clearing/imdg/utils/DbUtilsHelper.java index 932f413c6..87b815198 100644 --- a/clearing-parent/imdg/src/main/java/ru/spcex/clearing/imdg/utils/DbUtilsHelper.java +++ b/clearing-parent/imdg/src/main/java/ru/spcex/clearing/imdg/utils/DbUtilsHelper.java @@ -42,10 +42,9 @@ public class DbUtilsHelper { " (" + Arrays.stream(fields).map(f -> "\"" + f.toUpperCase() + "\"").collect(Collectors.joining(", ")) + ") values (" + // Arrays.stream(fields).map(f -> "\"" + f.toUpperCase() + "\"").collect(Collectors.joining(", ", ":", "")); String.join(", ", Collections.nCopies(fields.length, "?")) + - ") WHERE "; - if (matchingKey != null) // PostgreSQL conflict_target fixme проверить мэтчинг - updateOrInsert += " " + matchingKey.toUpperCase(); - updateOrInsert += " CONFLICT DO UPDATE"; + ") ON CONFLICT "; + updateOrInsert += "(" + matchingKey.toUpperCase()+")"; + updateOrInsert += " DO UPDATE SET " + Arrays.stream(fields).filter(f->!matchingKey.equalsIgnoreCase(f)).map(f -> "\"" + f.toUpperCase() + "\"=EXCLUDED.\"" + f.toUpperCase() + "\"").collect(Collectors.joining(", ")); return updateOrInsert; } diff --git a/clearing-parent/imdg/src/test/java/ru/spcex/clearing/imdg/utils/DbUtilsHelperTest.java b/clearing-parent/imdg/src/test/java/ru/spcex/clearing/imdg/utils/DbUtilsHelperTest.java new file mode 100644 index 000000000..1d3c23bb6 --- /dev/null +++ b/clearing-parent/imdg/src/test/java/ru/spcex/clearing/imdg/utils/DbUtilsHelperTest.java @@ -0,0 +1,15 @@ +package ru.spcex.clearing.imdg.utils; + +import static org.testng.Assert.*; + +public class DbUtilsHelperTest { + + @org.testng.annotations.Test + public void testCreateUpdateOrInsert() { + String sql = DbUtilsHelper.createUpdateOrInsert("ENERGY", + new String[]{"id", "power", "circle", "of", "fantasy", "prime"}, "id"); + assertEquals(sql, + "INSERT INTO ENERGY (\"ID\", \"POWER\", \"CIRCLE\", \"OF\", \"FANTASY\", \"PRIME\") values (?, ?, ?, ?, ?, ?) ON CONFLICT (ID) DO UPDATE SET \"POWER\"=EXCLUDED.\"POWER\", \"CIRCLE\"=EXCLUDED.\"CIRCLE\", \"OF\"=EXCLUDED.\"OF\", \"FANTASY\"=EXCLUDED.\"FANTASY\", \"PRIME\"=EXCLUDED.\"PRIME\"" + ); + } +} \ No newline at end of file diff --git a/pom.xml b/pom.xml index fc38f55cd..4b499e564 100644 --- a/pom.xml +++ b/pom.xml @@ -89,6 +89,14 @@ c3p0 0.9.5.2 + + + + org.testng + testng + 7.5 + test +