package eu.europeana.cloud.client.uis.rest.zookeeper;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.curator.utils.EnsurePath;
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;
/**
*
* Enables and constantly monitors the communication with Zookeeper by managing
* a connection to the ZooKeeper ensemble.
*
* @author emmanouil.koufakis@theeuropeanlibrary.org
*
*/
public class ZookeeperService {
/** Logging */
private static final Logger LOGGER = LoggerFactory.getLogger(ZookeeperService.class);
/** Enables and constantly monitors the communication with the ZooKeeper ensemble. */
private final CuratorFramework curatorFramework;
private final static int ZOOKEEPER_CONNECTION_TIMEOUT = 60000;
private final static int ZOOKEEPER_SESSION_TIMEOUT = 60000;
private final ServiceFinder serviceFinder;
/**
* If the connection is temporarily lost, Curator will attempt to retry the operation
* until it succeeds per the currently set retry policy.
*/
private final static RetryPolicy ZOOKEEPER_RETRY_POLICY = new ExponentialBackoffRetry( 1000, 3 );
public ZookeeperService() throws IOException {
LOGGER.info("ZookeeperService starting...");
final String zookeeperAddress = getZookeeperAddress();
LOGGER.info("ZookeeperService using Zookeeper Address='{}'", zookeeperAddress);
final String zNode = getZookeeperZNode();
LOGGER.info("ZookeeperService using zookeeper zNode='{}'", zNode);
curatorFramework = CuratorFrameworkFactory.builder()
.connectionTimeoutMs(ZOOKEEPER_CONNECTION_TIMEOUT)
.retryPolicy(ZOOKEEPER_RETRY_POLICY)
.sessionTimeoutMs(ZOOKEEPER_SESSION_TIMEOUT)
.connectString(zookeeperAddress).build();
curatorFramework.start();
// ZooKeeper paths must be explicitly created
// Let's make sure the path exists
try {
new EnsurePath(zNode).ensure(curatorFramework.getZookeeperClient());
} catch (final Exception e) {
LOGGER.error("ZooKeeper zNode='{}' not found... Exception='{}'", zNode, e.getMessage());
throw Throwables.propagate(e);
}
serviceFinder = new ServiceFinder(curatorFramework
, new JsonInstanceSerializer<ServiceProperties>(ServiceProperties.class)
, zNode);
LOGGER.info("ZookeeperService started successfully.");
}
public ServiceFinder getServiceFinder() {
return serviceFinder;
}
/**
* @return reads the Zookeeper Address from the property file.
*/
private String getZookeeperAddress() throws IOException {
Properties props = new Properties();
InputStream is = null;
try {
is = new FileInputStream(new File("src/main/resources/client.properties"));
props.load(is);
return props.getProperty("zookeeper.URL");
} catch (IOException e) {
LOGGER.error(e.getMessage());
} finally {
if (is != null) {
is.close();
}
}
return null;
}
/**
* @return reads the default Zookeeper zNode from the property file.
*/
private String getZookeeperZNode() throws IOException {
Properties props = new Properties();
InputStream is = null;
try {
is = new FileInputStream(new File("src/main/resources/client.properties"));
props.load(is);
return props.getProperty("zookeeper.ZNODE");
} catch (IOException e) {
LOGGER.error(e.getMessage());
} finally {
if (is != null) {
is.close();
}
}
return null;
}
}