Skip to content

Commit

Permalink
Enabled ClientStateListener to be used on FailoverClient
Browse files Browse the repository at this point in the history
Due to nature of how failover client works, we don't allow different
listeners to be registered at different client configs.

Since ClientStateListener registers itself to the ClientConfig,
this prevents it to be used via FailoverClient.

The reasoning behind constructor register itself is to force the
user to use this via config rather than registering it after client
starts.

So, sticking with the same decision we introduce another constructor
which accepts ClientFailoverConfig and registers same listener(itself)
to all the client configs.

Also on the ClientStateListener I have ignored CLIENT_CHANGED_CLUSTER.
This is rather a temporal event. We fire CLIENT_CONNECTED than
CLIENT_CHANGED_CLUSTER, in those cases we want the current state to
remain CLIENT_CONNECTED.

Fixes #18351

EE PR: hazelcast/hazelcast-enterprise#4142
  • Loading branch information
sancar committed Jul 16, 2021
1 parent 78f9033 commit e5fbd7b
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 35 deletions.
Expand Up @@ -120,82 +120,82 @@ private static boolean notEqual(Object l, Object r) {
@SuppressWarnings({"checkstyle:cyclomaticcomplexity", "checkstyle:npathcomplexity", "checkstyle:methodlength"})
private static void checkValidAlternative(ClientConfig mainConfig, ClientConfig alternativeConfig) {
String mainClusterName = mainConfig.getClusterName();
String alterNativeClusterName = alternativeConfig.getClusterName();
String alternativeClusterName = alternativeConfig.getClusterName();

checkValidAlternativeForNetwork(mainConfig, alternativeConfig);

if (notEqual(mainConfig.getProperties(), alternativeConfig.getProperties())) {
throwInvalidConfigurationException(mainClusterName, alterNativeClusterName, "properties");
throwInvalidConfigurationException(mainClusterName, alternativeClusterName, "properties");
}
if (notEqual(mainConfig.getLoadBalancer(), alternativeConfig.getLoadBalancer())) {
throwInvalidConfigurationException(mainClusterName, alterNativeClusterName, "loadBalancer");
throwInvalidConfigurationException(mainClusterName, alternativeClusterName, "loadBalancer");
}
if (notEqual(mainConfig.getLoadBalancerClassName(), alternativeConfig.getLoadBalancerClassName())) {
throwInvalidConfigurationException(mainClusterName, alterNativeClusterName, "loadBalancerClassName");
throwInvalidConfigurationException(mainClusterName, alternativeClusterName, "loadBalancerClassName");
}
if (notEqual(mainConfig.getListenerConfigs(), alternativeConfig.getListenerConfigs())) {
throwInvalidConfigurationException(mainClusterName, alterNativeClusterName, "listeners");
throwInvalidConfigurationException(mainClusterName, alternativeClusterName, "listeners");
}
if (notEqual(mainConfig.getInstanceName(), alternativeConfig.getInstanceName())) {
throwInvalidConfigurationException(mainClusterName, alterNativeClusterName, "instanceName");
throwInvalidConfigurationException(mainClusterName, alternativeClusterName, "instanceName");
}
if (notEqual(mainConfig.getConfigPatternMatcher(), alternativeConfig.getConfigPatternMatcher())) {
throwInvalidConfigurationException(mainClusterName, alterNativeClusterName, "configPatternMatcher");
throwInvalidConfigurationException(mainClusterName, alternativeClusterName, "configPatternMatcher");
}
if (notEqual(mainConfig.getNearCacheConfigMap(), alternativeConfig.getNearCacheConfigMap())) {
throwInvalidConfigurationException(mainClusterName, alterNativeClusterName, "nearCache");
throwInvalidConfigurationException(mainClusterName, alternativeClusterName, "nearCache");
}
if (notEqual(mainConfig.getReliableTopicConfigMap(), alternativeConfig.getReliableTopicConfigMap())) {
throwInvalidConfigurationException(mainClusterName, alterNativeClusterName, "reliableTopic");
throwInvalidConfigurationException(mainClusterName, alternativeClusterName, "reliableTopic");
}
if (notEqual(mainConfig.getQueryCacheConfigs(), alternativeConfig.getQueryCacheConfigs())) {
throwInvalidConfigurationException(mainClusterName, alterNativeClusterName, "queryCacheConfigs");
throwInvalidConfigurationException(mainClusterName, alternativeClusterName, "queryCacheConfigs");
}
if (notEqual(mainConfig.getSerializationConfig(), alternativeConfig.getSerializationConfig())) {
throwInvalidConfigurationException(mainClusterName, alterNativeClusterName, "serializationConfig");
throwInvalidConfigurationException(mainClusterName, alternativeClusterName, "serializationConfig");
}
if (notEqual(mainConfig.getNativeMemoryConfig(), alternativeConfig.getNativeMemoryConfig())) {
throwInvalidConfigurationException(mainClusterName, alterNativeClusterName, "nativeMemory");
throwInvalidConfigurationException(mainClusterName, alternativeClusterName, "nativeMemory");
}
if (notEqual(mainConfig.getProxyFactoryConfigs(), alternativeConfig.getProxyFactoryConfigs())) {
throwInvalidConfigurationException(mainClusterName, alterNativeClusterName, "proxyFactory");
throwInvalidConfigurationException(mainClusterName, alternativeClusterName, "proxyFactory");
}
if (notEqual(mainConfig.getManagedContext(), alternativeConfig.getManagedContext())) {
throwInvalidConfigurationException(mainClusterName, alterNativeClusterName, "managedContext");
throwInvalidConfigurationException(mainClusterName, alternativeClusterName, "managedContext");
}
if (notEqual(mainConfig.getClassLoader(), alternativeConfig.getClassLoader())) {
throwInvalidConfigurationException(mainClusterName, alterNativeClusterName, "classLoader");
throwInvalidConfigurationException(mainClusterName, alternativeClusterName, "classLoader");
}
if (notEqual(mainConfig.getConnectionStrategyConfig(), alternativeConfig.getConnectionStrategyConfig())) {
throwInvalidConfigurationException(mainClusterName, alterNativeClusterName, "connectionStrategy");
throwInvalidConfigurationException(mainClusterName, alternativeClusterName, "connectionStrategy");
}
if (notEqual(mainConfig.getUserCodeDeploymentConfig(), alternativeConfig.getUserCodeDeploymentConfig())) {
throwInvalidConfigurationException(mainClusterName, alterNativeClusterName, "userCodeDeployment");
throwInvalidConfigurationException(mainClusterName, alternativeClusterName, "userCodeDeployment");
}
if (notEqual(mainConfig.getFlakeIdGeneratorConfigMap(), alternativeConfig.getFlakeIdGeneratorConfigMap())) {
throwInvalidConfigurationException(mainClusterName, alterNativeClusterName, "flakeIdGenerator");
throwInvalidConfigurationException(mainClusterName, alternativeClusterName, "flakeIdGenerator");
}
if (notEqual(mainConfig.getLabels(), alternativeConfig.getLabels())) {
throwInvalidConfigurationException(mainClusterName, alterNativeClusterName, "labels");
throwInvalidConfigurationException(mainClusterName, alternativeClusterName, "labels");
}
if (notEqual(mainConfig.getUserContext(), alternativeConfig.getUserContext())) {
throwInvalidConfigurationException(mainClusterName, alterNativeClusterName, "userContext");
throwInvalidConfigurationException(mainClusterName, alternativeClusterName, "userContext");
}
if (notEqual(mainConfig.getMetricsConfig(), alternativeConfig.getMetricsConfig())) {
throwInvalidConfigurationException(mainClusterName, alterNativeClusterName, "metricsConfig");
throwInvalidConfigurationException(mainClusterName, alternativeClusterName, "metricsConfig");
}
if (notEqual(mainConfig.getInstanceTrackingConfig(), alternativeConfig.getInstanceTrackingConfig())) {
throwInvalidConfigurationException(mainClusterName, alterNativeClusterName, "instanceTrackingConfig");
throwInvalidConfigurationException(mainClusterName, alternativeClusterName, "instanceTrackingConfig");
}
if (mainConfig.isBackupAckToClientEnabled() != alternativeConfig.isBackupAckToClientEnabled()) {
throwInvalidConfigurationException(mainClusterName, alterNativeClusterName, "isBackupAckToClientEnabled");
throwInvalidConfigurationException(mainClusterName, alternativeClusterName, "isBackupAckToClientEnabled");
}
}

@SuppressWarnings({"checkstyle:cyclomaticcomplexity", "checkstyle:npathcomplexity", "checkstyle:methodlength"})
private static void checkValidAlternativeForNetwork(ClientConfig mainConfig, ClientConfig alternativeConfig) {
String mainClusterName = mainConfig.getClusterName();
String alterNativeClusterName = alternativeConfig.getClusterName();
String alternativeClusterName = alternativeConfig.getClusterName();

ClientNetworkConfig mainNetworkConfig = mainConfig.getNetworkConfig();
ClientNetworkConfig alternativeNetworkConfig = alternativeConfig.getNetworkConfig();
Expand All @@ -205,29 +205,29 @@ private static void checkValidAlternativeForNetwork(ClientConfig mainConfig, Cli
}

if (mainNetworkConfig == null || alternativeNetworkConfig == null) {
throwInvalidConfigurationException(mainClusterName, alterNativeClusterName, "network");
throwInvalidConfigurationException(mainClusterName, alternativeClusterName, "network");
}

if (mainNetworkConfig.isSmartRouting() != alternativeNetworkConfig.isSmartRouting()) {
throwInvalidConfigurationException(mainClusterName, alterNativeClusterName, "network:smartRouting");
throwInvalidConfigurationException(mainClusterName, alternativeClusterName, "network:smartRouting");
}
if (mainNetworkConfig.isRedoOperation() != alternativeNetworkConfig.isRedoOperation()) {
throwInvalidConfigurationException(mainClusterName, alterNativeClusterName, "network:redoOperation");
throwInvalidConfigurationException(mainClusterName, alternativeClusterName, "network:redoOperation");
}
if (mainNetworkConfig.getConnectionTimeout() != alternativeNetworkConfig.getConnectionTimeout()) {
throwInvalidConfigurationException(mainClusterName, alterNativeClusterName, "network:connectionTimeout");
throwInvalidConfigurationException(mainClusterName, alternativeClusterName, "network:connectionTimeout");
}
if (notEqual(mainNetworkConfig.getSocketOptions(), alternativeNetworkConfig.getSocketOptions())) {
throwInvalidConfigurationException(mainClusterName, alterNativeClusterName, "network:socketOptions");
throwInvalidConfigurationException(mainClusterName, alternativeClusterName, "network:socketOptions");
}
if (notEqual(mainNetworkConfig.getOutboundPortDefinitions(), alternativeNetworkConfig.getOutboundPortDefinitions())) {
throwInvalidConfigurationException(mainClusterName, alterNativeClusterName, "network:outboundPortDefinitions");
throwInvalidConfigurationException(mainClusterName, alternativeClusterName, "network:outboundPortDefinitions");
}
if (notEqual(mainNetworkConfig.getOutboundPorts(), alternativeNetworkConfig.getOutboundPorts())) {
throwInvalidConfigurationException(mainClusterName, alterNativeClusterName, "network:outboundPorts");
throwInvalidConfigurationException(mainClusterName, alternativeClusterName, "network:outboundPorts");
}
if (notEqual(mainNetworkConfig.getClientIcmpPingConfig(), alternativeNetworkConfig.getClientIcmpPingConfig())) {
throwInvalidConfigurationException(mainClusterName, alterNativeClusterName, "network:clientIcmp");
throwInvalidConfigurationException(mainClusterName, alternativeClusterName, "network:clientIcmp");
}
}
}
Expand Up @@ -17,15 +17,19 @@
package com.hazelcast.client.util;

