org.apache.slider.core.zk.ZKIntegration.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.slider.core.zk.ZKIntegration.java

Source

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 *  or more contributor license agreements.  See the NOTICE file
 *  distributed with this work for additional information
 *  regarding copyright ownership.  The ASF 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 org.apache.slider.core.zk;

import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooDefs;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.data.ACL;
import org.apache.zookeeper.data.Stat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.Closeable;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;

public class ZKIntegration implements Watcher, Closeable {

    /**
     * Base path for services
     */
    public static String ZK_SERVICES = "services";
    /**
     * Base path for all Slider references
     */
    public static String ZK_SLIDER = "slider";
    public static String ZK_USERS = "users";
    public static String SVC_SLIDER = "/" + ZK_SERVICES + "/" + ZK_SLIDER;
    public static String SVC_SLIDER_USERS = SVC_SLIDER + "/" + ZK_USERS;

    public static final List<String> ZK_USERS_PATH_LIST = new ArrayList<String>();
    static {
        ZK_USERS_PATH_LIST.add(ZK_SERVICES);
        ZK_USERS_PATH_LIST.add(ZK_SLIDER);
        ZK_USERS_PATH_LIST.add(ZK_USERS);
    }

    public static int SESSION_TIMEOUT = 5000;
    protected static final Logger log = LoggerFactory.getLogger(ZKIntegration.class);
    private ZooKeeper zookeeper;
    private final String username;
    private final String clustername;
    private final String userPath;
    private int sessionTimeout = SESSION_TIMEOUT;
    /**
     flag to set to indicate that the user path should be created if
     it is not already there
     */
    private final AtomicBoolean toInit = new AtomicBoolean(false);
    private final boolean createClusterPath;
    private final Watcher watchEventHandler;
    private final String zkConnection;
    private final boolean canBeReadOnly;

    protected ZKIntegration(String zkConnection, String username, String clustername, boolean canBeReadOnly,
            boolean createClusterPath, Watcher watchEventHandler) throws IOException {
        this.username = username;
        this.clustername = clustername;
        this.watchEventHandler = watchEventHandler;
        this.zkConnection = zkConnection;
        this.canBeReadOnly = canBeReadOnly;
        this.createClusterPath = createClusterPath;
        this.userPath = mkSliderUserPath(username);
    }

    public void init() throws IOException {
        assert zookeeper == null;
        log.debug("Binding ZK client to {}", zkConnection);
        zookeeper = new ZooKeeper(zkConnection, sessionTimeout, this, canBeReadOnly);
    }

    /**
     * Create an instance bonded to the specific closure
     * @param zkConnection
     * @param username
     * @param clustername
     * @param canBeReadOnly
     * @param watchEventHandler
     * @return
     * @throws IOException
     */
    public static ZKIntegration newInstance(String zkConnection, String username, String clustername,
            boolean createClusterPath, boolean canBeReadOnly, Watcher watchEventHandler) throws IOException {

        return new ZKIntegration(zkConnection, username, clustername, canBeReadOnly, createClusterPath,
                watchEventHandler);
    }

    @Override
    public synchronized void close() throws IOException {
        if (zookeeper != null) {
            try {
                zookeeper.close();
            } catch (InterruptedException ignored) {

            }
            zookeeper = null;
        }
    }

    public String getConnectionString() {
        return zkConnection;
    }

    public String getClusterPath() {
        return mkClusterPath(username, clustername);
    }

    public boolean getConnected() {
        return zookeeper.getState().isConnected();
    }

    public boolean getAlive() {
        return zookeeper.getState().isAlive();
    }

    public ZooKeeper.States getState() {
        return zookeeper.getState();
    }

    public Stat getClusterStat() throws KeeperException, InterruptedException {
        return stat(getClusterPath());
    }

    public boolean exists(String path) throws KeeperException, InterruptedException {
        return stat(path) != null;
    }

