diff --git a/clearing-parent/test-api-clearing/pom.xml b/clearing-parent/test-api-clearing/pom.xml index 8ed2b970f..7444c7297 100644 --- a/clearing-parent/test-api-clearing/pom.xml +++ b/clearing-parent/test-api-clearing/pom.xml @@ -9,12 +9,17 @@ test-api-clearing Test-api-clearing SPCEX-1.0.0.0 - Тестовые контроллеры для отладки клиринговой системы. Только для разработчиков. + + Тестовые контроллеры для отладки клиринговой системы. + Только для разработчиков. + 17 17 + + 17.0.1 @@ -34,13 +39,13 @@ ru.spcex.clearing classes SPCEX-1.0.0.0 - compile + ru.spcex.clearing dictionary SPCEX-1.0.0.0 - compile + @@ -63,10 +68,45 @@ com.fasterxml.jackson.core jackson-databind + + + + + + + + + + + + + + + + + + + + + + + + - ru.spcex.clearing - test-clearing - test + ru.spcex.platform + platform-imdg-api-hazelcast-impl + + + ru.spcex.platform + platform-messaging + + + io.springfox + springfox-swagger2 + + + io.springfox + springfox-swagger-ui diff --git a/clearing-parent/test-api-clearing/src/main/java/ru/spcex/clearing/test/ImdgService.java b/clearing-parent/test-api-clearing/src/main/java/ru/spcex/clearing/test/ImdgService.java index 2411b9dcf..2b284dafd 100644 --- a/clearing-parent/test-api-clearing/src/main/java/ru/spcex/clearing/test/ImdgService.java +++ b/clearing-parent/test-api-clearing/src/main/java/ru/spcex/clearing/test/ImdgService.java @@ -7,16 +7,17 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Service; import ru.clearing.classes.objects.BusinessObject; +import ru.spcex.clearing.imdg.IMDGDistributedNames; import java.util.ArrayList; import java.util.Collection; +import java.util.HashSet; import java.util.List; import java.util.concurrent.*; @Service public class ImdgService { - protected final Logger log= LoggerFactory.getLogger(getClass()); - int thread=3; + protected final Logger log = LoggerFactory.getLogger(getClass()); HazelcastInstance hazelcastServerInstance; @@ -24,16 +25,22 @@ public class ImdgService { return null; } - public int reloadMapFromDB() { log.info("Reload all from DB..."); long loadTime = System.currentTimeMillis(); int count = 0; + HashSet ignoreUpdateMap = new HashSet<>(); // Эти мапы не должны обновляться + ignoreUpdateMap.add(IMDGDistributedNames.Map_RequestInfo); + try { List> tasks = new ArrayList<>(); Collection mapNames = hazelcastServerInstance.getConfig().getMapConfigs().keySet(); for (String mapName : mapNames) { + if (ignoreUpdateMap.contains(mapName)) { + log.info("Ignore sync for map {}", mapName); + continue; + } tasks.add(() -> { Long maxKey = null; MapStoreConfig mapStoreConfig = hazelcastServerInstance.getConfig().getMapConfig(mapName).getMapStoreConfig(); @@ -41,15 +48,20 @@ public class ImdgService { long start = System.currentTimeMillis(); log.debug("evict map {}", mapName); IMap map = hazelcastServerInstance.getMap(mapName); -// todo проверить что ничего лишнего не попадет map.evictAll(); -// log.debug("Load map {}", mapName); -// map.loadAll(false); +// todo проверить что ничего лишнего не попадет + int size1 = map.size(); + map.evictAll(); + log.debug("Load map {}", mapName); + map.loadAll(false); int size = map.size(); long time = System.currentTimeMillis() - start; log.debug("{} {} rows reloaded in {}ms", mapName, size, time); + if (size1 != size) + log.warn("Map {} change size from {} to {}", mapName, size1, size); Object mapStore = mapStoreConfig.getImplementation(); //todo проверить реализацию. + maxKey = map.keySet().stream().max(Long::compareTo).orElse(null); // if (mapStore instanceof SimpleObjectMapStore) { // String tableName = ((SimpleObjectMapStore) mapStore).getTableName(); // maxKey = map.keySet().stream().max(Long::compareTo).orElse(null); // jdbcTemplate.queryForObject("select max(id) from " + tableName, Long.class); @@ -67,7 +79,7 @@ public class ImdgService { }); } long maxKey = 0L; - int threadCount = Runtime.getRuntime().availableProcessors();// todo config * Config.get().getRoot().getSettings().getInitHazelcastThreadMultiplier(); + int threadCount = 2; //Runtime.getRuntime().availableProcessors(); log.info("Initializing threads count = {}", threadCount); ExecutorService executor = Executors.newWorkStealingPool(threadCount); try { @@ -91,9 +103,8 @@ public class ImdgService { throw new RuntimeException("MapStore multithreaded reload not complete.", e); } -// HazelcastHelper.imdgSystem_setStorageState(true, hazelcastServerInstance); loadTime = System.currentTimeMillis() - loadTime; - log.info("All map reload time {} ms", loadTime); + log.info("All {} map reload time {} ms", count, loadTime); return count; } } diff --git a/clearing-parent/test-api-clearing/src/main/java/ru/spcex/clearing/test/KafkaService.java b/clearing-parent/test-api-clearing/src/main/java/ru/spcex/clearing/test/KafkaService.java index 60bec05aa..dbd6f971e 100644 --- a/clearing-parent/test-api-clearing/src/main/java/ru/spcex/clearing/test/KafkaService.java +++ b/clearing-parent/test-api-clearing/src/main/java/ru/spcex/clearing/test/KafkaService.java @@ -1,18 +1,45 @@ package ru.spcex.clearing.test; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import org.springframework.util.ClassUtils; +import org.springframework.util.StringUtils; +import ru.spcex.clearing.platform.messaging.service.sender.KafkaSender; import java.util.Collection; @Service public class KafkaService { + private static final ObjectMapper json = new ObjectMapper(); + protected final Logger log = LoggerFactory.getLogger(getClass()); + private final KafkaSender kafkaSender; + + @Autowired + public KafkaService(KafkaSender kafkaSender) { + this.kafkaSender = kafkaSender; + } Collection allTopics() { return null; } - int putMessage(String topic, String json) { - //todo - return 0; + public Long putMessage(String fullClassName, String topic, String jsonBody) throws ClassNotFoundException, JsonProcessingException { + log.info("Call test method for kafka, class=\"{}\"; topic=\"{}\"; message=\"{}\"", fullClassName, topic, jsonBody); + if (StringUtils.isEmpty(fullClassName)) throw new IllegalArgumentException("Class was emppty"); + if (StringUtils.isEmpty(topic)) throw new IllegalArgumentException("Topic was emppty"); + if (StringUtils.isEmpty(jsonBody)) throw new IllegalArgumentException("json was emppty"); + + Class parameterType = ClassUtils.forName(fullClassName, ClassUtils.getDefaultClassLoader()); + JavaType requestType = json.getTypeFactory().constructSimpleType(parameterType, null); + Object obj = json.readValue(jsonBody, requestType); + Long idOfBaseRequestMessage = kafkaSender.sendRequestToQueue(topic, obj); + log.debug("Test message to topic {} with request id={}", topic, idOfBaseRequestMessage); + return idOfBaseRequestMessage; } + } diff --git a/clearing-parent/test-api-clearing/src/main/java/ru/spcex/clearing/test/config/DirectImdgConfig.java b/clearing-parent/test-api-clearing/src/main/java/ru/spcex/clearing/test/config/DirectImdgConfig.java deleted file mode 100644 index df0ae9045..000000000 --- a/clearing-parent/test-api-clearing/src/main/java/ru/spcex/clearing/test/config/DirectImdgConfig.java +++ /dev/null @@ -1,66 +0,0 @@ -package ru.spcex.clearing.test.config; - -import com.hazelcast.client.HazelcastClient; -import com.hazelcast.client.config.ClientConfig; -import com.hazelcast.core.HazelcastInstance; -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.Bean; -import org.springframework.context.annotation.Configuration; -import ru.spcex.clearing.test.config.settings.TestServiceSettings; -import ru.spcex.platform.imdg.api.ImdgProvider; -import ru.spcex.platform.imdg.iml.hazelcast.config.HazelcastClientParams; -import ru.spcex.platform.imdg.iml.hazelcast.service.HazelcastService; -import ru.spcex.platform.imdg.iml.hazelcast.util.HazelcastHelper; - - -@Configuration -public class DirectImdgConfig { - Logger log = LoggerFactory.getLogger(getClass()); - -// @Autowired -// @Bean -// public ImdgProvider imdgProvider( -// @Qualifier("taskExecutorHazelcastClientInitializer") ThreadPoolTaskExecutor taskExecutorHazelcastClientInitializer, -// @Qualifier("taskExecutorIdGeneratorAwaiter") ThreadPoolTaskExecutor taskExecutorIdGeneratorAwaiter, -// TestServiceSettings clientSetting -// ) { -// ImdgProvider imdg = new HazelcastService(taskExecutorHazelcastClientInitializer, -// taskExecutorIdGeneratorAwaiter, -// clientSetting.getHazelcast()); -// return imdg; -// } - - @Autowired - @Bean("imdgNative") - public HazelcastInstance imdgNativeService(TestServiceSettings settings) { - HazelcastClientParams settingsElementHazelcastClient = settings.getHazelcast(); -// if (hazelcastInstance != null) { -// try { -// hazelcastInstance.shutdown(); -// } catch (Throwable ignored) { -// } -// } - HazelcastInstance hazelcastInstance; - log.info("Hazelcast: client init"); - ClientConfig clientConfig = HazelcastHelper.getClientConfig( - settingsElementHazelcastClient.getClusterMembers(), - settingsElementHazelcastClient.getLogin(), - settingsElementHazelcastClient.getPassword(), - settingsElementHazelcastClient.getInstanceName(), - settingsElementHazelcastClient.getNearCacheConfig() - ); -// if (environment != null && Arrays.asList(environment.getActiveProfiles()).contains("tests")) { -// clientConfig.getNetworkConfig().setConnectionAttemptLimit(HazelcastHelper.TEST_CONNECTION_ATTEMPT_LIMIT); -// } - log.info("Hazelcast: client created, trying connect to server ({}) ...", settingsElementHazelcastClient.getClusterMembers()); - hazelcastInstance = HazelcastClient.newHazelcastClient(clientConfig); - log.info("Hazelcast: client created and connected"); - return hazelcastInstance; - } - - - -} diff --git a/clearing-parent/test-api-clearing/src/main/java/ru/spcex/clearing/test/config/ImdgConfig.java b/clearing-parent/test-api-clearing/src/main/java/ru/spcex/clearing/test/config/ImdgConfig.java new file mode 100644 index 000000000..e564bce32 --- /dev/null +++ b/clearing-parent/test-api-clearing/src/main/java/ru/spcex/clearing/test/config/ImdgConfig.java @@ -0,0 +1,265 @@ +package ru.spcex.clearing.test.config; + +import com.hazelcast.client.HazelcastClient; +import com.hazelcast.client.config.ClientConfig; +import com.hazelcast.core.*; +import com.hazelcast.query.Predicate; +import com.hazelcast.query.Predicates; +import com.hazelcast.query.SqlPredicate; +import org.mockito.Mockito; +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.Bean; +import org.springframework.context.annotation.Configuration; +import ru.spcex.clearing.imdg.IMDGDistributedNames; +import ru.spcex.clearing.test.config.settings.TestServiceSettings; +import ru.spcex.platform.classes.base.SpcexObjectBase; +import ru.spcex.platform.imdg.api.Imdg; +import ru.spcex.platform.imdg.api.ImdgId; +import ru.spcex.platform.imdg.api.ImdgProvider; +import ru.spcex.platform.imdg.api.ImdgTransaction; +import ru.spcex.platform.imdg.iml.hazelcast.adapter.ImdgIdGeneratorHazelcast; +import ru.spcex.platform.imdg.iml.hazelcast.adapter.ImdgTransactionalHazelcast; +import ru.spcex.platform.imdg.iml.hazelcast.config.HazelcastClientParams; +import ru.spcex.platform.imdg.iml.hazelcast.service.HazelcastService; +import ru.spcex.platform.imdg.iml.hazelcast.util.HazelcastHelper; +import ru.spcex.platform.utils.log.ExceptionUtils; + +import java.util.*; + + +@Configuration +public class ImdgConfig { + Logger log = LoggerFactory.getLogger(getClass()); + + @Autowired + @Bean + public ImdgProvider imdgProvider( +// @Qualifier("taskExecutorHazelcastClientInitializer") ThreadPoolTaskExecutor taskExecutorHazelcastClientInitializer, +// @Qualifier("taskExecutorIdGeneratorAwaiter") ThreadPoolTaskExecutor taskExecutorIdGeneratorAwaiter, + TestServiceSettings clientSetting, HazelcastInstance hcInstance + ) { +// ImdgProvider imdg = new HazelcastService(taskExecutorHazelcastClientInitializer, +// taskExecutorIdGeneratorAwaiter, +// clientSetting.getHazelcast()); + + ImdgProvider imdg = new ImdgProvider() { + @Override + public Imdg getImdg(String key, Class clazz) { + ImdgDirectHazelcast imdg = new ImdgDirectHazelcast<>(); + imdg.setMap(hcInstance.getMap(key)); + imdg.setHzInstance(hcInstance); + imdg.setMapName(key); + imdg.setIdGenerator(hcInstance.getIdGenerator(IMDGDistributedNames.MAP_SEQUENCE_NAME)); + return imdg; + } + + @Override + public ImdgId getImdgIdGenerator() { + ImdgIdGeneratorHazelcast generator = new ImdgIdGeneratorHazelcast(); + generator.setIdGenerator(hcInstance.getIdGenerator(IMDGDistributedNames.MAP_SEQUENCE_NAME)); + return generator; + } + + @Override + public ImdgTransaction newTransaction() { + throw new UnsupportedOperationException("Stump has not implement high level function"); + } + }; + return imdg; + } + + @Autowired + @Bean("imdgNative") + public HazelcastInstance imdgNativeService(TestServiceSettings settings) { + HazelcastClientParams settingsElementHazelcastClient = settings.getHazelcast(); + HazelcastInstance hazelcastInstance; + log.info("Hazelcast: client init"); + ClientConfig clientConfig = HazelcastHelper.getClientConfig( + settingsElementHazelcastClient.getClusterMembers(), + settingsElementHazelcastClient.getLogin(), + settingsElementHazelcastClient.getPassword(), + settingsElementHazelcastClient.getInstanceName(), + settingsElementHazelcastClient.getNearCacheConfig() + ); +// hazelcastInstance = Mockito.mock(HazelcastInstance.class); // debug + log.info("Hazelcast: client created, trying connect to server ({}) ...", settingsElementHazelcastClient.getClusterMembers()); + hazelcastInstance = HazelcastClient.newHazelcastClient(clientConfig); + log.info("Hazelcast: client created and connected"); + return hazelcastInstance; + } + + + private static class ImdgDirectHazelcast implements Imdg { + private final Logger log = LoggerFactory.getLogger(getClass()); + private IdGenerator idGenerator; + + private IMap map; + + private String mapName; + + private HazelcastInstance hzInstance; + + @Override + public Long insert(T paramT) { + if (paramT.getId() == null) { + paramT.setId(idGenerator.newId()); + } + map.put(paramT.getId(), paramT); + return paramT.getId(); + } + + @Override + public void lockAndPerform(Runnable operation) { + ILock hzLock = null; + try { + //в качестве альтернативы getCPSubsystem, поддерживается только при 3+ нодах хазелкаста + hzLock = hzInstance.getLock(mapName); + hzLock.lock(); + operation.run(); + } finally { + if (hzLock != null) { + try { + hzLock.unlock(); + } catch (Throwable e) { + log.error("{} {}", mapName, ExceptionUtils.getStackTrace(e)); + } + } + } + } + + @Override + public void update(T paramT) { + map.put(paramT.getId(), paramT); + } + + @Override + public void delete(T paramT) { + map.remove(paramT.getId()); + } + + @Override + public T getSingleObjectByID(Long paramLong) { + return map.get(paramLong); + } + + /** + * возвращает объект удовлетворяющий условиям + * не проверяет, если удовлетворяющих условиям > 1 + */ + @SuppressWarnings("unchecked") + @Override + public T getFirstObjectByFieldValues(Map> conditions) { + Predicate[] predicates = new Predicate[conditions.size()]; + final int[] i = {0}; + conditions.forEach((key, value) -> { + predicates[i[0]] = Predicates.equal(key, value); + i[0]++; + }); + Predicate and = Predicates.and(predicates); + Set ids = map.keySet(and); + Iterator idsIterator = ids.iterator(); + if (idsIterator.hasNext()) { + return map.get(idsIterator.next()); + } else { + return null; + } + } + + @Override + public T getFirstObjectBySQL(String paramString) { + SqlPredicate sqlPredicate = new SqlPredicate(paramString); + Set found = map.keySet(sqlPredicate); + Iterator allFoundByCondition = found.iterator(); + if (allFoundByCondition.hasNext()) { + return map.get(allFoundByCondition.next()); + } else return null; + } + + @Override + public T getSingleObjectBySQL(String paramString) { + SqlPredicate sqlPredicate = new SqlPredicate(paramString); + Set found = map.keySet(sqlPredicate); + if (found.size() > 1) { + throw new RuntimeException("More than one element found by predicate [" + paramString + "] - " + found.size()); + } + Iterator allFoundByCondition = found.iterator(); + if (allFoundByCondition.hasNext()) { + return map.get(allFoundByCondition.next()); + } else return null; + } + + @Override + public Collection getCollectionObjectsBySQL(String paramString) { + SqlPredicate sqlPredicate = new SqlPredicate(paramString); + Collection found = map.values(sqlPredicate); + List result = new ArrayList<>(found); // Hazelcast может вернуть proxy-коллекцию + return result; + } + + /** + * возвращает коллекцию объектов, удовлетворяющий условиям на поля + */ + @SuppressWarnings("unchecked") + @Override + public Collection getCollectionObjectsByFieldValues(Map> conditions) { + Predicate[] predicates = new Predicate[conditions.size()]; + final int[] i = {0}; + conditions.forEach((key, value) -> { + predicates[i[0]] = Predicates.equal(key, value); + i[0]++; + }); + Predicate or = Predicates.or(predicates); + Set ids = map.keySet(or); + Iterator idIterator = ids.iterator(); + Collection searchResult = new ArrayList<>(); + while (idIterator.hasNext()) { + T element = map.get(idIterator.next()); + if (element != null) { + searchResult.add(element); + } + } + return searchResult; + } + + public IMap getMap() { + return map; + } + + public void setMap(IMap map) { + this.map = map; + } + + public IdGenerator getIdGenerator() { + return idGenerator; + } + + public void setIdGenerator(IdGenerator idGenerator) { + this.idGenerator = idGenerator; + } + + public HazelcastInstance getHzInstance() { + return hzInstance; + } + + public void setHzInstance(HazelcastInstance hzInstance) { + this.hzInstance = hzInstance; + } + + public String getMapName() { + return mapName; + } + + public void setMapName(String mapName) { + this.mapName = mapName; + } + + @Override + public Long nextIDSequenceFor() { + return idGenerator.newId(); + } + } + +} diff --git a/clearing-parent/test-api-clearing/src/main/java/ru/spcex/clearing/test/config/JsonUtil.java b/clearing-parent/test-api-clearing/src/main/java/ru/spcex/clearing/test/config/JsonUtil.java new file mode 100644 index 000000000..92f524927 --- /dev/null +++ b/clearing-parent/test-api-clearing/src/main/java/ru/spcex/clearing/test/config/JsonUtil.java @@ -0,0 +1,73 @@ +package ru.spcex.clearing.test.config; + +import com.fasterxml.jackson.annotation.JsonAutoDetect; +import com.fasterxml.jackson.annotation.PropertyAccessor; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.ObjectReader; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; + +import java.io.IOException; +import java.util.List; +import java.util.Map; +import java.util.Set; + +// todo it is copy-paste from test-clearing +public class JsonUtil { + + public static List readValues(String json, Class clazz) { + ObjectReader reader = JacksonObjectMapper.getMapper().readerFor(clazz); + try { + return reader.readValues(json).readAll(); + } catch (IOException e) { + throw new IllegalArgumentException("Invalid read array from JSON:\n'" + json + "'", e); + } + } + + public static T readValue(String json, Class clazz) { + try { + return JacksonObjectMapper.getMapper().readValue(json, clazz); + } catch (IOException e) { + throw new IllegalArgumentException("Invalid read from JSON:\n'" + json + "'", e); + } + } + + public static String writeValue(T obj) { + try { + return JacksonObjectMapper.getMapper().writeValueAsString(obj); + } catch (JsonProcessingException e) { + throw new IllegalStateException("Invalid write to JSON:\n'" + obj + "'", e); + } + } + + public static String writeIgnoreProps(T obj, String... ignoreProps) { + Map map = JacksonObjectMapper.getMapper().convertValue(obj, new TypeReference<>() { + }); + map.keySet().removeAll(Set.of(ignoreProps)); + return writeValue(map); + } + + public static class JacksonObjectMapper extends ObjectMapper { + private static final ObjectMapper MAPPER = new JacksonObjectMapper(); + + private JacksonObjectMapper() { + //настройки Ильи + configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, true); + //модуль для корректной сериализации LocalDateTime в поля JSON - JavaTimeModule модуль библиотеки jackson-datatype-jsr310 + registerModule(new JavaTimeModule()); + configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false); + //запрещаем доступ ко всем полям и методам класса и потом разрешаем доступ только к полям, нужны чтобы не было лишних полей из-за методов как: public ActionType getActionType() у BankAccountNewAction + setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.NONE); + setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY); + //не сериализуем null-поля +// setSerializationInclusion(JsonInclude.Include.NON_NULL); + } + + public static ObjectMapper getMapper() { + return MAPPER; + } + } +} \ No newline at end of file diff --git a/clearing-parent/test-api-clearing/src/main/java/ru/spcex/clearing/test/config/KafkaConfig.java b/clearing-parent/test-api-clearing/src/main/java/ru/spcex/clearing/test/config/KafkaConfig.java index 4727f7482..643c3694a 100644 --- a/clearing-parent/test-api-clearing/src/main/java/ru/spcex/clearing/test/config/KafkaConfig.java +++ b/clearing-parent/test-api-clearing/src/main/java/ru/spcex/clearing/test/config/KafkaConfig.java @@ -2,6 +2,7 @@ package ru.spcex.clearing.test.config; import org.apache.kafka.clients.consumer.Consumer; import org.apache.kafka.clients.producer.Producer; +import org.mockito.Mockito; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.config.ConfigurableBeanFactory; @@ -23,23 +24,26 @@ import ru.spcex.platform.imdg.api.ImdgProvider; @Configuration public class KafkaConfig { - @Autowired - @Bean - @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) - public Consumer createConsumer(TestServiceSettings settings) { - return KafkaConsumerFactory.consumer(settings.getKafkaConsumer()); - } +// @Autowired +// @Bean +// @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) +// public Consumer createConsumer(TestServiceSettings settings) { +// return KafkaConsumerFactory.consumer(settings.getKafkaConsumer()); +//// return Mockito.mock(Consumer.class); +// } @Autowired @Bean public Producer createProducer(TestServiceSettings settings) { return KafkaProducerFactory.producer(settings.getKafkaProducer()); +// return Mockito.mock(Producer.class); } @Bean public ProducerFactory pf(TestServiceSettings settings) { KafkaProducerSettings kafkaSettings = settings.getKafkaProducer(); return KafkaProducerFactory.producerFactory(kafkaSettings); +// return Mockito.mock(ProducerFactory.class); } @Bean("kafkaTemplate") @@ -50,7 +54,8 @@ public class KafkaConfig { @Autowired @Bean public KafkaSender kafkaSender(@Qualifier("kafkaTemplate") KafkaTemplate kafkaTemplate, - ImdgProvider imdgProvider) { + ImdgProvider imdgProvider + ) { ImdgId imdgIdGenerator = imdgProvider.getImdgIdGenerator(); return KafkaSender .setup() @@ -61,5 +66,7 @@ public class KafkaConfig { return imdg::insert; }) .build(); + +// return Mockito.mock(KafkaSender.class); } } diff --git a/clearing-parent/test-api-clearing/src/main/java/ru/spcex/clearing/test/config/SwaggerConfig.java b/clearing-parent/test-api-clearing/src/main/java/ru/spcex/clearing/test/config/SwaggerConfig.java deleted file mode 100644 index 1f0204817..000000000 --- a/clearing-parent/test-api-clearing/src/main/java/ru/spcex/clearing/test/config/SwaggerConfig.java +++ /dev/null @@ -1,39 +0,0 @@ -package ru.spcex.clearing.test.config; - -import com.google.common.base.Predicates; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import springfox.documentation.builders.ApiInfoBuilder; -import springfox.documentation.builders.PathSelectors; -import springfox.documentation.builders.RequestHandlerSelectors; -import springfox.documentation.service.ApiInfo; -import springfox.documentation.spi.DocumentationType; -import springfox.documentation.spring.web.plugins.Docket; -import springfox.documentation.swagger2.annotations.EnableSwagger2; - -@SuppressWarnings("Guava") -@Configuration -@EnableSwagger2 -public class SwaggerConfig { - - @Bean - public Docket api() { - return new Docket(DocumentationType.SWAGGER_2) - .groupName("clearing-backend-api") - .apiInfo(metadata()) - .select() - .apis(Predicates.not(RequestHandlerSelectors.basePackage("org.springframework.boot"))) - .paths(PathSelectors.any()) - .build() - .useDefaultResponseMessages(false); - } - - private ApiInfo metadata() { - return new ApiInfoBuilder() - .title("Spcex Clearing service") - .description("Сервис клиринга") - .version("0.0.1") - .build(); - } - -} diff --git a/clearing-parent/test-api-clearing/src/main/java/ru/spcex/clearing/test/config/WebConfig.java b/clearing-parent/test-api-clearing/src/main/java/ru/spcex/clearing/test/config/WebConfig.java deleted file mode 100644 index 9f83a7ade..000000000 --- a/clearing-parent/test-api-clearing/src/main/java/ru/spcex/clearing/test/config/WebConfig.java +++ /dev/null @@ -1,106 +0,0 @@ -package ru.spcex.clearing.test.config; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.boot.web.server.Cookie; -import org.springframework.boot.web.server.WebServerFactoryCustomizer; -import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory; -import org.springframework.boot.web.servlet.server.CookieSameSiteSupplier; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.http.converter.HttpMessageConverter; -import org.springframework.http.converter.StringHttpMessageConverter; -import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; -import org.springframework.web.bind.annotation.CrossOrigin; -import org.springframework.web.context.request.RequestContextListener; -import org.springframework.web.servlet.config.annotation.*; -import ru.spcex.clearing.test.config.settings.TestServiceSettings; - - -import java.util.List; -import java.util.function.Consumer; - -@SuppressWarnings("Duplicates") -@Configuration -@EnableWebMvc -//todo remove? see ClearingCorsFilter -@CrossOrigin -public class WebConfig implements WebMvcConfigurer { - private final MappingJackson2HttpMessageConverter customJsonHttpConverter; - private final String sameSite; - - @Bean("customJsonHttpConverter") - public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() { - return new MappingJackson2HttpMessageConverter(JsonUtil.JacksonObjectMapper.getMapper()); - } - - @Autowired - public WebConfig(@Qualifier("customJsonHttpConverter") MappingJackson2HttpMessageConverter customJsonHttpConverter, - TestServiceSettings backendSettings - ) { - this.customJsonHttpConverter = customJsonHttpConverter; - sameSite = null; // this.sameSite = backendSettings.getSecurity().getSameSite(); - } - - @Override - public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) { - configurer.enable(); - } - - @Autowired - @Override - public void configureMessageConverters(List> messageConverters) { - Consumer> addConverter = httpMessageConverter -> { - messageConverters.removeIf(registeredConverter -> registeredConverter.getClass().equals(httpMessageConverter.getClass())); - messageConverters.add(httpMessageConverter); - }; - addConverter.accept(new StringHttpMessageConverter()); - addConverter.accept(customJsonHttpConverter); - } - - @Override - public void addViewControllers(ViewControllerRegistry registry) { - registry.addRedirectViewController("/v2/api-docs", "/v2/api-docs?group=api"); - registry.addRedirectViewController("/swagger-resources/configuration/ui", "/swagger-resources/configuration/ui"); - registry.addRedirectViewController("/swagger-resources/configuration/security", "/swagger-resources/configuration/security"); - registry.addRedirectViewController("/swagger-resources", "/swagger-resources"); - registry.addRedirectViewController("", "/swagger-ui.html"); - } - - @Override - public void addResourceHandlers(ResourceHandlerRegistry registry) { - registry - .addResourceHandler("/swagger-ui.html**") - .addResourceLocations("classpath:/META-INF/resources/swagger-ui.html"); - } - - @Bean - public WebServerFactoryCustomizer enableDefaultServlet() { - return (factory) -> factory.setRegisterDefaultServlet(true); - } - - @Override - public void addCorsMappings(CorsRegistry registry) { - registry.addMapping("/**").allowedMethods("*"); - } - - @Bean - public RequestContextListener requestContextListener() { - return new RequestContextListener(); - } - - @Bean - public CookieSameSiteSupplier applicationCookieSameSiteSupplier() { - if (sameSite == null) { - return null; - } else if (sameSite.equalsIgnoreCase(Cookie.SameSite.NONE.attributeValue())) { - return CookieSameSiteSupplier.ofNone(); - } else if (sameSite.equalsIgnoreCase(Cookie.SameSite.LAX.attributeValue())) { - return CookieSameSiteSupplier.ofLax(); - } else if (sameSite.equalsIgnoreCase(Cookie.SameSite.STRICT.attributeValue())) { - return CookieSameSiteSupplier.ofStrict(); - } else { - throw new IllegalStateException("unknown SameSite setting"); - } - } -} diff --git a/clearing-parent/test-api-clearing/src/main/java/ru/spcex/clearing/test/config/settings/TestServiceSettings.java b/clearing-parent/test-api-clearing/src/main/java/ru/spcex/clearing/test/config/settings/TestServiceSettings.java index 28d35460b..8a001f244 100644 --- a/clearing-parent/test-api-clearing/src/main/java/ru/spcex/clearing/test/config/settings/TestServiceSettings.java +++ b/clearing-parent/test-api-clearing/src/main/java/ru/spcex/clearing/test/config/settings/TestServiceSettings.java @@ -15,7 +15,7 @@ public class TestServiceSettings { private KafkaConsumerSettings kafkaConsumer; private KafkaProducerSettings kafkaProducer; - private ControllerSettings controllerSettings;//todo refactoring + private ControllerSettings controllerSettings; public ControllerSettings getControllerSettings() { return controllerSettings; diff --git a/clearing-parent/test-api-clearing/src/main/java/ru/spcex/clearing/test/controller/Controller.java b/clearing-parent/test-api-clearing/src/main/java/ru/spcex/clearing/test/controller/Controller.java index 6c8ad9a59..5a9d2d430 100644 --- a/clearing-parent/test-api-clearing/src/main/java/ru/spcex/clearing/test/controller/Controller.java +++ b/clearing-parent/test-api-clearing/src/main/java/ru/spcex/clearing/test/controller/Controller.java @@ -3,92 +3,73 @@ package ru.spcex.clearing.test.controller; import com.sun.net.httpserver.HttpExchange; import com.sun.net.httpserver.HttpHandler; import com.sun.net.httpserver.HttpServer; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.DisposableBean; -import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import org.springframework.util.StringUtils; import ru.spcex.clearing.test.ImdgService; -import ru.spcex.clearing.test.config.settings.ControllerSettings; +import ru.spcex.clearing.test.KafkaService; import ru.spcex.clearing.test.config.settings.TestServiceSettings; import ru.spcex.platform.utils.log.ExceptionUtils; import java.io.IOException; import java.io.OutputStream; -import java.net.InetSocketAddress; import java.time.LocalDateTime; +import java.util.Map; @Service -public class Controller implements InitializingBean, DisposableBean { - protected final Logger log = LoggerFactory.getLogger(getClass()); - HttpServer server; - - final ControllerSettings settings; - final ImdgService imdgService; +public class Controller extends HttpServerSimpleFramework { + protected final ImdgService imdgService; + protected final KafkaService kafkaService; @Autowired - public Controller(ImdgService imdgService, TestServiceSettings settings) { + public Controller(ImdgService imdgService, KafkaService kafkaService, + TestServiceSettings settings) { + super(Integer.parseInt(settings.getControllerSettings().getPort()), settings.getControllerSettings().getContextPath()); + if (settings.getControllerSettings() == null || settings.getControllerSettings().getPort() == null) { + log.warn("Debug HTTP port not set, can not init HTTP controller service."); + } this.imdgService = imdgService; - this.settings = settings.getControllerSettings(); + this.kafkaService = kafkaService; } @Override - public void afterPropertiesSet() throws Exception { - Integer port = null; // 8701 - try { - if (settings == null || StringUtils.isEmpty(settings.getPort())) { - log.debug("Debug HTTP port not set, do not init HTTP controller service."); - return; + protected void createContextPages(HttpServer server, String baseUrl) throws IOException { + //server.createContext(baseUrl, new RedirectPage(baseUrl+"index.html")); + //server.createContext(baseUrl + "/favicon.ico", staticPageFromResource("pages/favicon.ico", null).contentType="image/icon"); + server.createContext(baseUrl + "", staticPageFromResource("pages/index.html", null)); + + // Database + server.createContext(baseUrl + "imdg/reload", new ImdgHandler()); + //server.createContext(baseUrl+"db/info", new ImdgInfoHandler()); + + // Message + server.createContext(baseUrl + "message.html", staticPageFromResource("pages/message.html", null)); + server.createContext(baseUrl + "message.do", new KafkaHandler()); + } + + class KafkaHandler extends CustomHtmlHandler { + @Override + public void makePage(HttpExchange exchange, OutputStream os) throws IOException { + if ("post".equalsIgnoreCase(exchange.getRequestMethod())) { + Map parsed = parsePostBody(exchange); + + String fullCLass = parsed.get("field0"); + String qName = parsed.get("field1"); + String msg = parsed.get("field2"); + writeLine(os, "

Sending message to" + qName + "

"); + try { + Long n = kafkaService.putMessage(fullCLass, qName, msg); + writeLine(os, "Message #" + n + " success send: "); + } catch (Exception er) { + writeLine(os, "

Message error:" + ExceptionUtils.getStackTrace(er) + "

"); + } + writeLine(os, "

" + msg + "

"); + } else { + writeLine(os, "

HTTP method " + exchange.getRequestMethod() + ". Use POST method.

"); } - port = Integer.parseInt(settings.getPort().trim()); - String url = settings.getContextPath().trim(); - log.info("Controller for debug reload star at port {} with url \"{}\"", port, url); - this.server = HttpServer.create(new InetSocketAddress(port), 0); - IndexHandler index=new IndexHandler(); - server.createContext(url, index); - server.createContext(url+"/index.html", index); - server.createContext(url+"/imdg", new ImdgHandler()); - server.createContext(url+"/kafka", new KafkaHandler()); - server.setExecutor(null); // default - server.start(); - } catch (Throwable t) { - log.error("Can not start debug HTTP server in port {}: {}", port, ExceptionUtils.getStackTrace(t)); } } - @Override - public void destroy() throws Exception { - if (server != null) { - server.stop(100); - log.info("Controller for reload stop."); - } - } - - - class IndexHandler extends HtmlHandler { - @Override - public void makePage(HttpExchange t, OutputStream os) throws IOException { - writeLine(os, "Welcome!
"); - writeLine(os, " Reload IMDG. "); - writeLine(os, " Send to kafka. "); - } - } - class KafkaHandler extends HtmlHandler { - @Override - public void makePage(HttpExchange t, OutputStream os) throws IOException { - writeLine(os, "Welcome kafka send!
"); - byte[] jsonB = t.getRequestBody().readAllBytes(); - //t.getRequestHeaders().getFirst() - String json=new String(jsonB, "windows-1251"); - //todo ... - writeLine(os, " Reload IMDG. "); - writeLine(os, " Send to kafka. "); - } - } - - class ImdgHandler extends HtmlHandler { + class ImdgHandler extends CustomHtmlHandler { @Override public void makePage(HttpExchange t, OutputStream os) throws IOException { writeLine(os, "Wait, reload all maps from DB...
"); @@ -110,30 +91,4 @@ public class Controller implements InitializingBean, DisposableBean { } } - - abstract class HtmlHandler implements HttpHandler { - public abstract void makePage(HttpExchange t, OutputStream os) throws IOException; - - @Override - public void handle(HttpExchange t) throws IOException { - log.info("{} request by user \"{}\"", getClass().getSimpleName(), t.getRemoteAddress().getAddress()); - t.sendResponseHeaders(200, 0); - t.setAttribute("Content-Type", "text/html; charset=windows-1251"); // or "text/plain или text/html; charset=windows-1251" - try (OutputStream os = t.getResponseBody()) { - writeLine(os, "\n\n"); - writeLine(os, "
"); - makePage(t, os); - writeLine(os, "
"); - writeLine(os, ""); - } - log.trace("HTTP Request done."); - } - - void writeLine(OutputStream os, String text) throws IOException { - if (text != null) - os.write(text.getBytes("windows-1251")); - os.write("\n".getBytes("windows-1251")); - } - - } -} +} \ No newline at end of file diff --git a/clearing-parent/test-api-clearing/src/main/java/ru/spcex/clearing/test/controller/HttpServerSimpleFramework.java b/clearing-parent/test-api-clearing/src/main/java/ru/spcex/clearing/test/controller/HttpServerSimpleFramework.java new file mode 100644 index 000000000..bd7401817 --- /dev/null +++ b/clearing-parent/test-api-clearing/src/main/java/ru/spcex/clearing/test/controller/HttpServerSimpleFramework.java @@ -0,0 +1,185 @@ +package ru.spcex.clearing.test.controller; + +import com.sun.net.httpserver.Headers; +import com.sun.net.httpserver.HttpExchange; +import com.sun.net.httpserver.HttpHandler; +import com.sun.net.httpserver.HttpServer; + +import java.io.*; +import java.net.InetSocketAddress; +import java.net.URLDecoder; +import java.nio.charset.Charset; +import java.nio.file.Files; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Objects; + +import org.apache.commons.lang3.exception.ExceptionUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.DisposableBean; +import org.springframework.beans.factory.InitializingBean; + +/** + * Простой HTTP server и фреимворк для HTML5 страниц. + * Только для отладки. + */ +public abstract class HttpServerSimpleFramework implements InitializingBean, DisposableBean { + protected final Logger log = LoggerFactory.getLogger(getClass()); + protected HttpServer server; + protected Integer port; + protected String baseUrl; + + + public HttpServerSimpleFramework(Integer port, String baseUrl) { + this.port = port; + this.baseUrl = baseUrl; + } + + protected void createContextPages(HttpServer server, String baseUrl) throws IOException { + server.createContext(baseUrl, new RedirectPage(baseUrl + "index.html")); + server.createContext(baseUrl + "index.html", staticPageFromResource("pages/index.html", null)); + } + + @Override + public void afterPropertiesSet() throws Exception { + Integer port = null; // 8080 + try { + log.info("Server star at port {} with url \"{}\"", port, baseUrl); + this.server = HttpServer.create(new InetSocketAddress(port), 0); + server.setExecutor(null); // default + createContextPages(server, baseUrl); + server.start(); + } catch (Throwable t) { + log.error("Can not start HTTP server in port {}: {}", port, ExceptionUtils.getStackTrace(t)); + throw t; + } + } + + @Override + public void destroy() throws Exception { + if (server != null) { + server.stop(100); + log.info("HTTP test controller stop."); + } + } + + public static Map parsePostBody(HttpExchange exchange) throws IOException { + try (InputStreamReader isr = new InputStreamReader(exchange.getRequestBody(), "utf-8"); + BufferedReader br = new BufferedReader(isr)) { + String query = br.readLine(); + return parsePostBody(query); + } + } + + public static Map parsePostBody(String data) { + String[] elems = data.split("&"); + Map param = new LinkedHashMap<>(); + for (String token : elems) { + int separator = token.indexOf("="); + if (separator == -1) throw new IllegalArgumentException("Separator '=' not found in: " + token); + String key = token.substring(0, separator); + String value = token.substring(separator + 1, token.length()); + key = URLDecoder.decode(key); + value = URLDecoder.decode(value); + param.put(key, value); + } + return param; + } + + public abstract class CustomHtmlHandler implements HttpHandler { + protected final Logger log = LoggerFactory.getLogger(getClass()); + protected final Charset encodung = Charset.forName("windows-1251"); + + public abstract void makePage(HttpExchange he, OutputStream os) throws IOException; + + @Override + public void handle(HttpExchange he) throws IOException { + log.info("{} request by user \"{}\" {} url {}", getClass().getSimpleName(), + he.getRemoteAddress().getAddress(), he.getRequestMethod(), he.getRequestURI()); + he.sendResponseHeaders(200, 0); + he.setAttribute("Content-Type", "text/html; charset=windows-1251"); // or "text/plain или text/html; charset=windows-1251" + try (OutputStream os = he.getResponseBody()) { + writeLine(os, "\n\n"); + writeLine(os, "
"); + makePage(he, os); + writeLine(os, "
"); + writeLine(os, ""); + } catch (Exception e) { + log.error("Content build error at page \"{}\": {}", + he.getRequestURI(), ExceptionUtils.getStackTrace(e)); + throw e; + } + log.trace("HTTP Request done."); + } + + protected void writeLine(OutputStream os, String text) throws IOException { + if (text != null) + os.write(text.getBytes(encodung)); + os.write("\n".getBytes(encodung)); + } + } + + public static class RedirectPage implements HttpHandler { + protected final Logger log = LoggerFactory.getLogger(getClass()); + protected String toUrl; + + public RedirectPage(String toUrl) { + this.toUrl = Objects.requireNonNull(toUrl); + } + + @Override + public void handle(HttpExchange he) throws IOException { + log.info("Access {} url \"{}\" IP {}; redirect to \"{}\"", he.getRequestMethod(), + he.getRequestURI(), he.getRemoteAddress().getAddress().getHostAddress(), toUrl); + Headers responseHeaders = he.getResponseHeaders(); + responseHeaders.set("Location", toUrl); + he.sendResponseHeaders(301, 0); // https://developer.mozilla.org/ru/docs/Web/HTTP/Redirections + he.close(); + } + } + + public static StaticPage staticPageFromFile(File fromFile, String encoding) throws IOException { + if (encoding == null) encoding = "windows-1251"; + String str = Files.readString(fromFile.toPath(), Charset.forName(encoding)); + StaticPage page = new StaticPage(str); + page.encoding = Charset.forName(encoding); + page.contentType = "text/html; charset=" + page.encoding.name(); + return page; + } + + public static StaticPage staticPageFromResource(String inRes, String encoding) throws IOException { + if (encoding == null) encoding = "windows-1251"; + String str = new String(StaticPage.class.getClassLoader().getResourceAsStream(inRes).readAllBytes(), encoding); + StaticPage page = new StaticPage(str); + page.encoding = Charset.forName(encoding); + page.contentType = "text/html; charset=" + page.encoding.name(); + return page; + } + + public static class StaticPage implements HttpHandler { + protected final Logger log = LoggerFactory.getLogger(getClass()); + protected Charset encoding = Charset.forName("windows-1251"); + protected String contentType = "text/html; charset=" + encoding.name(); + protected String content; + + public StaticPage(String content) { + this.content = Objects.requireNonNull(content); + } + + @Override + public void handle(HttpExchange he) throws IOException { + log.info("Access {} url \"{}\" IP {}", he.getRequestMethod(), he.getRequestURI(), + he.getRemoteAddress().getAddress().getHostAddress()); + he.sendResponseHeaders(200, 0); + if (contentType != null) + he.setAttribute("Content-Type", contentType); + try (OutputStream os = he.getResponseBody()) { + os.write(content.getBytes(encoding)); + } catch (Exception err) { + he.sendResponseHeaders(500, 0); // too late + log.error("StaticPage error {}", ExceptionUtils.getStackTrace(err)); + } + } + } +} diff --git a/clearing-parent/test-api-clearing/src/main/java/ru/spcex/clearing/test/controller/ImdgController.java b/clearing-parent/test-api-clearing/src/main/java/ru/spcex/clearing/test/controller/ImdgController.java deleted file mode 100644 index 50d142a38..000000000 --- a/clearing-parent/test-api-clearing/src/main/java/ru/spcex/clearing/test/controller/ImdgController.java +++ /dev/null @@ -1,111 +0,0 @@ -package ru.spcex.clearing.test.controller; - - -import com.sun.net.httpserver.HttpExchange; -import com.sun.net.httpserver.HttpHandler; -import com.sun.net.httpserver.HttpServer; -import org.apache.commons.lang3.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.DisposableBean; -import org.springframework.beans.factory.InitializingBean; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; -import ru.spcex.clearing.test.ImdgService; -import ru.spcex.clearing.test.config.settings.ControllerSettings; -import ru.spcex.clearing.test.config.settings.TestServiceSettings; -import ru.spcex.platform.utils.log.ExceptionUtils; - -import java.io.IOException; -import java.io.OutputStream; -import java.net.InetSocketAddress; -import java.time.LocalDateTime; - -@Service -public class ImdgController implements InitializingBean, DisposableBean { - protected final Logger log = LoggerFactory.getLogger(getClass()); - protected HttpServer server; - - protected final ControllerSettings settings; - protected final ImdgService imdgService; - - @Autowired - public ImdgController(ImdgService imdgService, TestServiceSettings settings) { - this.imdgService = imdgService; - this.settings = settings.getControllerSettings(); - } - - @Override - public void afterPropertiesSet() throws Exception { - Integer port = null; // 8701 - try { - if (settings == null || StringUtils.isEmpty(settings.getPort())) { - log.debug("Debug HTTP port not set, do not init HTTP controller service."); - return; - } - port = Integer.parseInt(settings.getPort().trim()); - String url = StringUtils.isBlank(settings.getContextPath()) ? "/imdg" : settings.getContextPath().trim(); - log.info("Controller for debug reload star at port {} with url \"{}\"", port, url); - this.server = HttpServer.create(new InetSocketAddress(port), 0); - server.createContext(url, new MyHandler()); - server.setExecutor(null); // default - server.start(); - } catch (Throwable t) { - log.error("Can not start debug HTTP server in port {}: {}", port, ExceptionUtils.getStackTrace(t)); - } - } - - @Override - public void destroy() throws Exception { - if (server != null) { - server.stop(100); - log.info("Controller for reload stop."); - } - } - - class MyHandler implements HttpHandler { - @Override - public void handle(HttpExchange t) throws IOException { - log.info("Reload request by user \"{}\"", t.getRemoteAddress().getAddress()); - t.sendResponseHeaders(200, 0); - t.setAttribute("Content-Type", "text/html; charset=windows-1251"); // or "text/plain или text/html; charset=windows-1251" - try (OutputStream os = t.getResponseBody()) { - writeHead(os); - writeLine(os, "Wait, reload all maps from DB...
"); - synchronized (ImdgController.this) { - os.flush(); - try { - long clock = System.currentTimeMillis(); - int count = imdgService.reloadMapFromDB(); - clock = System.currentTimeMillis() - clock; - writeLine(os, count + " map per " + clock + " ms
"); - } catch (Throwable e) { - String msg = "Error reload: " + ExceptionUtils.getStackTrace(e); - log.error(msg); - writeLine(os, msg); - } - } - writeLine(os, "Done. " + LocalDateTime.now() + "
"); - writeLine(os, " Reload again. "); - writeEnd(os); - } //os.close(); - log.trace("HTTP Request done."); - } - - void writeHead(OutputStream os) throws IOException { - writeLine(os, "\n\n"); - writeLine(os, "
"); - } - - void writeLine(OutputStream os, String text) throws IOException { - if (text != null) - os.write(text.getBytes("windows-1251")); - os.write("\n".getBytes("windows-1251")); - } - - void writeEnd(OutputStream os) throws IOException { - writeLine(os, "
"); - writeLine(os, ""); - } - } -} diff --git a/clearing-parent/test-api-clearing/src/main/java/ru/spcex/clearing/test/controller/kafka/AnyKafkaMessageAction.java b/clearing-parent/test-api-clearing/src/main/java/ru/spcex/clearing/test/controller/kafka/AnyKafkaMessageAction.java index d3c2af435..146cc7246 100644 --- a/clearing-parent/test-api-clearing/src/main/java/ru/spcex/clearing/test/controller/kafka/AnyKafkaMessageAction.java +++ b/clearing-parent/test-api-clearing/src/main/java/ru/spcex/clearing/test/controller/kafka/AnyKafkaMessageAction.java @@ -1,59 +1,59 @@ -package ru.spcex.clearing.test.controller.kafka; - -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonRawValue; -import com.fasterxml.jackson.databind.JsonNode; -import io.swagger.annotations.ApiModelProperty; -import ru.spcex.clearing.platform.messaging.domain.ActionType; -import ru.spcex.clearing.platform.messaging.domain.cud.registry.TradingClearingRegistryNewRequest; - -public class AnyKafkaMessageAction /*implements IAction*/ { - @ApiModelProperty(value = "полное имя класса payload для BaseRequest", example = "ru.spcex.clearing.platform.messaging.domain.cud.schedule.LauncherCommandRequest") - @JsonProperty - private String fullClassName; - @JsonProperty - private String topicName; - @JsonRawValue - public String json; - - @JsonProperty("json") - private void unpackRawJson(JsonNode json) { - this.json = json.toString(); - } - -// @Override - public TradingClearingRegistryNewRequest toRequest() { - var req = new TradingClearingRegistryNewRequest(); - return req; - } - - @ApiModelProperty(hidden = true) -// @Override - public ActionType getActionType() { - return ActionType.SYSTEM; - } - - public String getFullClassName() { - return fullClassName; - } - - public void setFullClassName(String fullClassName) { - this.fullClassName = fullClassName; - } - - public String getTopicName() { - return topicName; - } - - public void setTopicName(String topicName) { - this.topicName = topicName; - } - - public String getJson() { - return json; - } - - public void setJson(String json) { - this.json = json; - } -} +//package ru.spcex.clearing.test.controller.kafka; +// +//import com.fasterxml.jackson.annotation.JsonProperty; +//import com.fasterxml.jackson.annotation.JsonRawValue; +//import com.fasterxml.jackson.databind.JsonNode; +//import io.swagger.annotations.ApiModelProperty; +//import ru.spcex.clearing.platform.messaging.domain.ActionType; +//import ru.spcex.clearing.platform.messaging.domain.cud.registry.TradingClearingRegistryNewRequest; +// +//public class AnyKafkaMessageAction /*implements IAction*/ { +// @ApiModelProperty(value = "полное имя класса payload для BaseRequest", example = "ru.spcex.clearing.platform.messaging.domain.cud.schedule.LauncherCommandRequest") +// @JsonProperty +// private String fullClassName; +// @JsonProperty +// private String topicName; +// @JsonRawValue +// public String json; +// +// @JsonProperty("json") +// private void unpackRawJson(JsonNode json) { +// this.json = json.toString(); +// } +// +//// @Override +// public TradingClearingRegistryNewRequest toRequest() { +// var req = new TradingClearingRegistryNewRequest(); +// return req; +// } +// +// @ApiModelProperty(hidden = true) +//// @Override +// public ActionType getActionType() { +// return ActionType.SYSTEM; +// } +// +// public String getFullClassName() { +// return fullClassName; +// } +// +// public void setFullClassName(String fullClassName) { +// this.fullClassName = fullClassName; +// } +// +// public String getTopicName() { +// return topicName; +// } +// +// public void setTopicName(String topicName) { +// this.topicName = topicName; +// } +// +// public String getJson() { +// return json; +// } +// +// public void setJson(String json) { +// this.json = json; +// } +//} diff --git a/clearing-parent/test-api-clearing/src/main/java/ru/spcex/clearing/test/controller/kafka/KafkaApiController.java b/clearing-parent/test-api-clearing/src/main/java/ru/spcex/clearing/test/controller/kafka/KafkaApiController.java index fa035d507..3d930fd85 100644 --- a/clearing-parent/test-api-clearing/src/main/java/ru/spcex/clearing/test/controller/kafka/KafkaApiController.java +++ b/clearing-parent/test-api-clearing/src/main/java/ru/spcex/clearing/test/controller/kafka/KafkaApiController.java @@ -1,88 +1,88 @@ -package ru.spcex.clearing.test.controller.kafka; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.JavaType; -import com.fasterxml.jackson.databind.ObjectMapper; -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.MediaType; -import org.springframework.stereotype.Controller; -import org.springframework.util.ClassUtils; -import org.springframework.web.bind.annotation.RequestBody; -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.platform.messaging.service.sender.KafkaSender; -import ru.spcex.platform.utils.enumeration.EnumMessage; -import ru.spcex.platform.utils.enumeration.IErrorEnumId; -import ru.spcex.platform.utils.error.ValidationException; -import ru.spcex.platform.utils.text.TextUtil; - -@Controller -@RequestMapping("/anonymous/kafka-api") -public class KafkaApiController { - private final Logger log = LoggerFactory.getLogger(getClass()); - private final KafkaSender kafkaSender; - private static final ObjectMapper json = new ObjectMapper(); - static { - } - - enum BackEndError implements IErrorEnumId { - ValidationError(9000L), - UnknownJsonProperty(9001L), - FailedToReadHttpMessage(9002L), - KeycloakRepeatedRoles(9003L), - DictionaryNotFound(9004L), - ResourceNotFound(9005L) - ; - private final Long id; - - BackEndError(Long id) { - this.id = id; - } - - @Override - public Long getId() { - return id; - } - } - - @Autowired - public KafkaApiController(KafkaSender kafkaSender) { - this.kafkaSender = kafkaSender; - } - - @ApiOperation(value = "Test backend-api availability.") - @ApiResponses(value = {@ApiResponse(code = 200, message = "OK", response = String.class)}) - @RequestMapping(method = RequestMethod.POST, path = "/any/message", produces = MediaType.TEXT_PLAIN_VALUE) - @ResponseBody - public String processGet(@ApiParam(value = "Параметры команды в JSON формате.", required = true) - @RequestBody AnyKafkaMessageAction bankAccountNewAction) throws ClassNotFoundException, ValidationException, JsonProcessingException { - log.info("Call test method for backend-api controller"); - validate(bankAccountNewAction); - Class parameterType = ClassUtils.forName(bankAccountNewAction.getFullClassName(), ClassUtils.getDefaultClassLoader()); - JavaType requestType = json.getTypeFactory().constructSimpleType(parameterType, null); - Object obj = json.readValue(bankAccountNewAction.getJson(), requestType); - Long idOfBaseRequestMessage = kafkaSender.sendRequestToQueue(bankAccountNewAction.getTopicName(), obj); - log.debug("Test message to topic {} with request id={}", bankAccountNewAction.getTopicName(), idOfBaseRequestMessage); - return "success: baseRequest.id = " + idOfBaseRequestMessage; - } - - private void validate(AnyKafkaMessageAction bankAccountNewAction) throws ValidationException { - if (TextUtil.isEmpty(bankAccountNewAction.getTopicName())) { - throw new ValidationException(new EnumMessage(BackEndError.ValidationError, "topicName")); - } - if (TextUtil.isEmpty(bankAccountNewAction.getFullClassName())) { - throw new ValidationException(new EnumMessage(BackEndError.ValidationError, "fullClassName")); - } - if (TextUtil.isEmpty(bankAccountNewAction.getJson())) { - throw new ValidationException(new EnumMessage(BackEndError.ValidationError, "json")); - } - } - -} +//package ru.spcex.clearing.test.controller.kafka; +// +//import com.fasterxml.jackson.core.JsonProcessingException; +//import com.fasterxml.jackson.databind.JavaType; +//import com.fasterxml.jackson.databind.ObjectMapper; +//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.MediaType; +//import org.springframework.stereotype.Controller; +//import org.springframework.util.ClassUtils; +//import org.springframework.web.bind.annotation.RequestBody; +//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.platform.messaging.service.sender.KafkaSender; +//import ru.spcex.platform.utils.enumeration.EnumMessage; +//import ru.spcex.platform.utils.enumeration.IErrorEnumId; +//import ru.spcex.platform.utils.error.ValidationException; +//import ru.spcex.platform.utils.text.TextUtil; +// +//@Controller +//@RequestMapping("/anonymous/kafka-api") +//public class KafkaApiController { +// private final Logger log = LoggerFactory.getLogger(getClass()); +// private final KafkaSender kafkaSender; +// private static final ObjectMapper json = new ObjectMapper(); +// static { +// } +// +// enum BackEndError implements IErrorEnumId { +// ValidationError(9000L), +// UnknownJsonProperty(9001L), +// FailedToReadHttpMessage(9002L), +// KeycloakRepeatedRoles(9003L), +// DictionaryNotFound(9004L), +// ResourceNotFound(9005L) +// ; +// private final Long id; +// +// BackEndError(Long id) { +// this.id = id; +// } +// +// @Override +// public Long getId() { +// return id; +// } +// } +// +// @Autowired +// public KafkaApiController(KafkaSender kafkaSender) { +// this.kafkaSender = kafkaSender; +// } +// +// @ApiOperation(value = "Test backend-api availability.") +// @ApiResponses(value = {@ApiResponse(code = 200, message = "OK", response = String.class)}) +// @RequestMapping(method = RequestMethod.POST, path = "/any/message", produces = MediaType.TEXT_PLAIN_VALUE) +// @ResponseBody +// public String processGet(@ApiParam(value = "Параметры команды в JSON формате.", required = true) +// @RequestBody AnyKafkaMessageAction bankAccountNewAction) throws ClassNotFoundException, ValidationException, JsonProcessingException { +// log.info("Call test method for backend-api controller"); +// validate(bankAccountNewAction); +// Class parameterType = ClassUtils.forName(bankAccountNewAction.getFullClassName(), ClassUtils.getDefaultClassLoader()); +// JavaType requestType = json.getTypeFactory().constructSimpleType(parameterType, null); +// Object obj = json.readValue(bankAccountNewAction.getJson(), requestType); +// Long idOfBaseRequestMessage = kafkaSender.sendRequestToQueue(bankAccountNewAction.getTopicName(), obj); +// log.debug("Test message to topic {} with request id={}", bankAccountNewAction.getTopicName(), idOfBaseRequestMessage); +// return "success: baseRequest.id = " + idOfBaseRequestMessage; +// } +// +// private void validate(AnyKafkaMessageAction bankAccountNewAction) throws ValidationException { +// if (TextUtil.isEmpty(bankAccountNewAction.getTopicName())) { +// throw new ValidationException(new EnumMessage(BackEndError.ValidationError, "topicName")); +// } +// if (TextUtil.isEmpty(bankAccountNewAction.getFullClassName())) { +// throw new ValidationException(new EnumMessage(BackEndError.ValidationError, "fullClassName")); +// } +// if (TextUtil.isEmpty(bankAccountNewAction.getJson())) { +// throw new ValidationException(new EnumMessage(BackEndError.ValidationError, "json")); +// } +// } +// +//} diff --git a/clearing-parent/test-api-clearing/src/main/resources/application.properties b/clearing-parent/test-api-clearing/src/main/resources/application.properties index 074aaeb9f..6eda6ea43 100644 --- a/clearing-parent/test-api-clearing/src/main/resources/application.properties +++ b/clearing-parent/test-api-clearing/src/main/resources/application.properties @@ -1,14 +1,13 @@ #spring.main.web-application-type=none -test-service.port=8701 -test-service.url=/clearing/test/ - #debug tester mode: -test-service.debug-server.port=8701 -test-service.debug-server.context-path=/imdg/reload +test-service.controller-settings.port=8701 +test-service.controller-settings.context-path=/ -server.port=8070 -server.servlet.context-path=/backend-api-test +# /clearing/test/ /imdg/reload + +#server.port=8701 +#server.servlet.context-path=/ test-service.hazelcast.cluster-members=127.0.0.1:5701 diff --git a/clearing-parent/test-api-clearing/src/main/resources/logback.xml b/clearing-parent/test-api-clearing/src/main/resources/logback.xml index e3e8a4454..c4c3640d0 100644 --- a/clearing-parent/test-api-clearing/src/main/resources/logback.xml +++ b/clearing-parent/test-api-clearing/src/main/resources/logback.xml @@ -8,7 +8,7 @@ - ./logs/utility-service.log + ./logs/test-api-clearing.log %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %class{0}:%msg%n @@ -16,7 +16,7 @@ - ./logs/utility-service.%i.log + ./logs/test-api-clearing.%i.log 1 10 diff --git a/clearing-parent/test-api-clearing/src/main/resources/pages/index.html b/clearing-parent/test-api-clearing/src/main/resources/pages/index.html new file mode 100644 index 000000000..3e506c67b --- /dev/null +++ b/clearing-parent/test-api-clearing/src/main/resources/pages/index.html @@ -0,0 +1,32 @@ + + + + + +
+

Debug control panel

+

Action:

+ +
+

Sending message dialog

+
+ Send Message to queue +
+
+
+ Do +
+
+
+ + +
+ diff --git a/clearing-parent/test-api-clearing/src/main/resources/pages/message.html b/clearing-parent/test-api-clearing/src/main/resources/pages/message.html new file mode 100644 index 000000000..656b9a85d --- /dev/null +++ b/clearing-parent/test-api-clearing/src/main/resources/pages/message.html @@ -0,0 +1,55 @@ + + + + + +
+ +
+

Sending message dialog

+
+
+ + +
+
+ +       + +
+
+ +    + +
+
+ +
+
+
+ +
+ Enter Kafka debug message... +
+ \message> CD .. +
+ +
+ diff --git a/clearing-parent/test-api-clearing/test-api-clearing.sh b/clearing-parent/test-api-clearing/test-api-clearing.sh new file mode 100644 index 000000000..e5db2091a --- /dev/null +++ b/clearing-parent/test-api-clearing/test-api-clearing.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +CLEARING_HOME=/opt/mfd/clearing/ +cd $CLEARING_HOME/bin + +echo Warinig: start test module "test-api-clearing.jar". Do not use this on real system, please. +CMD="java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:7702 -jar test-api-clearing.jar --spring.config.location=$CLEARING_HOME/settings/test-api-clearing/" + +$CMD >/dev/null 2>&1 & +