
io.jsync.spi.cluster.impl.HazelcastClusterManager Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jsync.io Show documentation
Show all versions of jsync.io Show documentation
jsync.io is a non-blocking, event-driven networking framework for Java
/*
* Copyright (c) 2011-2013 The original author or authors
* ------------------------------------------------------
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Apache License v2.0 which accompanies this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* The Apache License v2.0 is available at
* http://www.opensource.org/licenses/apache2.0.php
*
* You may elect to redistribute this code under either of these licenses.
*/
package io.jsync.spi.cluster.impl;
import com.hazelcast.client.proxy.ClientClusterProxy;
import com.hazelcast.config.Config;
import com.hazelcast.config.InMemoryXmlConfig;
import com.hazelcast.config.MultiMapConfig;
import com.hazelcast.core.*;
import io.jsync.logging.Logger;
import io.jsync.logging.impl.LoggerFactory;
import io.jsync.spi.AsyncSPI;
import io.jsync.spi.cluster.AsyncMap;
import io.jsync.spi.cluster.AsyncMultiMap;
import io.jsync.spi.cluster.ClusterManager;
import io.jsync.spi.cluster.NodeListener;
import io.jsync.utils.CryptoUtils;
import org.apache.commons.io.IOUtils;
import java.io.*;
import java.util.*;
/**
* A cluster manager that uses Hazelcast
*
* @author Tim Fox
*/
public class HazelcastClusterManager implements ClusterManager, MembershipListener {
private static final Logger log = LoggerFactory.getLogger(HazelcastClusterManager.class);
// Hazelcast config file
private static final String DEFAULT_CONFIG_FILE = "cluster.xml";
private static final String CONFIG_FILE = "cluster.xml";
private static HazelcastInstance nextHazelcastInstance;
private final AsyncSPI async;
private HazelcastInstance hazelcast;
private String nodeID;
private NodeListener nodeListener;
private boolean active;
private String registrationID;
/**
* Constructor
*/
protected HazelcastClusterManager(final AsyncSPI async) {
this.async = async;
// We have our own shutdown hook and need to ensure ours runs before Hazelcast is shutdown
System.setProperty("hazelcast.shutdownhook.enabled", "false");
}
public static void setNextInstance(HazelcastInstance nextInstance) {
nextHazelcastInstance = nextInstance;
}
private static InputStream getConfigStream() {
ClassLoader cl = HazelcastClusterManager.class.getClassLoader();
InputStream is = cl.getResourceAsStream(CONFIG_FILE);
// Check for CONFIG_FILE in jar location
File curDir = (new File("."));
if (curDir.isDirectory()) {
File[] files = curDir.listFiles();
for (File file : files) {
if (file.getName().equals(CONFIG_FILE)) {
try {
log.info("Loading cluster config from " + CONFIG_FILE);
return new FileInputStream(file);
} catch (FileNotFoundException e) {
continue; // Not Found so continue? Why not
}
}
}
}
if (is == null) {
is = cl.getResourceAsStream(DEFAULT_CONFIG_FILE);
}
return is;
}
/**
* Get the Hazelcast config
*
* @return a config object
*/
private static String getConfigXml() {
try (InputStream is = getConfigStream()) {
if (is != null) {
return IOUtils.toString(is, "UTF-8");
}
} catch (IOException ex) {
log.error("Failed to read config", ex);
}
return null;
}
public static Config getDefaultConfig() {
// Right now we want to load the getConfig() into a InMemoryXmlConfig with some default properties
Properties defaultConfigProperties = new Properties();
defaultConfigProperties.put("hazelcast.memcache.enabled", false);
defaultConfigProperties.put("hazelcast.rest.enabled", false);
defaultConfigProperties.put("hazelcast.wait.seconds.before.join", 0);
defaultConfigProperties.put("hazelcast.logging.type", false);
Config cfg = new InMemoryXmlConfig(getConfigXml(), defaultConfigProperties);
// Now we want to configure some other stuff by default
MultiMapConfig subsConfig = new MultiMapConfig("subs");
subsConfig.setBinary(true);
subsConfig.setAsyncBackupCount(2);
subsConfig.setBackupCount(1);
cfg.addMultiMapConfig(subsConfig);
return cfg;
}
/**
* This method joins the cluster. If the system property hazelcast.mode is set to "client"
* then this hazelcast instance will connect via a HazelcastClient rather than a direct member
* of the cluster. This can be set via
*/
public synchronized void join() {
if (active) {
return;
}
if (nextHazelcastInstance == null) {
hazelcast = Hazelcast.newHazelcastInstance(getConfig());
nodeID = hazelcast.getCluster().getLocalMember().getUuid();
} else {
hazelcast = nextHazelcastInstance;
// Ensure that it's not a ClusterClient
if (!(hazelcast.getCluster() instanceof ClientClusterProxy)) {
nodeID = hazelcast.getCluster().getLocalMember().getUuid();
} else {
// Generate a random ID
// Not sure if this is too safe
nodeID = "client-" + CryptoUtils.calculateHmacSHA1(UUID.randomUUID().toString(), UUID.randomUUID().toString());
}
nextHazelcastInstance = null;
}
registrationID = hazelcast.getCluster().addMembershipListener(this);
active = true;
}
/**
* Every eventbus handler has an ID. SubsMap (subscriber map) is a MultiMap which
* maps handler-IDs with server-IDs and thus allows the eventbus to determine where
* to send messages.
*
* @param name A unique name by which the the MultiMap can be identified within the cluster.
* See the cluster config file (e.g. cluster.xml in case of HazelcastClusterManager) for
* additional MultiMap config parameters.
* @return subscription map
*/
public AsyncMultiMap getAsyncMultiMap(final String name) {
com.hazelcast.core.MultiMap map = hazelcast.getMultiMap(name);
return new HazelcastAsyncMultiMap(async, map);
}
@Override
public String getNodeID() {
return nodeID;
}
@Override
public List getNodes() {
Set members = hazelcast.getCluster().getMembers();
List lMembers = new ArrayList<>();
for (Member member : members) {
lMembers.add(member.getUuid());
}
return lMembers;
}
@Override
public void nodeListener(NodeListener listener) {
this.nodeListener = listener;
}
@Override
public AsyncMap getAsyncMap(String name) {
IMap map = hazelcast.getMap(name);
return new HazelcastAsyncMap(async, map);
}
@Override
public Map getSyncMap(String name) {
IMap map = hazelcast.getMap(name);
return map;
}
public synchronized void leave() {
if (!active) {
return;
}
if (hazelcast.getLifecycleService().isRunning()) {
hazelcast.getCluster().removeMembershipListener(registrationID);
hazelcast.getLifecycleService().shutdown();
}
active = false;
}
@Override
public synchronized void memberAdded(MembershipEvent membershipEvent) {
if (!active) {
return;
}
try {
if (nodeListener != null) {
Member member = membershipEvent.getMember();
nodeListener.nodeAdded(member.getUuid());
}
} catch (Throwable t) {
log.error("Failed to handle memberAdded", t);
}
}
@Override
public synchronized void memberRemoved(MembershipEvent membershipEvent) {
if (!active) {
return;
}
try {
if (nodeListener != null) {
Member member = membershipEvent.getMember();
nodeListener.nodeLeft(member.getUuid());
}
} catch (Throwable t) {
log.error("Failed to handle memberRemoved", t);
}
}
@Override
public void memberAttributeChanged(MemberAttributeEvent memberAttributeEvent) {
if (!active) {
return;
}
try {
if (nodeListener != null) {
Member member = memberAttributeEvent.getMember();
nodeListener.nodeAttributeChanged(member.getUuid(),
memberAttributeEvent.getKey(), memberAttributeEvent.getValue());
}
} catch (Throwable t) {
log.error("Failed to handle memberAttributeChanged", t);
}
}
protected Config getConfig() {
return getDefaultConfig();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy