All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.kaazing.gateway.server.context.resolve.DefaultClusterContext Maven / Gradle / Ivy

There is a newer version: 6.1.3
Show newest version
/**
 * Copyright 2007-2016, Kaazing Corporation. 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 org.kaazing.gateway.server.context.resolve;

import static org.kaazing.gateway.server.context.resolve.DefaultServiceContext.BALANCER_MAP_NAME;
import static org.kaazing.gateway.server.context.resolve.DefaultServiceContext.MEMBERID_BALANCER_MAP_NAME;

import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.Lock;
import java.util.logging.Level;
import java.util.logging.LogRecord;

import org.kaazing.gateway.resource.address.ResolutionUtils;
import org.kaazing.gateway.server.messaging.buffer.ClusterMemoryMessageBufferFactory;
import org.kaazing.gateway.server.messaging.collections.ClusterCollectionsFactory;
import org.kaazing.gateway.service.cluster.BalancerMapListener;
import org.kaazing.gateway.service.cluster.ClusterConnectOptionsContext;
import org.kaazing.gateway.service.cluster.ClusterContext;
import org.kaazing.gateway.service.cluster.ClusterMessaging;
import org.kaazing.gateway.service.cluster.InstanceKeyListener;
import org.kaazing.gateway.service.cluster.MemberId;
import org.kaazing.gateway.service.cluster.MembershipEventListener;
import org.kaazing.gateway.service.cluster.ReceiveListener;
import org.kaazing.gateway.service.cluster.SendListener;
import org.kaazing.gateway.service.messaging.buffer.MessageBufferFactory;
import org.kaazing.gateway.service.messaging.collections.CollectionsFactory;
import org.kaazing.gateway.util.GL;
import org.kaazing.gateway.util.Utils;
import org.kaazing.gateway.util.aws.AwsUtils;
import org.kaazing.gateway.util.scheduler.SchedulerProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.hazelcast.config.AwsConfig;
import com.hazelcast.config.Config;
import com.hazelcast.config.Join;
import com.hazelcast.config.MapConfig;
import com.hazelcast.config.MulticastConfig;
import com.hazelcast.config.NetworkConfig;
import com.hazelcast.config.TcpIpConfig;
import com.hazelcast.core.Cluster;
import com.hazelcast.core.EntryEvent;
import com.hazelcast.core.EntryListener;
import com.hazelcast.core.Hazelcast;
import com.hazelcast.core.HazelcastInstance;
import com.hazelcast.core.IMap;
import com.hazelcast.core.IdGenerator;
import com.hazelcast.core.Member;
import com.hazelcast.core.MembershipEvent;
import com.hazelcast.core.MembershipListener;
import com.hazelcast.impl.GroupProperties;
import com.hazelcast.logging.LogEvent;
import com.hazelcast.logging.LogListener;
import com.hazelcast.logging.LoggingService;
import com.hazelcast.nio.Address;

/**
 * ClusterContext for KEG
 * 

*
Balancer data

  1. HttpBalancerService.MEMBERID_BALANCER_MAP_NAME:
    • List of balanced URIs for one member *
    • Key: Cluster member id
    • Value: Map(key: balancerURI, value: acceptURIs)
  2. HttpBalancerService.BALANCER_MAP_NAME *
    • List of balanced URIs for whole cluster
    • Key: balanceURI
    • Value: acceptURIs
*/ public class DefaultClusterContext implements ClusterContext, LogListener { private static final String CLUSTER_LOG_FORMAT = "HAZELCAST: [%s] - %s"; private static final String INSTANCE_KEY_MAP = "instanceKeyMap"; private final Logger logger = LoggerFactory.getLogger(GL.CLUSTER_LOGGER_NAME); private final String localInstanceKey = Utils.randomHexString(16); private MessageBufferFactory messageBufferFactory; private CollectionsFactory collectionsFactory; private List localInterfaces = new ArrayList<>(); private final List clusterMembers = new ArrayList<>(); private final List membershipEventListeners = new ArrayList<>(); private final List instanceKeyListeners = new ArrayList<>(); private final List balancerMapListeners = new ArrayList<>(); private ClusterMessaging clusterMessaging; private MemberId localNodeId; private final String clusterName; private HazelcastInstance clusterInstance; private final SchedulerProvider schedulerProvider; private final ClusterConnectOptionsContext connectOptions; private final AtomicBoolean clusterInitialized = new AtomicBoolean(false); public DefaultClusterContext(String name, List interfaces, List members, SchedulerProvider schedulerProvider) { this(name, interfaces, members, schedulerProvider, null); } public DefaultClusterContext(String name, List interfaces, List members, SchedulerProvider schedulerProvider, ClusterConnectOptionsContext connectOptions) { this.clusterName = name; this.localInterfaces.addAll(interfaces); this.clusterMembers.addAll(members); this.schedulerProvider = schedulerProvider; this.connectOptions = connectOptions; } @Override public void start() { // Check that we have either localInterfaces or clusterMembers if (localInterfaces.size() + clusterMembers.size() == 0) { // if no local interfaces if (localInterfaces.size() == 0) { GL.info(GL.CLUSTER_LOGGER_NAME, "No network interfaces specified in the gateway configuration"); throw new IllegalArgumentException("No network interfaces specified in the gateway configuration"); } // if no members if (clusterMembers.size() == 0) { GL.info(GL.CLUSTER_LOGGER_NAME, "No cluster members specified in the gateway configuration"); throw new IllegalArgumentException("No cluster members specified in the gateway configuration"); } } try { // from ha.xml and then add members interfaces Config config = initializeHazelcastConfig(); initializeCluster(config); GL.info(GL.CLUSTER_LOGGER_NAME, "Cluster Member started: IP Address: {}; Port: {}; id: {}", localNodeId.getHost(), localNodeId.getPort(), localNodeId.getId()); } catch (Exception e) { GL.error(GL.CLUSTER_LOGGER_NAME, "Unable to initialize cluster due to an exception: {}", e); throw new RuntimeException(String.format("Unable to initialize cluster due to an exception: %s", e), e); } } @Override public void dispose() { // If we're in client mode, then we may not have this clusterMessaging // object. So don't try to destroy it if it is not there at all // (KG-3496). if (clusterMessaging != null) { clusterMessaging.destroy(); } if (clusterInstance != null) { // KG-5837: do not call Hazelcast.shutdownAll() since that will hobble all in-process gateways clusterInstance.getLifecycleService().shutdown(); } } private Config initializeHazelcastConfig() throws Exception { Config hazelCastConfig = new Config(); hazelCastConfig.getGroupConfig().setName(getClusterName()); hazelCastConfig.getGroupConfig().setPassword("5942"); MapConfig mapConfig = hazelCastConfig.getMapConfig("serverSessions"); mapConfig.setBackupCount(3); MapConfig sharedBalancerMapConfig = hazelCastConfig.getMapConfig(BALANCER_MAP_NAME); sharedBalancerMapConfig.setBackupCount(Integer.MAX_VALUE); MapConfig memberBalancerMapConfig = hazelCastConfig.getMapConfig(MEMBERID_BALANCER_MAP_NAME); memberBalancerMapConfig.setBackupCount(Integer.MAX_VALUE); // disable port auto increment hazelCastConfig.setPortAutoIncrement(false); // The first accepts port is the port used by all network interfaces. int clusterPort = (localInterfaces.size() > 0) ? localInterfaces.get(0).getPort() : -1; // TO turn off logging in hazelcast API. // Note: must use Logger.getLogger, not LogManager.getLogger java.util.logging.Logger logger = java.util.logging.Logger.getLogger("com.hazelcast"); logger.setLevel(Level.OFF); // initialize hazelcast if (clusterPort != -1) { hazelCastConfig.setPort(clusterPort); } NetworkConfig networkConfig = new NetworkConfig(); for (MemberId localInterface : localInterfaces) { String protocol = localInterface.getProtocol(); if ("udp".equalsIgnoreCase(protocol) || "aws".equalsIgnoreCase(protocol)) { throw new IllegalArgumentException("Cannot accept on a multicast or aws address, use unicast address starting " + "with tcp://"); } // NOTE: The version of Hazelcast(1.9.4.8) that is being used does not support IPv6 address. The Hazelcast library // throws NumberFormatException when IPv6 address is specified as an interface to bind to. String hostAddress = localInterface.getHost(); InetAddress address = getResolvedAddressFromHost(hostAddress); if (address instanceof Inet6Address) { throw new IllegalArgumentException("ERROR: Cluster member accept url - '" + localInterface.toString() + "' consists of IPv6 address which is not supported. Use Ipv4 address instead."); } // convertHostToIP method is used in order to address situations in which network interface syntax is present String hostConvertedToIP = convertHostToIP(localInterface.getHost()); networkConfig.getInterfaces().addInterface(hostConvertedToIP); if (localInterface.getPort() != clusterPort) { throw new IllegalArgumentException("Port numbers on the network interfaces in do not match"); } } boolean usingMulticast = false; Join joinConfig = networkConfig.getJoin(); MulticastConfig multicastConfig = joinConfig.getMulticastConfig(); // Disable multicast to avoid using the default multicast address 224.2.2.3:54327. // In this way, new cluster members joining the cluster won't accidentally join // due to having configured the default multicast address. If multicast adresses are mentioned below, // we enable it. See KG-6045 for an example of an accidental multicast cluster connection. multicastConfig.setEnabled(false); TcpIpConfig tcpIpConfig = joinConfig.getTcpIpConfig(); List multicastAddresses = new ArrayList<>(); List unicastAddresses = new ArrayList<>(); MemberId awsMember = null; for (MemberId member : clusterMembers) { switch (member.getProtocol()) { case "udp": // convertHostToIP method is used in order to address situations in which network interface syntax is present multicastAddresses.add(new InetSocketAddress(convertHostToIP(member.getHost()), member.getPort())); break; case "tcp": // convertHostToIP method is used in order to address situations in which network interface syntax is present unicastAddresses.add(new InetSocketAddress(convertHostToIP(member.getHost()), member.getPort())); break; case "aws": awsMember = member; // There should be only one tag when AWS is being // used. We have already validated that in // GatewayContextResolver.processClusterMembers() method. break; } } if (awsMember == null) { // Gateway is running in an on-premise env. int multicastAddressesCount = multicastAddresses.size(); if (multicastAddressesCount > 1) { throw new IllegalArgumentException("Conflicting multicast discovery addresses in cluster configuration"); } else if (multicastAddressesCount > 0) { if (AwsUtils.isDeployedToAWS()) { throw new IllegalArgumentException("Multicast cluster configuration not supported on AWS, use " + "aws://security-group/ in connect tag"); } multicastConfig.setEnabled(true); InetSocketAddress multicastAddress = multicastAddresses.get(0); multicastConfig.setMulticastGroup(multicastAddress.getHostName()); multicastConfig.setMulticastPort(multicastAddress.getPort()); } if (unicastAddresses.size() > 0) { tcpIpConfig.setEnabled(!usingMulticast); for (InetSocketAddress unicastAddress : unicastAddresses) { tcpIpConfig.addAddress(new Address(unicastAddress)); } } // Check if address specified to bind to is a wildcard address. If it is a wildcard address, // do not override the property PROP_SOCKET_BIND_ANY. If not, set the PROP_SOCKET_BIND_ANY to false so // that Hazelcast won't discard the interface specified to bind to. boolean useAnyAddress = false; // Check to see if the address specified is the wildcard address for (String networkInterface : networkConfig.getInterfaces().getInterfaces()) { InetAddress address = getResolvedAddressFromHost(networkInterface); if (address.isAnyLocalAddress()) { // this will prevent PROP_SOCKET_BIND_ANY property from being overridden to false // so that Hazelcast can bind to wildcard address useAnyAddress = true; break; } } // Override the PROP_SOCKET_BIND_ANY to false if the address to bind to is not wildcard address // Explicitly enable the interface so that Hazelcast will pick the one specified if (!useAnyAddress) { networkConfig.getInterfaces().setEnabled(true); hazelCastConfig.setProperty(GroupProperties.PROP_SOCKET_BIND_ANY, "false"); } } else { // Gateway is running in the AWS/Cloud env. // Get rid of the leading slash "/" in the path. String path = awsMember.getPath(); String groupName = null; if (path != null) { if ((path.indexOf("/") == 0) && (path.length() > 1)) { groupName = path.substring(1, path.length()); } } // If the groupName is not specified, then we will get it from // the meta-data. if ((groupName == null) || (groupName.length() == 0)) { groupName = AwsUtils.getSecurityGroupName(); } multicastConfig.setEnabled(false); tcpIpConfig.setEnabled(false); AwsConfig awsConfig = joinConfig.getAwsConfig(); awsConfig.setEnabled(true); awsConfig.setAccessKey(connectOptions.getAwsAccessKeyId()); awsConfig.setSecretKey(connectOptions.getAwsSecretKey()); awsConfig.setRegion(AwsUtils.getRegion()); awsConfig.setSecurityGroupName(groupName); // KG-7725: Hazelcast wants to bind on an interface, and if the Gateway doesn't // tell it which ones to pick it'll pick one on its own. Make sure interfaces // are explicitly enabled, and grab the local IP address since this will be the // IP address used to do discovery of other Gateways in the given security group. // Otherwise an elastic IP associated with the instance might cause Hazelcast to // pick a different IP address to listen on than the one used to connect to other // members, meaning where Gateways are listening is *not* where Gateways try to // connect to other Gateways. In those situations the cluster does not form. String localIPv4 = AwsUtils.getLocalIPv4(); networkConfig.getInterfaces().setEnabled(true); networkConfig.getInterfaces().clear(); networkConfig.getInterfaces().addInterface(localIPv4); // KG-12825: Override the property PROP_SOCKET_BIND_ANY and set it to false so that // Hazelcast does not discard the interface explicitly specified to bind to. hazelCastConfig.setProperty(GroupProperties.PROP_SOCKET_BIND_ANY, "false"); } hazelCastConfig.setNetworkConfig(networkConfig); // Override the shutdown hook in Hazelcast so that the connection counts can be correctly maintained. // The cluster instance should be shutdown by the Gateway, so there should be no need for the default // Hazelcast shutdown hook. hazelCastConfig.setProperty(GroupProperties.PROP_SHUTDOWNHOOK_ENABLED, "false"); return hazelCastConfig; } /** * Method returning IP from host * @param host * @return * @throws UnknownHostException */ private String convertHostToIP(String host) throws UnknownHostException { return getResolvedAddressFromHost(host).getHostAddress(); } @SuppressWarnings("unused") private List processInterfaceOrMemberEntry(String entry) { if (entry == null) { return null; } ArrayList addresses = new ArrayList<>(); int starIndex = entry.indexOf('*'); int dashIndex = entry.indexOf('-'); if (starIndex == -1 && dashIndex == -1) { addresses.add(entry); return addresses; } String[] parts = entry.split("\\."); if (parts.length != 4) { throw new IllegalArgumentException("Invalid wildcard in the entry for cluster configuration: " + entry); } // Prevent wildcards in the first part if (parts[0].contains("*") && parts[0].contains("-")) { throw new IllegalArgumentException( "Invalid wildcard in the entry for cluster configuration, first part of the address cannot contain a " + "wildcard: " + entry); } String part1 = parts[0]; String[] part2s = processEntryPart(entry, parts[1]); String[] part3s = processEntryPart(entry, parts[2]); String[] part4s = processEntryPart(entry, parts[3]); for (String part2 : part2s) { for (String part3 : part3s) { for (String part4 : part4s) { addresses.add(part1 + "." + part2 + "." + part3 + "." + part4); } } } return addresses; } /** * Previous to network interface syntax support, only InetAddress.getByName(hostAddress) was used for when * returning IPs based on host name. This basically did a InetAddress.getAllByName(hostAddress)[0] * Consequently, only the first IP address was returned * A similar approach has been used with added NetworkIntrfaceSyntax support, where only the first IP * is returned for a localInterface * Same approach is used also for cluster members * Method returning resolved addresses from host * @param hostAddress * @return * @throws UnknownHostException */ private InetAddress getResolvedAddressFromHost(String hostAddress) throws UnknownHostException { // TODO: Previous to network interface syntax support, only InetAddress.getByName(hostAddress) was used for when // returning IPs based on host name. This basically did a InetAddress.getAllByName(hostAddress)[0] // Consequently, only the first IP address was returned // A similar approach has been used with added NetworkIntrfaceSyntax support, where only the first IP // is returned for a localInterface // Same approach is used also for cluster members InetAddress address; Collection addresses = ResolutionUtils.getAllByName(hostAddress, false); if (addresses.isEmpty()) { address = InetAddress.getByName(hostAddress); } else { address = addresses.iterator().next(); } return address; } private String[] processEntryPart(String entry, String ipPart) { // No wild cards if (!ipPart.contains("*") && !ipPart.contains("-")) { String[] resolvedParts = new String[1]; resolvedParts[0] = ipPart; return resolvedParts; } // process * if (ipPart.equals("*")) { String[] resolvedParts = new String[256]; for (int i = 0; i < 256; i++) { resolvedParts[i] = String.valueOf(i); } return resolvedParts; } // process ranges if (ipPart.contains("-")) { String[] rangeParts = ipPart.split("-"); if (rangeParts.length != 2) { throw new IllegalArgumentException("Invalid wildcard in the entry for cluster configuration: " + entry); } int start = Integer.parseInt(rangeParts[0]); int end = Integer.parseInt(rangeParts[1]); String[] resolvedParts = new String[end - start + 1]; for (int i = start; i <= end; i++) { resolvedParts[i] = String.valueOf(i); } return resolvedParts; } throw new IllegalArgumentException("Invalid wildcard in the entry for cluster configuration: " + entry); } @Override public MemberId getLocalMember() { return this.localNodeId; } @Override public Collection getMemberIds() { Map instanceKeyMap = getCollectionsFactory().getMap(INSTANCE_KEY_MAP); return instanceKeyMap.keySet(); } private MemberId getMemberId(Member member) { InetSocketAddress inetSocketAddress = member.getInetSocketAddress(); String hostname = inetSocketAddress.getHostName(); if (!inetSocketAddress.isUnresolved()) { String ipAddr = inetSocketAddress.getAddress().getHostAddress(); hostname = ipAddr; GL.debug(GL.CLUSTER_LOGGER_NAME, "getMemberId: Hostname: {}; IP Address: {}", hostname, ipAddr); } return new MemberId("tcp", hostname, inetSocketAddress.getPort()); } private MembershipListener membershipListener = new MembershipListener() { @Override public void memberAdded(MembershipEvent membershipEvent) { MemberId newMemberId = getMemberId(membershipEvent.getMember()); GL.info(GL.CLUSTER_LOGGER_NAME, "Cluster member {} is now online", newMemberId.getId()); fireMemberAdded(newMemberId); GL.info(GL.CLUSTER_LOGGER_NAME, "Member Added"); logClusterStateAtInfoLevel(); } @Override public void memberRemoved(MembershipEvent membershipEvent) { MemberId removedMember = getMemberId(membershipEvent.getMember()); GL.info(GL.CLUSTER_LOGGER_NAME, "Cluster member {} has gone down", removedMember); // Clean up the member's instanceKey Map instanceKeyMap = getCollectionsFactory().getMap(INSTANCE_KEY_MAP); instanceKeyMap.remove(removedMember); // cleanup balancer URIs for the member that went down Map>> memberIdBalancerUriMap = getCollectionsFactory().getMap(MEMBERID_BALANCER_MAP_NAME); if (memberIdBalancerUriMap == null) { throw new IllegalStateException("MemberId to BalancerMap is null"); } IMap> sharedBalanceUriMap = getCollectionsFactory().getMap(BALANCER_MAP_NAME); if (sharedBalanceUriMap == null) { throw new IllegalStateException("Shared balanced URIs map is null"); } Map> memberBalancedUrisMap = memberIdBalancerUriMap.remove(removedMember); if (memberBalancedUrisMap != null) { GL.debug(GL.CLUSTER_LOGGER_NAME, "Cleaning up balancer cluster state for member {}", removedMember); try { for (String key : memberBalancedUrisMap.keySet()) { GL.debug(GL.CLUSTER_LOGGER_NAME, "URI Key: {}", key); List memberBalancedUris = memberBalancedUrisMap.get(key); TreeSet globalBalancedUris; TreeSet newGlobalBalancedUris; do { globalBalancedUris = sharedBalanceUriMap.get(key); newGlobalBalancedUris = new TreeSet<>(globalBalancedUris); for (String memberBalancedUri : memberBalancedUris) { GL.debug(GL.CLUSTER_LOGGER_NAME, "Attempting to removing Balanced URI : {}", memberBalancedUri); newGlobalBalancedUris.remove(memberBalancedUri); } } while (!sharedBalanceUriMap.replace(key, globalBalancedUris, newGlobalBalancedUris)); GL.debug(GL.CLUSTER_LOGGER_NAME, "Removed balanced URIs for cluster member {}, new global list: {}", removedMember, newGlobalBalancedUris); } } catch (Exception e) { throw new IllegalStateException("Unable to remove the balanced URIs served by the member going down from " + "global map"); } } fireMemberRemoved(removedMember); GL.info(GL.CLUSTER_LOGGER_NAME, "Member Removed"); logClusterStateAtInfoLevel(); } }; @Override public String getInstanceKey(MemberId memberId) { if (memberId == localNodeId) { return this.localInstanceKey; // quicker, and works with CLIENT_MODE, too. } Map instanceKeyMap = getCollectionsFactory().getMap(INSTANCE_KEY_MAP); return instanceKeyMap.get(memberId); } private EntryListener instanceKeyEntryListener = new EntryListener() { // WE're supporting the idea of 'instance keys' (i.e. random strings that are supposed // to be unique per instance of a gateway) solely for management to be able to tell the // difference between two instances of a gateway accessed through the same management URL. // The Console supports displaying history, and it needs to know when reconnecting to a // given management URL whether or not the configuration might have changed. Because // member IDs generally don't change (for now they're based on the cluster accept URL), // they're a bad indicator of an instance stopping and being restarted. Thus the need for the // instance key. When a member is added or removed, the instanceKey is also added or // removed, and we can trigger events for management to update their cluster state. @Override public void entryAdded(EntryEvent newEntryEvent) { fireInstanceKeyAdded(newEntryEvent.getValue()); } @Override public void entryEvicted(EntryEvent evictedEntryEvent) { throw new RuntimeException("Instance keys should not be evicted, only added or removed."); } @Override public void entryRemoved(EntryEvent removedEntryEvent) { fireInstanceKeyRemoved(removedEntryEvent.getValue()); } @Override public void entryUpdated(EntryEvent updatedEntryEvent) { throw new RuntimeException("Instance keys can not be updated, only added or removed."); } }; private EntryListener> balancerMapEntryListener = new EntryListener>() { @Override public void entryAdded(EntryEvent> newEntryEvent) { GL.trace(GL.CLUSTER_LOGGER_NAME, "New entry for balance URI: {} value: {}", newEntryEvent.getKey(), newEntryEvent .getValue()); fireBalancerEntryAdded(newEntryEvent); } @Override public void entryEvicted(EntryEvent> evictedEntryEvent) { throw new RuntimeException("Balancer map entries should not be evicted, only added or removed."); } @Override public void entryRemoved(EntryEvent> removedEntryEvent) { GL.trace(GL.CLUSTER_LOGGER_NAME, "Entry removed for balance URI: {} value: {}", removedEntryEvent .getKey(), removedEntryEvent.getValue()); fireBalancerEntryRemoved(removedEntryEvent); } @Override public void entryUpdated(EntryEvent> updatedEntryEvent) { GL.trace(GL.CLUSTER_LOGGER_NAME, "Entry updated for balance URI: {} value: {}", updatedEntryEvent .getKey(), updatedEntryEvent.getValue()); fireBalancerEntryUpdated(updatedEntryEvent); } }; // cluster collections @Override public Lock getLock(Object obj) { return clusterInstance.getLock(obj); } @Override public IdGenerator getIdGenerator(String name) { return clusterInstance.getIdGenerator(name); } // cluster communication @Override public void addReceiveQueue(String name) { if (clusterMessaging != null) { clusterMessaging.addReceiveQueue(name); } } @Override public void addReceiveTopic(String name) { if (clusterMessaging != null) { clusterMessaging.addReceiveTopic(name); } } @Override public void send(Object msg, SendListener listener, MemberId member) { if (clusterMessaging != null) { clusterMessaging.send(msg, listener, member); } } @Override public void send(Object msg, SendListener listener, String name) { if (clusterMessaging != null) { clusterMessaging.send(msg, listener, name); } } @SuppressWarnings("unchecked") @Override public Object send(Object msg, MemberId member) throws Exception { if (clusterMessaging != null) { return clusterMessaging.send(msg, member); } return null; } @SuppressWarnings("unchecked") @Override public Object send(Object msg, String name) throws Exception { if (clusterMessaging != null) { return clusterMessaging.send(msg, name); } return null; } @Override public void setReceiver(Class type, ReceiveListener receiveListener) { if (clusterMessaging != null) { clusterMessaging.setReceiver(type, receiveListener); } } @Override public void removeReceiver(Class type) { if (clusterMessaging != null) { clusterMessaging.removeReceiver(type); } } @Override public void addMembershipEventListener(MembershipEventListener eventListener) { if (eventListener != null) { membershipEventListeners.add(eventListener); GL.debug(GL.CLUSTER_LOGGER_NAME, "MemberShipEventListener Added"); } } @Override public void removeMembershipEventListener(MembershipEventListener eventListener) { if (eventListener != null) { membershipEventListeners.remove(eventListener); } } @Override public void addInstanceKeyListener(InstanceKeyListener instanceKeyListener) { if (instanceKeyListener != null) { instanceKeyListeners.add(instanceKeyListener); } } @Override public void removeInstanceKeyListener(InstanceKeyListener instanceKeyListener) { if (instanceKeyListener != null) { instanceKeyListeners.remove(instanceKeyListener); } } @Override public void addBalancerMapListener(BalancerMapListener balancerMapListener) { if (balancerMapListener != null) { balancerMapListeners.add(balancerMapListener); GL.debug(GL.CLUSTER_LOGGER_NAME, "Add balancerMapListener"); } GL.debug(GL.CLUSTER_LOGGER_NAME, "Exit Add balancerMapListener"); } @Override public void removeBalancerMapListener(BalancerMapListener balancerMapListener) { if (balancerMapListener != null) { balancerMapListeners.remove(balancerMapListener); GL.debug(GL.CLUSTER_LOGGER_NAME, "Remove balancerMapListener"); } GL.debug(GL.CLUSTER_LOGGER_NAME, "Exit Remove balancerMapListener"); } @Override public String getClusterName() { return this.clusterName; } @Override public List getAccepts() { return localInterfaces; } @Override public List getConnects() { return clusterMembers; } @Override public ClusterConnectOptionsContext getConnectOptions() { return connectOptions; } @Override public MessageBufferFactory getMessageBufferFactory() { return messageBufferFactory; } @Override /* * Logs cluster state and balancer service maps contents when ha logging is enabled at trace level ! */ public void logClusterState() { logClusterMembers(); logBalancerMap(); } @Override /* * Logs cluster state at Info Level, recommended use only for startup or methods that are called only one time when * cluster state changes ! */ public void logClusterStateAtInfoLevel() { if (clusterInstance != null) { Cluster cluster = clusterInstance.getCluster(); if (cluster != null) { GL.info(GL.CLUSTER_LOGGER_NAME, "Current cluster members:"); Set currentMembers = clusterInstance.getCluster().getMembers(); for (Member currentMember : currentMembers) { MemberId memberId = getMemberId(currentMember); GL.info(GL.CLUSTER_LOGGER_NAME, " member: {}", memberId); } } } GL.info(GL.CLUSTER_LOGGER_NAME, "Current shared balancer map:"); Map> balancerMap = getCollectionsFactory().getMap(BALANCER_MAP_NAME); for (String balanceURI : balancerMap.keySet()) { Set balanceTargets = balancerMap.get(balanceURI); GL.info(GL.CLUSTER_LOGGER_NAME, " balance URI: {} target list: {}", balanceURI, balanceTargets); } } private void logClusterMembers() { // log current cluster state on TRACE level if (clusterInstance != null) { Cluster cluster = clusterInstance.getCluster(); if (cluster != null) { GL.trace(GL.CLUSTER_LOGGER_NAME, "Current cluster members:"); Set currentMembers = clusterInstance.getCluster().getMembers(); for (Member currentMember : currentMembers) { MemberId memberId = getMemberId(currentMember); GL.trace(GL.CLUSTER_LOGGER_NAME, " member: {}", memberId); } } } } private void logBalancerMap() { GL.trace(GL.CLUSTER_LOGGER_NAME, "Current members of balancer map:"); Map>> memberIdBalancerUriMap = getCollectionsFactory().getMap(MEMBERID_BALANCER_MAP_NAME); for (MemberId memberID : memberIdBalancerUriMap.keySet()) { GL.trace(GL.CLUSTER_LOGGER_NAME, " MemberID {}", memberID); Map> balanceURIMap = memberIdBalancerUriMap.get(memberID); for (String balanceURI : balanceURIMap.keySet()) { List balanceTargets = balanceURIMap.get(balanceURI); GL.trace(GL.CLUSTER_LOGGER_NAME, " balance URI: {} target list: {}", balanceURI, balanceTargets); } } GL.trace(GL.CLUSTER_LOGGER_NAME, "Current shared balancer map::"); Map> balancerMap = getCollectionsFactory().getMap(BALANCER_MAP_NAME); for (String balanceURI : balancerMap.keySet()) { Set balanceTargets = balancerMap.get(balanceURI); GL.trace(GL.CLUSTER_LOGGER_NAME, " balance URI: {} target list: {}", balanceURI, balanceTargets); } } /** * Fire member added event */ private void fireMemberAdded(MemberId newMember) { GL.debug(GL.CLUSTER_LOGGER_NAME, "Firing member added for : {}", newMember); for (MembershipEventListener listener : membershipEventListeners) { try { listener.memberAdded(newMember); } catch (Throwable e) { GL.error(GL.CLUSTER_LOGGER_NAME, "Error in member added event {}", e); } } } /** * Fire member removed event */ private void fireMemberRemoved(MemberId exMember) { GL.debug(GL.CLUSTER_LOGGER_NAME, "Firing member removed for: {}", exMember); for (MembershipEventListener listener : membershipEventListeners) { try { listener.memberRemoved(exMember); } catch (Throwable e) { GL.error(GL.CLUSTER_LOGGER_NAME, "Error in member removed event {}", e); } } } /** * Fire instanceKeyAdded event */ private void fireInstanceKeyAdded(String instanceKey) { GL.debug(GL.CLUSTER_LOGGER_NAME, "Firing instanceKeyAdded for: {}", instanceKey); for (InstanceKeyListener listener : instanceKeyListeners) { try { listener.instanceKeyAdded(instanceKey); } catch (Throwable e) { GL.error(GL.CLUSTER_LOGGER_NAME, "Error in instanceKeyAdded event {}", e); } } } /** * Fire instanceKeyRemoved event */ private void fireInstanceKeyRemoved(String instanceKey) { GL.debug(GL.CLUSTER_LOGGER_NAME, "Firing instanceKeyRemoved for: {}", instanceKey); for (InstanceKeyListener listener : instanceKeyListeners) { try { listener.instanceKeyRemoved(instanceKey); } catch (Throwable e) { GL.error(GL.CLUSTER_LOGGER_NAME, "Error in instanceKeyRemoved event {}", e); } } } /** * Fire balancerEntryAdded event */ private void fireBalancerEntryAdded(EntryEvent> entryEvent) { String balancerURI = entryEvent.getKey(); GL.debug(GL.CLUSTER_LOGGER_NAME, "Firing balancerEntryAdded for: {}", balancerURI); for (BalancerMapListener listener : balancerMapListeners) { try { listener.balancerEntryAdded(balancerURI, entryEvent.getValue()); } catch (Throwable e) { GL.error(GL.CLUSTER_LOGGER_NAME, "Error in balancerEntryAdded event {}", e); } } } /** * Fire balancerEntryRemoved event */ private void fireBalancerEntryRemoved(EntryEvent> entryEvent) { String balancerURI = entryEvent.getKey(); GL.debug(GL.CLUSTER_LOGGER_NAME, "Firing balancerEntryRemoved for: {}", balancerURI); for (BalancerMapListener listener : balancerMapListeners) { try { listener.balancerEntryRemoved(balancerURI, entryEvent.getValue()); } catch (Throwable e) { GL.error(GL.CLUSTER_LOGGER_NAME, "Error in balancerEntryRemoved event {}", e); } } } /** * Fire balancerEntryUpdated event */ private void fireBalancerEntryUpdated(EntryEvent> entryEvent) { String balancerURI = entryEvent.getKey(); GL.debug(GL.CLUSTER_LOGGER_NAME, "Firing balancerEntryUpdated for: {}", balancerURI); for (BalancerMapListener listener : balancerMapListeners) { try { listener.balancerEntryUpdated(balancerURI, entryEvent.getValue()); } catch (Throwable e) { GL.error(GL.CLUSTER_LOGGER_NAME, "Error in balancerEntryUpdated event {}", e); } } } @Override public CollectionsFactory getCollectionsFactory() { initializeCluster(null); return this.collectionsFactory; } private void initializeCluster(Config config) { if (clusterInitialized.compareAndSet(false, true)) { clusterInstance = Hazelcast.newHazelcastInstance(config); if (clusterInstance == null) { throw new RuntimeException("Unable to initialize the cluster"); } Cluster cluster = clusterInstance.getCluster(); cluster.addMembershipListener(this.membershipListener); // Register a listener for Hazelcast logging events LoggingService loggingService = clusterInstance.getLoggingService(); loggingService.addLogListener(Level.FINEST, this); this.collectionsFactory = new ClusterCollectionsFactory(clusterInstance); this.messageBufferFactory = new ClusterMemoryMessageBufferFactory(clusterInstance); localNodeId = getMemberId(cluster.getLocalMember()); clusterMessaging = new ClusterMessaging(this, clusterInstance, schedulerProvider); IMap instanceKeyMap = collectionsFactory.getMap(INSTANCE_KEY_MAP); instanceKeyMap.put(localNodeId, localInstanceKey); instanceKeyMap.addEntryListener(instanceKeyEntryListener, true); IMap> balancerMap = collectionsFactory.getMap(BALANCER_MAP_NAME); balancerMap.addEntryListener(balancerMapEntryListener, true); } } @Override public void log(LogEvent logEvent) { Member member = logEvent.getMember(); LogRecord record = logEvent.getLogRecord(); Level level = record.getLevel(); if (level.equals(Level.SEVERE)) { logger.error(String.format(CLUSTER_LOG_FORMAT, member, record.getMessage())); } else if (level.equals(Level.WARNING)) { logger.warn(String.format(CLUSTER_LOG_FORMAT, member, record.getMessage())); } else if (level.equals(Level.INFO)) { logger.info(String.format(CLUSTER_LOG_FORMAT, member, record.getMessage())); } else if (level.equals(Level.FINE)) { if (logger.isDebugEnabled()) { logger.debug(String.format(CLUSTER_LOG_FORMAT, member, record.getMessage())); } } else if (level.equals(Level.FINER) || level.equals(Level.FINEST)) { if (logger.isTraceEnabled()) { logger.trace(String.format(CLUSTER_LOG_FORMAT, member, record.getMessage())); } } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy