ialbert 2022-08-09 20:53:33 +03:00
parent 4f199c3d37
commit 1d33e0cd3b
25 changed files with 870 additions and 30 deletions

View file

@ -33,6 +33,10 @@
<artifactId>keycloak-spring-boot-starter</artifactId>
<version>${keycloak-spring-boot-starter.version}</version>
</dependency>
<dependency>
<groupId>ru.spcex.platform</groupId>
<artifactId>platform-imdg-api-hazelcast-impl</artifactId>
</dependency>
</dependencies>
<dependencyManagement>

View file

@ -0,0 +1,47 @@
package ru.spcex.clearing.backendapi.config;
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 org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import ru.spcex.platform.imdg.api.ImdgProvider;
import ru.spcex.platform.imdg.iml.hazelcast.service.HazelcastService;
@Configuration
public class BackEndApiImdgConfig {
@Bean(name = "taskExecutorHazelcastClientInitializer")
public ThreadPoolTaskExecutor taskExecutorHazelcastClientInitializer() {
return createThreadPoolTaskExecutor(1, true);
}
@Bean(name = "taskExecutorIdGeneratorAwaiter")
public ThreadPoolTaskExecutor taskExecutorIdGeneratorAwaiter() {
return createThreadPoolTaskExecutor(1, false);
}
@Autowired
@Bean
public ImdgProvider imdgProvider(
@Qualifier("taskExecutorHazelcastClientInitializer") ThreadPoolTaskExecutor taskExecutorHazelcastClientInitializer,
@Qualifier("taskExecutorIdGeneratorAwaiter") ThreadPoolTaskExecutor taskExecutorIdGeneratorAwaiter,
HazelcastSettings clientSetting
) {
return new HazelcastService(taskExecutorHazelcastClientInitializer,
taskExecutorIdGeneratorAwaiter,
clientSetting);
}
private static ThreadPoolTaskExecutor createThreadPoolTaskExecutor(int maxPoolSz, boolean waitForCompletion) {
ThreadPoolTaskExecutor pool = new ThreadPoolTaskExecutor();
if (maxPoolSz > 2) {
pool.setKeepAliveSeconds(60);
pool.setAllowCoreThreadTimeOut(true);
}
pool.setCorePoolSize(maxPoolSz);
pool.setWaitForTasksToCompleteOnShutdown(waitForCompletion);
return pool;
}
}

View file

@ -0,0 +1,12 @@
package ru.spcex.clearing.backendapi.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;
import ru.spcex.platform.imdg.iml.hazelcast.config.HazelcastClientParams;
@Component
@PropertySource("file:${spring.config.location}/application.properties")
@ConfigurationProperties("backend-api.hazelcast")
public class HazelcastSettings extends HazelcastClientParams {
}

View file

@ -3,6 +3,9 @@ server.servlet.context-path=/backend-api
spring.main.web-application-type=servlet
backend-api.example-setting=test
backend-api.hazelcast.cluster-members=127.0.0.1
backend-api.hazelcast.login=dev
backend-api.hazelcast.password=dev-pass
##keycloak

View file

@ -64,10 +64,24 @@
<artifactId>hazelcast-all</artifactId>
<version>${external_libraries.hazelcast.version}</version>
</dependency>
<dependency>
<groupId>ru.spcex.platform</groupId>
<artifactId>platform-imdg-api-hazelcast-impl</artifactId>
</dependency>
</dependencies>
<build>
<finalName>jar/${project.artifactId}</finalName>
<resources>
<resource>
<directory>src/main/resources</directory>
<excludes>
<exclude>application.properties</exclude>
</excludes>
<filtering>false</filtering>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>

View file

