package cloudone.cumulonimbus;
import cloudone.ServiceFullName;
import cloudone.cumulonimbus.model.Cluster;
import cloudone.cumulonimbus.model.RegisteredRuntime;
import cloudone.cumulonimbus.persistence.ServiceRegistryPersistence;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
/**
* Catalogue of registered services.
*
* @author Martin Mares (martin.mares at oracle.com)
*/
public class ServiceRegistryService {
public interface RegistrationListener {
/** Service runtime instance is about to register.
*
* @param runtime which is about to register.
* @param cluster with other registered instances.
* @throws Exception in case that it is not possible to register such instance.
*/
public void register(RegisteredRuntime runtime, Cluster cluster) throws Exception;
/** This service runtime instance was unregistered.
*
* @param runtime which is unregistered.
* @param cluster from which this instance was unregistered.
*/
public void unregister(RegisteredRuntime runtime, Cluster cluster);
}
private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(ServiceRegistryService.class);
private static final String FILE_NAME = "appregistry.json";
private static ServiceRegistryService INSTANCE;
private final ConcurrentMap<ServiceFullName, Cluster> registry = new ConcurrentHashMap<>();
private final ConcurrentMap<String, RegisteredRuntime> secRegistry = new ConcurrentHashMap<>();
private final List<RegistrationListener> listeners = Collections.synchronizedList(new ArrayList<RegistrationListener>());
ServiceRegistryService() {
}
private void fireRegister(final RegisteredRuntime runtime, final Cluster cluster) throws Exception {
final List<RegistrationListener> passListeners = new ArrayList<>(listeners.size());
try {
for (RegistrationListener listener : listeners) {
listener.register(runtime, cluster);
passListeners.add(listener);
}
} catch (Exception exc) {
fireUnRegister(runtime, cluster, passListeners);
throw exc;
}
}
private void fireUnRegister(final RegisteredRuntime runtime,
final Cluster cluster,
final List<RegistrationListener> listeners) {
for (RegistrationListener listener : listeners) {
try {
listener.unregister(runtime, cluster);
} catch (RuntimeException re) {
LOGGER.warn("Exception during unregistration of " + runtime.toRuntimeName() + " from " + listener, re);
}
}
}
private void fireUnRegister(final RegisteredRuntime runtime, final Cluster cluster) {
fireUnRegister(runtime, cluster, this.listeners);
}
public void addRegistrationListener(RegistrationListener listener) {
listeners.add(listener);
}
public RegisteredRuntime register(ServiceFullName fullName,
int adminPort,
Map<String, Integer> applicationPorts) throws Exception {
final Cluster cluster = registry.computeIfAbsent(fullName, fn -> new Cluster(fn));
final RegisteredRuntime result = cluster.register(adminPort, applicationPorts);
try {
fireRegister(result, cluster);
} catch (Exception e) {
//Remove from registry
cluster.unRegister(result);
if (cluster.getRuntimes().isEmpty()) {
registry.remove(result.getServiceName());
}
LOGGER.warn("Can not accept service registration!", e);
throw e;
}
secRegistry.put(result.getInstanceSecCode(), result);
LOGGER.info("REGISTERED: " + result.toRuntimeName());
return result;
}
public boolean unregister(RegisteredRuntime runtime) {
if (runtime == null) {
return false;
}
Cluster cluster = registry.get(runtime.getServiceName());
if (cluster != null) {
if (cluster.unRegister(runtime)) {
if (cluster.getRuntimes().size() == 0) {
registry.remove(cluster.getFullName());
}
fireUnRegister(runtime, cluster);
LOGGER.info("UNREGISTERED: " + runtime.toRuntimeName());
return true;
}
}
return false;
}
private void registerClusterInternal(Cluster cluster) throws Exception {
if (registry.putIfAbsent(cluster.getFullName(), cluster) != null) {
throw new Exception("Cluster " + cluster.getFullName() + " allready registered");
}
for (RegisteredRuntime runtime : cluster.getRuntimes()) {
fireRegister(runtime, cluster);
}
}
public Collection<Cluster> getClusters() {
return Collections.unmodifiableCollection(registry.values());
}
public Cluster getCluster(ServiceFullName name) {
if (name == null) {
return null;
}
return registry.get(name);
}
public RegisteredRuntime getRuntime(String secCode) {
return secRegistry.get(secCode);
}
public static ServiceRegistryService getInstance() {
return INSTANCE;
}
static ServiceRegistryService init(final File dir, final RegistrationListener... listeners) throws Exception {
final File storeFile = new File(dir, FILE_NAME);
INSTANCE = new ServiceRegistryService();
if (listeners != null) {
for (RegistrationListener listener : listeners) {
INSTANCE.addRegistrationListener(listener);
}
}
//Load from file
ServiceRegistryPersistence serviceRegistryPersistence = new ServiceRegistryPersistence(storeFile, INSTANCE);
for (Cluster cluster : serviceRegistryPersistence.loadClusters()) {
INSTANCE.registerClusterInternal(cluster);
}
INSTANCE.addRegistrationListener(serviceRegistryPersistence);
return INSTANCE;
}
}