
com.hazelcast.client.config.ClientFailoverConfig Maven / Gradle / Ivy
/*
* Copyright (c) 2008-2024, Hazelcast, Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hazelcast.client.config;
import com.hazelcast.client.config.impl.XmlClientFailoverConfigLocator;
import com.hazelcast.client.config.impl.YamlClientFailoverConfigLocator;
import com.hazelcast.config.InvalidConfigurationException;
import com.hazelcast.core.HazelcastException;
import java.util.LinkedList;
import java.util.List;
import static com.hazelcast.client.config.ClientConnectionStrategyConfig.ReconnectMode.OFF;
import static com.hazelcast.internal.config.DeclarativeConfigUtil.SYSPROP_CLIENT_FAILOVER_CONFIG;
import static com.hazelcast.internal.config.DeclarativeConfigUtil.validateSuffixInSystemProperty;
/**
* Config class to configure multiple client configs to be used by single client instance.
* The client will try to connect them in given order. When the connected cluster fails
* or the client blacklisted from the cluster via the Management Center, the client will
* search for alternative clusters with given configs.
*
* The client configurations must be exactly the same except the following configuration options:
*
* - {@code clusterName}
* - {@code SecurityConfig}
* - {@code NetworkConfig.Addresses}
* - {@code NetworkConfig.SocketInterceptorConfig}
* - {@code NetworkConfig.SSLConfig}
* - {@code NetworkConfig.AwsConfig}
* - {@code NetworkConfig.GcpConfig}
* - {@code NetworkConfig.AzureConfig}
* - {@code NetworkConfig.KubernetesConfig}
* - {@code NetworkConfig.EurekaConfig}
* - {@code NetworkConfig.CloudConfig}
* - {@code NetworkConfig.DiscoveryConfig}
*
*/
public class ClientFailoverConfig {
private int tryCount = Integer.MAX_VALUE;
private List clientConfigs = new LinkedList<>();
public ClientFailoverConfig() {
}
/**
* Populates Hazelcast {@link ClientFailoverConfig} object from an external configuration file.
*
* It tries to load Hazelcast Failover Client configuration from a list of well-known locations.
* When no location contains Hazelcast Failover Client configuration then it returns default.
*
* Note that the same mechanism is used when calling
* {@link com.hazelcast.client.HazelcastClient#newHazelcastFailoverClient()}.
*
* @return ClientFailoverConfig created from a file when exists, otherwise default.
*/
public static ClientFailoverConfig load() {
validateSuffixInSystemProperty(SYSPROP_CLIENT_FAILOVER_CONFIG);
XmlClientFailoverConfigLocator xmlConfigLocator = new XmlClientFailoverConfigLocator();
YamlClientFailoverConfigLocator yamlConfigLocator = new YamlClientFailoverConfigLocator();
if (xmlConfigLocator.locateFromSystemProperty()) {
// 1. Try loading XML config from the configuration provided in system property
return new XmlClientFailoverConfigBuilder(xmlConfigLocator).build();
} else if (yamlConfigLocator.locateFromSystemProperty()) {
// 2. Try loading YAML config from the configuration provided in system property
return new YamlClientFailoverConfigBuilder(yamlConfigLocator).build();
} else if (xmlConfigLocator.locateInWorkDirOrOnClasspath()) {
// 3. Try loading XML config from the working directory or from the classpath
return new XmlClientFailoverConfigBuilder(xmlConfigLocator).build();
} else if (yamlConfigLocator.locateInWorkDirOrOnClasspath()) {
// 4. Try loading YAML config from the working directory or from the classpath
return new YamlClientFailoverConfigBuilder(yamlConfigLocator).build();
} else {
throw new HazelcastException("Failed to load ClientFailoverConfig");
}
}
/**
* Adds the client config to the end of the alternative client configurations list.
*
* @param clientConfig the ClientConfig to add
* @return this for chaining
*/
public ClientFailoverConfig addClientConfig(ClientConfig clientConfig) {
validateClientConfig(clientConfig);
clientConfigs.add(clientConfig);
return this;
}
/**
* Sets the count that the client iterates over the given list of alternative clusters.
* For each alternative cluster, the client will try to connect to the cluster
* respecting related ConnectionRetryConfig.
*
* When the client can not connect a cluster, it will try to connect tryCount times going
* over the alternative client configs in a round-robin fashion. This is triggered at the
* start and also when the client disconnects from the cluster and can not connect back
* to it by exhausting attempts described in ConnectionRetryConfig. In that case,
* the client will continue from where it is left off in ClientConfig lists, and try
* the next one again in round-robin tryCount X number of alternative cluster times.
*
* Example:
* Assume that 3 alternative clusters are given in the ClientConfig list.
* Let's call them cluster A , B and C .
* When the tryCount is set as 2, the maximum number of subsequent connection attempts done
* by the client is 3 x 2 = 6.
* They will be tried in the following order as long as the client can not connect to any of them:
* A -> B -> C -> A -> B -> C -> Client Shutdown.
* Trial 1 -> Trial 2 -> Client Shutdown.
*
* Assume that client was connected to cluster B, and then it is disconnected from it. In that case, the trial
* oder will be as follows:
* C -> A -> B -> C -> A -> B -> Client Shutdown.
* Trial 1 -> Trial 2 -> Client Shutdown.
*
* @param tryCount the count of attempts
* @return this for chaining
*/
public ClientFailoverConfig setTryCount(int tryCount) {
this.tryCount = tryCount;
return this;
}
/**
* Gets the configured list of alternative client configurations.
*
* @return the list of configured ClientConfigs
*/
public List getClientConfigs() {
return clientConfigs;
}
/**
* Sets the configured list of alternative client configurations.
*
* Note: this method replaces previously configured alternative client
* configurations with the given list.
*
* @param clientConfigs the list of ClientConfigs to be used
* @return this for chaining
*/
public ClientFailoverConfig setClientConfigs(List clientConfigs) {
clientConfigs.forEach(this::validateClientConfig);
this.clientConfigs = clientConfigs;
return this;
}
/**
* Sets the count that the client iterates over the given list of alternative clusters.
* For each alternative cluster, the client will try to connect to the cluster
* respecting related ConnectionRetryConfig.
* Default value is {@code Integer.MAX_VALUE}.
*
* @return the max try count
*/
public int getTryCount() {
return tryCount;
}
@Override
public String toString() {
return "ClientFailoverConfig{"
+ "tryCount=" + tryCount
+ ", clientConfigs=" + clientConfigs
+ '}';
}
private void validateClientConfig(ClientConfig clientConfig) {
if (clientConfig.getConnectionStrategyConfig().getReconnectMode() == OFF) {
throw new InvalidConfigurationException("Reconnect mode for ClientFailoverConfig must not be OFF");
}
}
}