@ -12,10 +12,12 @@ public class HazelcastConfiguration {
private ConfigurationRootElement configRoot = DfaConfig.get().getRoot();
private final PoolMapConfigs poolMapConfigs;
private final HazelcastServerElement hzSettings;
@Autowired
public HazelcastConfiguration(PoolMapConfigs poolMapConfigs) {
public HazelcastConfiguration(PoolMapConfigs poolMapConfigs, ImdgSettings imdgSettings) {
this.poolMapConfigs = poolMapConfigs;
this.hzSettings = imdgSettings.getHazelcast();
}
@Bean
@ -37,7 +39,7 @@ public class HazelcastConfiguration {
.setMulticastConfig(new MulticastConfig()
.setEnabled(false))
.setTcpIpConfig(new TcpIpConfig()
.setEnabled(true)
.setEnabled(true).setMembers(hzSettings.getClusterMembers())
)
)
);

View file

@ -0,0 +1,43 @@
package ru.spcex.clearing.imdg.config;
import java.util.List;
public class HazelcastServerElement {
private int listenPort = 5071;
private String login = "dev";
private String password = "dev-pass";
private List<String> clusterMembers;
public int getListenPort() {
return listenPort;
}
public void setListenPort(int listenPort) {
this.listenPort = listenPort;
}
public String getLogin() {
return login;
}
public void setLogin(String login) {
this.login = login;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public List<String> getClusterMembers() {
return clusterMembers;
}
public void setClusterMembers(List<String> clusterMembers) {
this.clusterMembers = clusterMembers;
}
}

View file

@ -0,0 +1,21 @@
package ru.spcex.clearing.imdg.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;
@Component
@PropertySource("file:${spring.config.location}/application.properties")
@ConfigurationProperties("imdg")
public class ImdgSettings {
private HazelcastServerElement hazelcast;
public HazelcastServerElement getHazelcast() {
return hazelcast;
}
public void setHazelcast(HazelcastServerElement hazelcast) {
this.hazelcast = hazelcast;
}
}

View file

@ -15,6 +15,7 @@ import ru.clearing.classes.objects.BusinessObject;
import ru.spcex.clearing.imdg.base.DictionaryMapStore;
import ru.spcex.clearing.imdg.base.SimpleObjectMapStore;
import ru.spcex.clearing.imdg.utils.IMDGDistributedNames;
import ru.spcex.platform.imdg.iml.hazelcast.util.HazelcastHelper;
import java.util.ArrayList;
import java.util.List;
@ -125,7 +126,7 @@ public abstract class AbstractHazelcastLifecycleSupport implements InitializingB
throw new RuntimeException("MapStore multithreaded not complete.", e);
}
// HazelcastCommon.otcSystem_setStorageState(true, hazelcastServerInstance); todo в других модулях может быть проверка на это, и должна быть.
HazelcastHelper.otcSystem_setStorageState(true, hazelcastServerInstance);
// hazelcastServerInstance.getClientService().addClientListener(clientListener);
loadTime = System.currentTimeMillis() - loadTime;
log.info("All map load time {} ms", loadTime);

View file

@ -0,0 +1 @@
imdg.hazelcast.cluster-members[0]=127.0.0.1

View file

@ -0,0 +1,65 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>platform-parent</artifactId>
<groupId>ru.spcex.platform</groupId>
<version>1.0.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>platform-imdg-api-hazelcast-impl</artifactId>
<version>1.0.0</version>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>ru.spcex.platform</groupId>
<artifactId>platform-imdg-api</artifactId>
</dependency>
<dependency>
<groupId>ru.spcex.platform</groupId>
<artifactId>platform-utils</artifactId>
</dependency>
<dependency>
<groupId>com.hazelcast</groupId>
<artifactId>hazelcast-all</artifactId>
<version>${external_libraries.hazelcast.version}</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${external_libraries.logback.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>${external_libraries.logback.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${external_libraries.slf4j.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
</project>

View file

@ -0,0 +1,19 @@
package ru.spcex.platform.imdg.iml.hazelcast.adapter;
import com.hazelcast.core.IMap;
import ru.spcex.platform.classes.base.SpcexObjectBase;
import ru.spcex.platform.imdg.api.Imdg;
public class ImdgHazelcast<T extends SpcexObjectBase> implements Imdg<T> {
private IMap<Long, T> map;
public IMap<Long, T> getMap() {
return map;
}
public void setMap(IMap<Long, T> map) {
this.map = map;
}
//todo implement methods
}

View file

@ -0,0 +1,60 @@
package ru.spcex.platform.imdg.iml.hazelcast.config;
import com.hazelcast.config.NearCacheConfig;
@SuppressWarnings({"FieldCanBeLocal", "unused"})
public class HazelcastClientParams {
public HazelcastClientParams() {
}
private String clusterMembers;
private String login;
private String password;
private String instanceName;
private NearCacheConfig nearCacheConfig;
public String getClusterMembers() {
return clusterMembers;
}
public void setClusterMembers(String clusterMembers) {
this.clusterMembers = clusterMembers;
}
public String getLogin() {
return login;
}
public void setLogin(String login) {
this.login = login;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getInstanceName() {
return instanceName;
}
public void setInstanceName(String instanceName) {
this.instanceName = instanceName;
}
public NearCacheConfig getNearCacheConfig() {
return nearCacheConfig;
}
public void setNearCacheConfig(NearCacheConfig nearCacheConfig) {
this.nearCacheConfig = nearCacheConfig;
}
}

View file

@ -0,0 +1,37 @@
package ru.spcex.platform.imdg.iml.hazelcast.service;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import ru.spcex.platform.imdg.iml.hazelcast.config.HazelcastClientParams;
public final class HazelcastService extends HazelcastServiceBase implements InitializingBean, DisposableBean {
public HazelcastService(ThreadPoolTaskExecutor taskExecutorHazelcastClientInitializer,
ThreadPoolTaskExecutor taskExecutorIdGeneratorAwaiter,
HazelcastClientParams hazelcastClientParams) {
super(taskExecutorHazelcastClientInitializer, taskExecutorIdGeneratorAwaiter, hazelcastClientParams);
}
public void init() {
taskExecutorHazelcastClientInitializer.submit(this::reinitializeHazelcastClient);
}
@Scheduled(cron = "* 0 0 * * *")
@Override
protected void reloadClient() {
super.reloadClient();
}
@Override
public void destroy() {
shutdown();
}
@Override
public void afterPropertiesSet() throws Exception {
init();
}
}

View file

@ -0,0 +1,259 @@
package ru.spcex.platform.imdg.iml.hazelcast.service;
import com.hazelcast.client.HazelcastClient;
import com.hazelcast.client.config.ClientConfig;
import com.hazelcast.core.HazelcastInstance;
import com.hazelcast.core.LifecycleEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.env.Environment;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
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.iml.hazelcast.adapter.ImdgHazelcast;
import ru.spcex.platform.imdg.iml.hazelcast.config.HazelcastClientParams;
import ru.spcex.platform.imdg.iml.hazelcast.util.HazelcastHelper;
import ru.spcex.platform.utils.log.ExceptionUtils;
import java.util.*;
public abstract class HazelcastServiceBase
// implements IHazelcastService
implements ImdgProvider
{
protected final Logger log = LoggerFactory.getLogger(this.getClass());
public final int SLEEP_AFTER_RELOAD_MS = 5000;
protected String mapNameForCache;
protected final ThreadPoolTaskExecutor taskExecutorHazelcastClientInitializer;
protected final ThreadPoolTaskExecutor taskExecutorIdGeneratorAwaiter;
protected final HazelcastClientParams settingsElementHazelcastClient;
protected final Collection<IHazelcastClusterStatus> hazelcastStatusSubscribers = new ArrayList<>();
protected HazelcastInstance hazelcastInstance;
protected volatile boolean isAvailableNow;
private Environment environment;
public HazelcastServiceBase(
ThreadPoolTaskExecutor taskExecutorHazelcastClientInitializer,
ThreadPoolTaskExecutor taskExecutorIdGeneratorAwaiter,
HazelcastClientParams settingsElementHazelcastClient,
Environment environment) {
this.taskExecutorIdGeneratorAwaiter = taskExecutorIdGeneratorAwaiter;
this.taskExecutorHazelcastClientInitializer = taskExecutorHazelcastClientInitializer;
this.settingsElementHazelcastClient = settingsElementHazelcastClient;
this.environment = environment;
}
public HazelcastServiceBase(
ThreadPoolTaskExecutor taskExecutorHazelcastClientInitializer,
ThreadPoolTaskExecutor taskExecutorIdGeneratorAwaiter,
HazelcastClientParams settingsElementHazelcastClient) {
this.taskExecutorIdGeneratorAwaiter = taskExecutorIdGeneratorAwaiter;
this.taskExecutorHazelcastClientInitializer = taskExecutorHazelcastClientInitializer;
this.settingsElementHazelcastClient = settingsElementHazelcastClient;
}
private void createHazelcastClient() {
if (hazelcastInstance != null) {
try {
hazelcastInstance.shutdown();
} catch (Throwable ignored) {
}
}
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");
}
// @Override
public void reinitializeHazelcastClient() {
try {
createHazelcastClient();
Thread.sleep(100); // await for skip CLIENT_CONNECTED event. See warn "Hazelcast already available, but has call onAvailable() again."
awaitGeneratorId();
hazelcastInstance.getLifecycleService().addLifecycleListener((LifecycleEvent event) -> {
switch (event.getState()) {
case CLIENT_CONNECTED:
log.info("Hazelcast: event connected");
awaitGeneratorId();
break;
case CLIENT_DISCONNECTED:
log.info("Hazelcast: event disconnected");
onUnavailable();
break;
}
});
} catch (Throwable e) {
log.error("reinitializeHazelcastClient() has error: {}", ExceptionUtils.getStackTrace(e));
}
}
protected void onAvailable() {
if (isAvailableNow) {
log.warn("Hazelcast already available, but has call onAvailable() again. Ignore.");
return; // пропустить
}
isAvailableNow = false;
synchronized (hazelcastStatusSubscribers) {
hazelcastStatusSubscribers.forEach(hazelcastStatusSubscriber -> {
log.trace("hazelcastStatusSubscribers call> {}", hazelcastStatusSubscriber);
try {
hazelcastStatusSubscriber.getAvailable(hazelcastInstance);
} catch (Throwable e) {
log.warn(ExceptionUtils.getStackTrace(e));
}
});
isAvailableNow = true;
}
}
protected void onUnavailable() {
if (!isAvailableNow)
log.warn("Hazelcast already unavailable, but has call onUnavailable() again.");
isAvailableNow = false;
synchronized (hazelcastStatusSubscribers) {
hazelcastStatusSubscribers.forEach(hazelcastStatusSubscriber -> {
log.trace("hazelcastStatusSubscribers call unavailable> {}", hazelcastStatusSubscriber);
try {
hazelcastStatusSubscriber.getUnavailable(hazelcastInstance);
} catch (Throwable e) {
log.warn(ExceptionUtils.getStackTrace(e));
}
});
if (isAvailableNow) { // never: если успел проскочить между isAvailableNow = false и synchronized
log.warn("Concurrent call onAvailable() and onUnavailable(). Stacktrace: {}", ExceptionUtils.getStackTrace(new ConcurrentModificationException("Warning")));
isAvailableNow = false;
}
}
}
protected void reloadClient() {
String logMsg = "Reloading Hazelcast client:";
Date dtStart = new Date();
try {
onUnavailable();
Thread.sleep(SLEEP_AFTER_RELOAD_MS);
reinitializeHazelcastClient();
logMsg = String.format("%s done OK! (duration=%dms)",
logMsg, (new Date()).getTime() - dtStart.getTime());
} catch (Throwable e) {
logMsg = String.format("%s error (duration=%dms):\n%s",
logMsg, (new Date()).getTime() - dtStart.getTime(), ExceptionUtils.getStackTrace(e));
} finally {
log.info(logMsg);
}
}
protected void awaitGeneratorId() {
taskExecutorIdGeneratorAwaiter.execute(() -> {
try {
// ожидание инициализации Storage (только после инициализации IDGenerator начинать работу).
boolean done = false;
while (!done) {
log.debug("Execute awaitGeneratorId()");
try {
HazelcastHelper.otcSystem_waitTillReadyState(getHazelcast());
onAvailable();
done = true;
} catch (Throwable e) {
log.info(String.format("Waiting Hazelcast: %s -> %s", e.getClass().getSimpleName(), e.getMessage()));
createHazelcastClient();
try {
Thread.sleep(100);
} catch (InterruptedException ignored) {
log.warn("awaitGeneratorId thread interrupted!");
Thread.currentThread().interrupt();
return;
}
}
}
// проверка версии классов
// HazelcastCommon.verifyVersionClientsClasses(hazelcastInstance);
} catch (Throwable e) {
log.error("Error at awaitGeneratorId(): {}", ExceptionUtils.getStackTrace(e));
}
});
}
// @Override
public void statusSubscribe(IHazelcastClusterStatus clusterStatus) {
log.trace("hazelcastStatusSubscribers add> {}", clusterStatus);
synchronized (hazelcastStatusSubscribers) {
if (hazelcastStatusSubscribers.contains(clusterStatus)) // never
throw new IllegalStateException("ClusterStatus listener " + clusterStatus + " already added!");
hazelcastStatusSubscribers.add(clusterStatus);
if (isAvailableNow) { // register now
log.trace("hazelcastStatusSubscribers added and call now> {}", clusterStatus);
try {
clusterStatus.getAvailable(hazelcastInstance);
} catch (Throwable e) {
log.warn(ExceptionUtils.getStackTrace(e));
}
}
}
}
// @Override
public HazelcastInstance getHazelcast() {
return hazelcastInstance;
}
@Override
public <T extends SpcexObjectBase> Imdg<T> getImdg(String key, Class<T> clazz) {
ImdgHazelcast<T> imdg = new ImdgHazelcast<>();
imdg.setMap(getHazelcast().getMap(key));
return imdg;
}
// @Override
public void waitTillReadyState() throws InterruptedException {
boolean done = false;
int sleepCount = 0;
while (!done) {
try {
HazelcastInstance instance = getHazelcast();
if (instance != null) {
HazelcastHelper.otcSystem_waitTillReadyState(instance);
done = true;
break;
} else {
if (sleepCount++ % 30 == 0)
log.debug("Hazelcast not connected. Wait till STORAGE be ready...");
}
} catch (InterruptedException e) {
log.warn(String.format("Waiting Hazelcast interrupted: %s -> %s", e.getClass().getSimpleName(), e.getMessage()));
throw e;
}
Thread.sleep(100);
}
}
// @Override
public void shutdown() {
isAvailableNow = false;
if (hazelcastInstance != null)
hazelcastInstance.shutdown();
}
public String getMapNameForCache() {
return mapNameForCache;
}
public void setMapNameForCache(String mapNameForCache) {
this.mapNameForCache = mapNameForCache;
}
}

View file

@ -0,0 +1,10 @@
package ru.spcex.platform.imdg.iml.hazelcast.service;
import com.hazelcast.core.HazelcastInstance;
public interface IHazelcastClusterStatus {
void getAvailable(HazelcastInstance hazelcastNotInited);
void getUnavailable(HazelcastInstance hazelcastNotInited);
}

View file

@ -0,0 +1,130 @@
package ru.spcex.platform.imdg.iml.hazelcast.util;
import com.hazelcast.client.HazelcastClient;
import com.hazelcast.client.config.ClientConfig;
import com.hazelcast.client.config.ClientNetworkConfig;
import com.hazelcast.config.NearCacheConfig;
import com.hazelcast.core.HazelcastException;
import com.hazelcast.core.HazelcastInstance;
import com.hazelcast.core.IMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public final class HazelcastHelper {
private static final Logger log = LoggerFactory.getLogger(HazelcastHelper.class);
public static final int DEFAULT_CONNECTION_TIMEOUT_SEC = 30;
public static final int DEFAULT_CONNECTION_ATTEMPT_PERIOD_SEC = 10;
public static final int DEFAULT_CONNECTION_ATTEMPT_LIMIT = Integer.MAX_VALUE;
public static final int TEST_CONNECTION_ATTEMPT_LIMIT = 1;
public static final String OTC_SYSTEM_MAP = "OTC_SYSTEM";
public static ClientConfig getClientConfig(String members, String login, String password, String instanceName) {
return getClientConfig(members, login, password, instanceName, null);
}
public static ClientConfig getClientConfig(String members, String login, String password, String instanceName, NearCacheConfig nearCacheConfig) {
if (members == null) {
throw new IllegalArgumentException("members must not be null!");
}
String[] mm = members.split(",");
if (mm.length == 0) {
throw new IllegalArgumentException("members must not be empty!");
}
ClientNetworkConfig clientNetworkConfig = new ClientNetworkConfig();
for (String m : mm) {
if (m != null && !m.isEmpty()) {
clientNetworkConfig.addAddress(m);
}
}
ClientConfig config = new ClientConfig();
config.setInstanceName(instanceName);
config.setNetworkConfig(clientNetworkConfig);
config.setProperty("hazelcast.logging.type", "slf4j");
config.getGroupConfig().setName(login);
config.getGroupConfig().setPassword(password);
config.getNetworkConfig().setConnectionTimeout(DEFAULT_CONNECTION_TIMEOUT_SEC * 1000);
config.getNetworkConfig().setConnectionAttemptPeriod(DEFAULT_CONNECTION_ATTEMPT_PERIOD_SEC * 1000);
config.getNetworkConfig().setConnectionAttemptLimit(DEFAULT_CONNECTION_ATTEMPT_LIMIT);
if (nearCacheConfig != null) config.addNearCacheConfig(nearCacheConfig);
return config;
}
/**
* Создаёт клиента HazelcastInstance, подключённого по настрйокам ClientConfig.
* Ожидает готовности Storage, инициализирует TextErrorService.
* В случае ошибок делает повторение попыток создания клиента.
* <p>
* Пример получения ClientConfig:
* <code>
* HazelcastHelper.getClientConfig(
* Config.get().getHazelcastSettings().getClusterMembers(),
* Config.get().getHazelcastSettings().getLogin(),
* Config.get().getHazelcastSettings().getPassword()
* )
* </code>
*
* @param hzClientConfig
* @return HazelcastClient
*/
public HazelcastInstance makeHazelcastClientAndWaitTillReady(ClientConfig hzClientConfig) {
HazelcastInstance instance = null;
// ожидание инициализации Storage (только после инициализации IDGenerator начинать работу).
boolean done = false;
while (!done) {
try {
instance = HazelcastClient.newHazelcastClient(hzClientConfig);// createHzClient();
otcSystem_waitTillReadyState(instance);
// TextErrorService.setHazelcast(instance);
log.info("Hazelcast: TextErrorService done");
done = true;
} catch (InterruptedException e) {
throw new RuntimeException("Thread interrupted when waiting storage ready.", e);
} catch (Exception e) {
log.info(String.format("Waiting Hazelcast: %s -> %s", e.getClass().getSimpleName(), e.getMessage()));
try {
Thread.sleep(100);
} catch (InterruptedException ignored) {
throw new RuntimeException("Thread interrupted.", e);
}
}
}
// проверка версии классов
// HazelcastCommon.verifyVersionClientsClasses(instance);
return instance;
}
public static void otcSystem_waitTillReadyState(HazelcastInstance hazelcast) throws InterruptedException {
int sleepCount = 0;
try {
while (!otcSystem_getStorageState(hazelcast)) {
if (sleepCount++ % 30 == 0)
log.info("Wait till STORAGE be ready...");
Thread.sleep(100);
}
} catch (HazelcastException hcEx) {
// проброс InterruptException из Hazelcast
if (hcEx instanceof HazelcastException && hcEx.getCause() instanceof InterruptedException)
throw new InterruptedException("Can not obtain storage for check state, cause has interrupted. " + hcEx);
throw hcEx;
}
}
public static boolean otcSystem_getStorageState(HazelcastInstance hazelcast) {
IMap<String, String> systemMap = hazelcast.getMap(OTC_SYSTEM_MAP);
return Boolean.valueOf(systemMap.get("STORAGE.STATE"));
}
public static void otcSystem_setStorageState(boolean val, HazelcastInstance hazelcast) {
IMap<String, String> systemMap = hazelcast.getMap(OTC_SYSTEM_MAP);
systemMap.set("STORAGE.STATE", Boolean.toString(val));
}
}

View file

@ -0,0 +1,47 @@
package ru.spcex.platform.imdg.api;
import ru.spcex.platform.classes.base.SpcexObjectBase;
import java.util.Collection;
public interface Imdg<T extends SpcexObjectBase> {
default void insert(T paramT) {
throw new UnsupportedOperationException("not implemented insert");
}
default void update(T paramT) {
throw new UnsupportedOperationException("not implemented update");
}
default void delete(T paramT) {
throw new UnsupportedOperationException("not implemented delete");
}
default Long nextIDSequenceFor() {
throw new UnsupportedOperationException("not implemented nextIDSequenceFor");
}
default Collection<T> getCollectionObjectsBySQL(String paramString) {
throw new UnsupportedOperationException("not implemented getCollectionObjectsBySQL");
}
default T getSingleObjectBySQL(String paramString) {
throw new UnsupportedOperationException("not implemented getSingleObjectBySQL");
}
default T getSingleObjectByID(Long paramLong) {
throw new UnsupportedOperationException("not implemented getSingleObjectByID");
}
default Collection<Long> getCollectionIdsBySQL(String paramString) {
throw new UnsupportedOperationException("not implemented getCollectionIdsBySQL");
}
default Collection<T> getAllValues() {
throw new UnsupportedOperationException("not implemented getAllValues");
}
default <A> Collection<A> projectionsAttributeBySql(String paramString, String... paramVarArgs) {
throw new UnsupportedOperationException("not implemented projectionsAttributeBySql");
}
}

View file

@ -0,0 +1,11 @@
package ru.spcex.platform.imdg.api;
import ru.spcex.platform.classes.base.SpcexObjectBase;
public interface ImdgProvider {
/**
* пока простой интерфейс для получения доступа к мапам
*/
public <T extends SpcexObjectBase> Imdg<T> getImdg(String key, Class<T> clazz);
}

View file

@ -1,27 +0,0 @@
package ru.spcex.platform.imdg.api;
import ru.spcex.platform.classes.base.SpcexObjectBase;
import java.util.Collection;
public interface Storage {
<T extends SpcexObjectBase> void insert(Class<T> paramClass, T paramT);
<T extends SpcexObjectBase> void update(Class<T> paramClass, T paramT);
<T extends SpcexObjectBase> void delete(Class<T> paramClass, T paramT);
Long nextIDSequenceFor();
<T> Collection<T> getCollectionObjectsBySQL(Class<T> paramClass, String paramString);
<T> T getSingleObjectBySQL(Class<T> paramClass, String paramString);
<T> T getSingleObjectByID(Class<T> paramClass, Long paramLong);
<T> Collection<Long> getCollectionIdsBySQL(Class<T> paramClass, String paramString);
<T> Collection<T> getAllValues(Class<T> paramClass);
<T, A> Collection<A> projectionsAttributeBySql(Class<T> paramClass, String paramString, String... paramVarArgs);
}

View file

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>platform-utils</artifactId>
<name>Platform utilities</name>
<packaging>jar</packaging>
<version>1.0.0</version>
<parent>
<artifactId>platform-parent</artifactId>
<groupId>ru.spcex.platform</groupId>
<version>1.0.0</version>
</parent>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
</properties>
</project>

View file

@ -0,0 +1,13 @@
package ru.spcex.platform.utils.log;
import java.io.PrintWriter;
import java.io.StringWriter;
public class ExceptionUtils {
public static String getStackTrace(Throwable throwable) {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw, true);
throwable.printStackTrace(pw);
return sw.getBuffer().toString();
}
}

View file

@ -20,5 +20,7 @@
<modules>
<module>platform-imdg-api</module>
<module>platform-classes-base</module>
<module>platform-imdg-api-hazelcast-impl</module>
<module>platform-utils</module>
</modules>
</project>

21
pom.xml
View file

@ -31,10 +31,13 @@
<!--suppress UnresolvedMavenProperty -->
<folder_root_clearing>${folder_root_clearing_temp}</folder_root_clearing>
<folder_root_clearing_backend-api>${folder_root_clearing}/clearing-parent/backend-api</folder_root_clearing_backend-api>
<folder_root_clearing_imdg>${folder_root_clearing}/clearing-parent/imdg</folder_root_clearing_imdg>
<folder_root_dbf-exporter>${folder_root_clearing}/clearing-parent/dbf-exporter</folder_root_dbf-exporter>
<folder_root_dbf-importer>${folder_root_clearing}/clearing-parent/dbf-importer</folder_root_dbf-importer>
<!-- IMDG -->
<external_libraries.hazelcast.version>3.12.4</external_libraries.hazelcast.version>
<external_libraries.slf4j.version>1.7.33</external_libraries.slf4j.version>
<external_libraries.logback.version>1.2.10</external_libraries.logback.version>
</properties>
<dependencyManagement>
@ -52,6 +55,11 @@
<artifactId>backend-api</artifactId>
<version>${global.project.version}</version>
</dependency>
<dependency>
<groupId>ru.spcex.clearing</groupId>
<artifactId>imdg</artifactId>
<version>${global.project.version}</version>
</dependency>
<dependency>
<groupId>ru.spcex.clearing</groupId>
<artifactId>classes</artifactId>
@ -73,6 +81,19 @@
<artifactId>platform-classes-base</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>ru.spcex.platform</groupId>
<artifactId>platform-imdg-api-hazelcast-impl</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>ru.spcex.platform</groupId>
<artifactId>platform-utils</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>ru.spcex.platform</groupId>
<artifactId>platform-imdg-api</artifactId>

View file

@ -23,6 +23,10 @@
<groupId>ru.spcex.clearing</groupId>
<artifactId>backend-api</artifactId>
</dependency>
<dependency>
<groupId>ru.spcex.clearing</groupId>
<artifactId>imdg</artifactId>
</dependency>
</dependencies>
<profiles>
@ -106,6 +110,25 @@
</fileSets>
</configuration>
</execution>
<execution>
<id>copy-imdg-bin</id>
<phase>prepare-package</phase>
<goals>
<goal>copy</goal>
</goals>
<configuration>
<fileSets>
<fileSet>
<sourceFile>${folder_root_clearing_imdg}/target/jar/imdg-exec.jar</sourceFile>
<destinationFile>${folder.clearing.distr.modules}/imdg/imdg-exec.jar</destinationFile>
</fileSet>
<fileSet>
<sourceFile>${folder_root_clearing_imdg}/src/main/resources/application.properties</sourceFile>
<destinationFile>${folder.clearing.distr.modules}/imdg/application.properties</destinationFile>
</fileSet>
</fileSets>
</configuration>
</execution>
<execution>
<id>copy-dbf-exporter-bin</id>