/** * Licensed to Cloudera, Inc. under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. Cloudera, Inc. licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.cloudera.flume.master; import java.io.IOException; import org.apache.zookeeper.server.quorum.QuorumPeerConfig.ConfigException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.cloudera.flume.conf.FlumeConfiguration; /** * This class provides a singleton interface to a ZooKeeper ensemble, supporting * either in-process or external ZK servers. */ public class ZooKeeperService { static final Logger LOG = LoggerFactory.getLogger(ZooKeeperService.class); boolean external; ZKInProcessServer zk = null; boolean initialised = false; // A string of hostname:clientport:electionport tuples String serverAddr = null; // The string to use to connect clients to this service String clientAddr = null; // The singleton ZooKeeperService final static ZooKeeperService zkServiceSingleton = new ZooKeeperService(); /** * Reads startup parameters from a configuration file and does one of the * following: * * 1. start a standalone, in-process server * * 2. start an in-process server that's part of an ensemble * * 3. does nothing, as the service is a proxy for an entirely external cluster * * If called twice in succession, the second call will do nothing. */ synchronized protected void init(FlumeConfiguration cfg) throws IOException, InterruptedException { if (initialised) { return; } serverAddr = cfg.getMasterZKServers(); clientAddr = cfg.getMasterZKConnectString(); external = true; if (!cfg.getMasterZKUseExternal()) { external = false; if (cfg.getMasterIsDistributed()) { try { startZKDistributed(cfg); } catch (ConfigException e) { throw new IOException("Couldn't parse ZooKeeper configuration", e); } } else { int port = cfg.getMasterZKClientPort(); String dir = cfg.getMasterZKLogDir(); startZKStandalone(port, dir); } } initialised = true; } synchronized public boolean isInitialised() { return initialised; } /** * Initialises in standalone mode, creating an in-process ZK. */ protected void startZKStandalone(int port, String dir) throws IOException, InterruptedException { LOG.info("Starting standalone ZooKeeper instance on port " + port); zk = new ZKInProcessServer(port, dir); zk.start(); } /** * Initialises in distributed mode, starting an in-process server */ protected void startZKDistributed(FlumeConfiguration cfg) throws IOException, InterruptedException, ConfigException { LOG.info("Starting ZooKeeper server as part of ensemble"); zk = new ZKInProcessServer(cfg); zk.start(); } /** * Returns the singleton ZooKeeperService, which will not be null. However, it * may not be initialised and therefore attempts to connect to it with a * ZKClient may fail. Use getAndInit if you are not sure whether the service * is initialised. */ static public ZooKeeperService get() { return zkServiceSingleton; } /** * Returns the singleton ZooKeeperService, initialising it if it has not been * initialised already. */ synchronized public static ZooKeeperService getAndInit() throws IOException, InterruptedException { zkServiceSingleton.init(FlumeConfiguration.get()); return zkServiceSingleton; } /** * Returns the singleton ZooKeeperService, initialising it if it has not been * initialised already, using the supplied configuration */ synchronized public static ZooKeeperService getAndInit(FlumeConfiguration cfg) throws IOException, InterruptedException { zkServiceSingleton.init(cfg); return zkServiceSingleton; } /** * Returns a new ZKClient initialised for this service, but not connected. */ synchronized public ZKClient createClient() throws IOException { if (!initialised) { throw new IOException("Not yet initialised!"); } return new ZKClient(clientAddr); } /** * Shuts down any in-process ZooKeeper instance */ synchronized public void shutdown() { if (!initialised) { return; } if (!external && this.zk != null) { this.zk.stop(); } this.zk = null; this.initialised = false; } }