    public Stat stat(String path) throws KeeperException, InterruptedException {
        return zookeeper.exists(path, false);
    }

    @Override
    public String toString() {
        return "ZK integration bound @  " + zkConnection + ": " + zookeeper;
    }

    /**
     * Event handler to notify of state events
     * @param event
     */
    @Override
    public void process(WatchedEvent event) {
        log.debug("{}", event);
        try {
            maybeInit();
        } catch (Exception e) {
            log.error("Failed to init", e);
        }
        if (watchEventHandler != null) {
            watchEventHandler.process(event);
        }
    }

    private void maybeInit() throws KeeperException, InterruptedException {
        if (!toInit.getAndSet(true) && createClusterPath) {
            log.debug("initing");
            //create the user path
            mkPath(ZK_USERS_PATH_LIST, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
            //create the specific user
            createPath(userPath, null, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
        }
    }

    /**
     * Create a path under a parent, don't care if it already exists
     * As the path isn't returned, this isn't the way to create sequentially
     * numbered nodes.
     * @param parent parent dir. Must have a trailing / if entry!=null||empty 
     * @param entry entry -can be null or "", in which case it is not appended
     * @param acl
     * @param createMode
     * @return the path if created; null if not
     */
    public String createPath(String parent, String entry, List<ACL> acl, CreateMode createMode)
            throws KeeperException, InterruptedException {
        //initial create of full path
        assert acl != null;
        assert !acl.isEmpty();
        assert parent != null;
        String path = parent;
        if (entry != null) {
            path = path + entry;
        }
        try {
            log.debug("Creating ZK path {}", path);
            return zookeeper.create(path, null, acl, createMode);
        } catch (KeeperException.NodeExistsException ignored) {
            //node already there
            log.debug("node already present:{}", path);
            return null;
        }
    }

    /**
     * Recursive path create
     * @param path
     * @param data
     * @param acl
     * @param createMode
     */
    public void mkPath(List<String> paths, List<ACL> acl, CreateMode createMode)
            throws KeeperException, InterruptedException {
        String history = "/";
        for (String entry : paths) {
            createPath(history, entry, acl, createMode);
            history = history + entry + "/";
        }
    }

    /**
     * Blocking enum of users
     * @return an unordered list of clusters under a user
     */
    public List<String> getClusters() throws KeeperException, InterruptedException {
        return zookeeper.getChildren(userPath, null);
    }

    /**
     * Delete a node, does not throw an exception if the path is not fond
     * @param path path to delete
     * @return true if the path could be deleted, false if there was no node to delete 
     *
     */
    public boolean delete(String path) throws InterruptedException, KeeperException {
        try {
            zookeeper.delete(path, -1);
            log.debug("Deleting {}", path);
            return true;
        } catch (KeeperException.NoNodeException ignored) {
            return false;
        }
    }

    /**
     * Recursively delete a node, does not throw exception if any node does not exist.
     * @param path
     * @return true if delete was successful
     */
    public boolean deleteRecursive(String path) throws KeeperException, InterruptedException {

        try {
            List<String> children = zookeeper.getChildren(path, false);
            for (String child : children) {
                deleteRecursive(path + "/" + child);
            }
            delete(path);
        } catch (KeeperException.NoNodeException ignored) {
            return false;
        }

        return true;
    }

    /**
    * Build the path to a cluster; exists once the cluster has come up.
    * Even before that, a ZK watcher could wait for it.
    * @param username user
    * @param clustername name of the cluster
    * @return a strin
    */
    public static String mkClusterPath(String username, String clustername) {
        return mkSliderUserPath(username) + "/" + clustername;
    }

    /**
     * Build the path to a cluster; exists once the cluster has come up.
     * Even before that, a ZK watcher could wait for it.
     * @param username user
     * @return a string
     */
    public static String mkSliderUserPath(String username) {
        return SVC_SLIDER_USERS + "/" + username;
    }

}