This commit is contained in:
parent
4f199c3d37
commit
1d33e0cd3b
25 changed files with 870 additions and 30 deletions
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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 {
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
)
|
||||
)
|
||||
);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
imdg.hazelcast.cluster-members[0]=127.0.0.1
|
||||
65
platform-parent/platform-imdg-api-hazelcast-impl/pom.xml
Normal file
65
platform-parent/platform-imdg-api-hazelcast-impl/pom.xml
Normal 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>
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
|
@ -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));
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
22
platform-parent/platform-utils/pom.xml
Normal file
22
platform-parent/platform-utils/pom.xml
Normal 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>
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
@ -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
21
pom.xml
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue