package eu.europeana.cloud.service.coordination.discovery; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List; import org.apache.curator.x.discovery.ServiceCache; import org.apache.curator.x.discovery.ServiceDiscovery; import org.apache.curator.x.discovery.ServiceDiscoveryBuilder; import org.apache.curator.x.discovery.ServiceInstance; import org.apache.curator.x.discovery.ServiceProvider; import org.apache.curator.x.discovery.details.InstanceSerializer; import org.apache.curator.x.discovery.details.JsonInstanceSerializer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.base.Throwables; import eu.europeana.cloud.service.coordination.ServiceProperties; import eu.europeana.cloud.service.coordination.ZookeeperService; /** * Asks Zookeeper for available services. * * ZooKeeper is used for service discovery: * * Services are registered on a common znode, and any client can query Zookeeper * for a list of available services. * * @author emmanouil.koufakis@theeuropeanlibrary.org */ public class ZookeeperServiceDiscovery implements EcloudServiceDiscovery { /** Type of service to search for, e.g UIS. */ private final String serviceType; /** Service that actually performs the discovery. */ private final ServiceDiscovery<ServiceProperties> discovery; /** Logging */ private static final Logger LOGGER = LoggerFactory.getLogger(ZookeeperServiceDiscovery.class); private final ServiceCache<ServiceProperties> cache; /** * @param zookeeper service that provides the connection with Zookeeper. * @param serviceType Type of service to search for, e.g UIS. */ public ZookeeperServiceDiscovery(final ZookeeperService zookeeper, final String discoveryPath, final String serviceType) { this.serviceType = serviceType; final InstanceSerializer<ServiceProperties> instanceSerializer = new JsonInstanceSerializer<ServiceProperties>(ServiceProperties.class); discovery = ServiceDiscoveryBuilder.builder(ServiceProperties.class) .basePath(zookeeper.getZookeeperPath() + discoveryPath) .client(zookeeper.getClient()) .serializer(instanceSerializer) .build(); cache = discovery.serviceCacheBuilder().name(serviceType).build(); try { cache.start(); discovery.start(); } catch (final Exception e) { LOGGER.error("ZookeeperServiceDiscovery error starting the service.. {}", e.getMessage()); throw Throwables.propagate(e); } } @Override public List<ServiceProperties> getServices() { try { ServiceProvider<ServiceProperties> serviceProvider = discovery.serviceProviderBuilder() .serviceName(serviceType) .build(); serviceProvider.start(); Collection<ServiceInstance<ServiceProperties>> serviceInstances = serviceProvider.getAllInstances(); List<ServiceProperties> services = new ArrayList<ServiceProperties>(); for(Iterator<ServiceInstance<ServiceProperties>> i = serviceInstances.iterator(); i.hasNext(); ) { services.add(i.next().getPayload()); } return services; } catch (Exception e) { LOGGER.error(e.getMessage()); throw Throwables.propagate(e); } } private Collection<ServiceInstance<ServiceProperties>> getServiceInstances(final String serviceName) { Collection<ServiceInstance<ServiceProperties>> instances; try { instances = discovery.queryForInstances(serviceName); final int servicesDiscoveredCount = instances.size(); LOGGER.info("Found '{}' services: {} .", servicesDiscoveredCount, instances); } catch (Exception e) { LOGGER.error(e.getMessage()); throw Throwables.propagate(e); } return instances; } }