From e5fbd7bf1234435111ebae04fbd92dc07afc5865 Mon Sep 17 00:00:00 2001 From: sancar Date: Fri, 16 Jul 2021 11:53:17 +0300 Subject: [PATCH] Enabled ClientStateListener to be used on FailoverClient 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 --- .../FailoverClientConfigSupport.java | 64 +++++++++---------- .../client/util/ClientStateListener.java | 42 +++++++++++- 2 files changed, 71 insertions(+), 35 deletions(-) diff --git a/hazelcast/src/main/java/com/hazelcast/client/impl/clientside/FailoverClientConfigSupport.java b/hazelcast/src/main/java/com/hazelcast/client/impl/clientside/FailoverClientConfigSupport.java index 260b36f86a10..9c504b128123 100644 --- a/hazelcast/src/main/java/com/hazelcast/client/impl/clientside/FailoverClientConfigSupport.java +++ b/hazelcast/src/main/java/com/hazelcast/client/impl/clientside/FailoverClientConfigSupport.java @@ -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(); @@ -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"); } } } diff --git a/hazelcast/src/main/java/com/hazelcast/client/util/ClientStateListener.java b/hazelcast/src/main/java/com/hazelcast/client/util/ClientStateListener.java index be374a8ae16b..278818ab47a1 100644 --- a/hazelcast/src/main/java/com/hazelcast/client/util/ClientStateListener.java +++ b/hazelcast/src/main/java/com/hazelcast/client/util/ClientStateListener.java @@ -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; @@ -41,20 +45,49 @@ * 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 + *

+ * This constructor is introduced to let ClientStateListener to be used via + * {@link com.hazelcast.client.HazelcastClient#newHazelcastFailoverClient(ClientFailoverConfig)} + *

+ * 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. + *

+ * Note that ClientStateListener should be created after all the alternative client configs are added to the + * client failoverConfig. + * Example usage: + *

{@code
+     * ClientFailoverConfig clientFailoverConfig = new ClientFailoverConfig();
+     * clientFailoverConfig.addClientConfig(clientConfig).addClientConfig(clientConfig2);
+     * ClientStateListener listener = new ClientStateListener(clientFailoverConfig);
+     * HazelcastClient.newHazelcastFailoverClient(clientFailoverConfig);
+     * }
+     *
+     * @param clientFailoverConfig The client configuration to which this listener will be registered
+     * @since 5.0
+     */
+    public ClientStateListener(@Nonnull ClientFailoverConfig clientFailoverConfig) {
+        List 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));
     }
 
@@ -62,6 +95,9 @@ public ClientStateListener(ClientConfig clientConfig) {
     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();