import com.hazelcast.client.config.ClientConfig;
import com.hazelcast.client.config.ClientFailoverConfig;
import com.hazelcast.config.ListenerConfig;
import com.hazelcast.core.LifecycleEvent;
import com.hazelcast.core.LifecycleListener;

import javax.annotation.Nonnull;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import static com.hazelcast.core.LifecycleEvent.LifecycleState.CLIENT_CHANGED_CLUSTER;
import static com.hazelcast.core.LifecycleEvent.LifecycleState.CLIENT_CONNECTED;
import static com.hazelcast.core.LifecycleEvent.LifecycleState.CLIENT_DISCONNECTED;
import static com.hazelcast.core.LifecycleEvent.LifecycleState.SHUTDOWN;
Expand All @@ -41,27 +45,59 @@
* will not be useful. It is the user's responsibility to instantiate the client with the same
* ClientConfig which was used to instantiate this helper.
*/
public class ClientStateListener
implements LifecycleListener {
public class ClientStateListener implements LifecycleListener {
private LifecycleEvent.LifecycleState currentState = STARTING;

private final Lock lock = new ReentrantLock();
private final Condition connectedCondition = lock.newCondition();
private final Condition disconnectedCondition = lock.newCondition();

/**
* Registers this instance with the provided client configuration
* <p>
* This constructor is introduced to let ClientStateListener to be used via
* {@link com.hazelcast.client.HazelcastClient#newHazelcastFailoverClient(ClientFailoverConfig)}
* <p>
* Listeners used in the different client configs registered to single {@link ClientFailoverConfig} should be
* same. It can be achieved using this constructor while the other constructor
* {@link ClientStateListener#ClientStateListener(ClientConfig)} does not allow that usage.
* <p>
* Note that ClientStateListener should be created after all the alternative client configs are added to the
* client failoverConfig.
* Example usage:
* <pre>{@code
* ClientFailoverConfig clientFailoverConfig = new ClientFailoverConfig();
* clientFailoverConfig.addClientConfig(clientConfig).addClientConfig(clientConfig2);
* ClientStateListener listener = new ClientStateListener(clientFailoverConfig);
* HazelcastClient.newHazelcastFailoverClient(clientFailoverConfig);
* }<pre>
*
* @param clientFailoverConfig The client configuration to which this listener will be registered
* @since 5.0
*/
public ClientStateListener(@Nonnull ClientFailoverConfig clientFailoverConfig) {
List<ClientConfig> clientConfigs = clientFailoverConfig.getClientConfigs();
for (ClientConfig clientConfig : clientConfigs) {
clientConfig.addListenerConfig(new ListenerConfig(this));
}
}

/**
* Registers this instance with the provided client configuration
*
* @param clientConfig The client configuration to which this listener will be registered
*/
public ClientStateListener(ClientConfig clientConfig) {
public ClientStateListener(@Nonnull ClientConfig clientConfig) {
clientConfig.addListenerConfig(new ListenerConfig(this));
}

@Override
public void stateChanged(LifecycleEvent event) {
lock.lock();
try {
if (event.getState().equals(CLIENT_CHANGED_CLUSTER)) {
return;
}
currentState = event.getState();
if (currentState.equals(CLIENT_CONNECTED) || currentState.equals(SHUTTING_DOWN) || currentState.equals(SHUTDOWN)) {
connectedCondition.signalAll();
Expand Down

0 comments on commit e5fbd7b

Please sign in to comment.