package cz.cuni.mff.d3s.been.cluster.context;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import com.hazelcast.client.HazelcastClient;
import com.hazelcast.config.Config;
import com.hazelcast.core.*;
import cz.cuni.mff.d3s.been.cluster.NodeType;
import cz.cuni.mff.d3s.been.core.service.ServiceInfo;
/**
* Utility class for often used Hazelcast functions.
*
* @author Martin Sixta
*/
public class ClusterContext {
/** utility class for Hazelcast maps manipulation */
private final Maps maps;
/** utility class for host runtimes handling */
private final Runtimes runtimes;
/** utility class for tasks */
private final Tasks tasks;
/** utility class for task contexts */
private final TaskContexts taskContexts;
/** utility class for Hazelcast topics handling */
private final Topics topics;
/** utility class for BEEN services */
private final Services services;
/** utility class for dealing with benchmarks */
private final Benchmarks benchmarks;
/** utility class for persistence */
private final Persistence persistence;
/** the current Hazelcast node instance */
private final HazelcastInstance hcInstance;
/** does this cluster context use a HazelcastClient instead of a full node? */
private final boolean usesHazelcastClient;
/** configurable properties */
private final Properties properties;
/** scheduler for running periodic jobs */
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
/**
* Default constructor, creates a BEEN cluster context instance with the
* specified instance of Hazelcast and the specified configurable properties.
*
* @param hcInstance
* the Hazelcast instance to use
* @param properties
* the properties to use
*/
public ClusterContext(HazelcastInstance hcInstance, Properties properties) {
this.hcInstance = hcInstance;
this.properties = properties;
this.maps = new Maps(this);
this.runtimes = new Runtimes(this);
this.tasks = new Tasks(this);
this.taskContexts = new TaskContexts(this);
this.topics = new Topics(this);
this.services = new Services(this);
this.benchmarks = new Benchmarks(this);
this.persistence = new Persistence(this);
if (hcInstance instanceof HazelcastClient) {
this.usesHazelcastClient = true;
} else {
usesHazelcastClient = false;
}
}
/**
* Returns a Hazelcast latch with the specified name. If such a latch does not
* exist, it will be created.
*
* @param name
* name of the latch
* @return the latch with the specified name
*/
public ICountDownLatch getCountDownLatch(String name) {
return getInstance().getCountDownLatch(name);
}
/**
* Returns the instance of the {@link Tasks} utility class.
*
* @return the tasks utility class
*/
public Tasks getTasks() {
return tasks;
}
/**
* Returns the instance of the {@link TaskContexts} utility class.
*
* @return the task contexts utility class
*/
public TaskContexts getTaskContexts() {
return taskContexts;
}
/**
* Returns an instance of the {@link Maps} utility class.
*
* @return the maps utility class
*/
public Maps getMaps() {
return maps;
}
/**
* Returns an instance of the {@link Runtimes} utility class.
*
* @return the runtimes utility class
*/
public Runtimes getRuntimes() {
return runtimes;
}
/**
* Returns an instance of the {@link Topics} utility class.
*
* @return the topics utility class
*/
public Topics getTopics() {
return topics;
}
/**
* Returns an instance of the {@link Benchmarks} utility class.
*
* @return the benchmarks utility class
*/
public Benchmarks getBenchmarks() {
return benchmarks;
}
/**
* Returns an instance of the {@link Services} utility class.
*
* @return the services utility class
*/
public Services getServices() {
return services;
}
/**
* Returns an instance of the {@link Persistence} utility class.
*
* @return the persistence utility class
*/
public Persistence getPersistence() {
return persistence;
}
/**
* Returns the currently used Hazelcast instance that works as a connection to
* the BEEN cluster.
*
* @return the current Hazelcast instance
*/
public HazelcastInstance getInstance() {
return hcInstance;
}
/**
* Set of current members of the cluster. Returning set instance is not
* modifiable. Every member in the cluster has the same member list in the
* same order. First member is the oldest member.
*
* @return current members of the cluster
*/
public Set<Member> getMembers() {
return getInstance().getCluster().getMembers();
}
/**
* Returns type of the current instance
*
* @return instance type
*/
public NodeType getInstanceType() {
return cz.cuni.mff.d3s.been.cluster.Instance.getNodeType();
}
/**
* Returns the InetSocketAddress of this node.
* <p/>
* In case of DATA/LITE member it's the address the node is connected to the
* cluster.
* <p/>
* In case of a NATIVE node hostname with 0 port is returned.
*
* @return InetSocketAddress Of the cluster member or hostname of a native
* client
*/
public InetSocketAddress getInetSocketAddress() {
if (getInstanceType() == NodeType.NATIVE) {
try {
return new InetSocketAddress(InetAddress.getLocalHost(), 0);
} catch (UnknownHostException e) {
e.printStackTrace();
return new InetSocketAddress("localhost", 0);
}
} else {
return getCluster().getLocalMember().getInetSocketAddress();
}
}
/**
* Returns the Hazelcast {@link Cluster} object that represents the currently
* connected cluster.
*
* @return the cluster object
*/
public Cluster getCluster() {
return getInstance().getCluster();
}
/**
* Returns the Hazelcast {@link ClientService} object that offers services for
* handling client connections and disconnections.
*
* @return the client service object
*/
public ClientService getClientService() {
return getInstance().getClientService();
}
/**
* Returns a Hazelcast queue with the specified name. If such a queue does not
* exist, it will be created.
*
* @param name
* name of the queue
* @param <E>
* type of the queue items
* @return the queue with the specified name
*/
public <E> IQueue<E> getQueue(String name) {
return getInstance().getQueue(name);
}
/**
* Returns a Hazelcast topic with the specified name. If such a topic does not
* exist, it will be created.
*
* @param name
* name of the topic
* @param <E>
* type of the topic items
* @return the topic with the specified name
*/
public <E> ITopic<E> getTopic(String name) {
return getInstance().getTopic(name);
}
/**
* Returns a Hazelcast map with the specified name. If such a map does not
* exist, it will be created.
*
* @param name
* name of the map
* @param <K>
* type of the map keys
* @param <V>
* type of the map values
* @return the map with the specified name
*/
public <K, V> IMap<K, V> getMap(String name) {
return getInstance().getMap(name);
}
/**
* Returns a Hazelcast multimap with the specified name. If such a multimap
* does not exist, it will be created.
*
* @param name
* name of the multimap
* @param <K>
* type of the multimap keys
* @param <V>
* type of the multimap values
* @return the multimap with the specified name
*/
public <K, V> MultiMap<K, V> getMultiMap(String name) {
return getInstance().getMultiMap(name);
}
/**
* Returns a Hazelcast list with the specified name. If such a list does not
* exist, it will be created.
*
* @param name
* name of the list
* @param <E>
* type of the list items
* @return the list with the specified name
*/
public <E> IList<E> getList(String name) {
return getInstance().getList(name);
}
/**
* Returns the Hazelcast transaction object for the current thread.
*
* @return the transaction object
*/
public Transaction getTransaction() {
return getInstance().getTransaction();
}
/**
* Returns a Hazelcast atomic number with the specified name. If such an
* atomic number does not exist, it will be created.
*
* @param name
* the name of the atomic number
* @return the atomic number with the specified name
*/
public AtomicNumber getAtomicNumber(String name) {
return getInstance().getAtomicNumber(name);
}
/**
* Returns all queue, map, set, list, topic, lock, multimap instances created
* by Hazelcast.
*
* @return the collection of instances created by Hazelcast.
*/
public Collection<Instance> getInstances() {
return getInstance().getInstances();
}
/**
* Returns instances of specified type created by Hazelcast.
*
* @param instanceType
* the type of the instances to list
* @return the collection of instances of specified type created by Hazelcast.
*/
public Collection<Instance> getInstances(Instance.InstanceType instanceType) {
Collection<Instance> instances = new ArrayList<>();
for (Instance instance : getInstances()) {
if (instance.getInstanceType() == instanceType) {
instances.add(instance);
}
}
return instances;
}
/**
* Checks for existence of an instance (queue, map, set, list, topic, lock,
* multimap).
*
* @param instanceType
* type of the instance
* @param name
* name of the instance
* @return true if the instance exists, false otherwise
*/
public boolean containsInstance(Instance.InstanceType instanceType, String name) {
for (Instance instance : getInstances(instanceType)) {
boolean isName = instance.getId().toString().endsWith(":" + name);
if (isName) {
return true;
}
}
return false;
}
/**
* Returns the configuration of this Hazelcast instance.
*
* @return configuration of this Hazelcast instance
*/
public Config getConfig() {
return getInstance().getConfig();
}
/**
* Registers a service.
*
* @param serviceInfo
* service info object to be registered
* @param ttlSeconds
* the time-to-live in seconds after which the entry in the map
* should be evicted
*/
// TODO: check for concurency issues
public void storeServiceInfo(ServiceInfo serviceInfo, int ttlSeconds) {
services.getServicesMap().put(serviceInfo.getServiceName(), serviceInfo, ttlSeconds, TimeUnit.SECONDS);
}
/**
* Un-registers a service.
*
* @param serviceInfo
* service info object to be unregistered
*/
// TODO: check for concurency issues
public void removeServiceInfo(ServiceInfo serviceInfo) {
services.getServicesMap().remove(serviceInfo.getServiceName());
}
/**
* Returns a new cluster-wide unique ID from the generator with the specified
* name.
*
* @param key
* name of the ID generator to use
* @return newly created ID
*/
public long generateId(String key) {
return getInstance().getIdGenerator(key).newId();
}
/**
* Checks whether the connection to the cluster is active.
*
* @return true if the connection is active, false otherwise
*/
public boolean isActive() {
if (usesHazelcastClient) {
return ((HazelcastClient) hcInstance).isActive();
}
// Otherwise hcInstance is member of cluster, so
// ClusterCTX is connected to cluster by default
return true;
}
/**
* Get BEEN configuration properties.
*
* @return BEEN properties
*/
public Properties getProperties() {
return new Properties(properties);
}
/**
* Schedules a runnable job to be run at a periodic interval.
*
* @param runnable
* the runnable job to be scheduled
* @param initialDelay
* initial delay before the job will be run for the first time
* @param period
* the period after which the job will be run again
* @param timeUnit
* the time unit in which the period and delay are represented
*/
public void schedule(Runnable runnable, int initialDelay, int period, TimeUnit timeUnit) {
scheduler.scheduleAtFixedRate(runnable, initialDelay, period, timeUnit);
}
/**
* Stops the scheduler and all scheduled tasks.
*/
public void stop() {
if (!scheduler.isShutdown()) {
scheduler.shutdown();
}
}
}