/** * Copyright 2014 Comcast Cable Communications Management, LLC * * Licensed 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.comcast.viper.flume2storm.zookeeper; import java.util.LinkedList; import java.util.List; import org.apache.commons.lang.StringUtils; import org.apache.zookeeper.CreateMode; import org.apache.zookeeper.KeeperException; import org.apache.zookeeper.Watcher; import org.apache.zookeeper.ZooKeeper; import org.apache.zookeeper.data.Stat; import com.google.common.base.Preconditions; /** * Wrapper around {@link ZooKeeper} and {@link ZkClient} to provide a safety net * and some convenience methods. For any operation, {@link #with(ZkClient)} and * {@link #path(String)} setters must be invoked, otherwise an exception will be * thrown */ @SuppressWarnings("javadoc") public class ZkOperation { private ZkClient zkClient; private String path; // // Construction, setters, utilities // /** * @return A newly created {@link ZkOperation} */ public static ZkOperation get() { return new ZkOperation(); } public ZkOperation() { } public ZkOperation(final ZkClient zkClient, final String path) { this.zkClient = zkClient; this.path = path; } public ZkOperation with(final ZkClient zkClient) { this.zkClient = zkClient; return this; } public ZkOperation path(final String path) { this.path = path; return this; } protected String getNsPath() { Preconditions.checkNotNull(zkClient, "No ZkClient specified"); Preconditions.checkNotNull(path, "No ZooKeeper paty specified"); return ZkUtilies.buildZkPath(path); } protected ZooKeeper getZooKeeper() { Preconditions.checkState(zkClient.getState().isConnected(), "Not connected to ZooKeeper server"); final ZooKeeper result = zkClient.getZooKeeper(); Preconditions.checkState(result != null, "Failed to get ZooKeeper instance"); return result; } // // Node management // /** * @see ZooKeeper#exists(String, boolean) * * @return True if the specified ZNode exists, false otherwise * * @throws KeeperException * If a ZooKeeper exception occurred * @throws InterruptedException * If the synchronous operation was interrupted * @throws IllegalStateException * If not connected to the ZooKeeper server * @throws IllegalArgumentException * If the arguments provided to this operation are invalid */ public boolean nodeExists() throws KeeperException, InterruptedException { return getZooKeeper().exists(getNsPath(), false) != null; } /** * Creates a ZooKeeper node * * @see ZooKeeper#create(String, byte[], List, CreateMode) * * @param args * Node creation arguments * @return The path of the node if created, or null otherwise * * @throws KeeperException * If a ZooKeeper exception occurred * @throws InterruptedException * If the synchronous operation was interrupted * @throws IllegalStateException * If not connected to the ZooKeeper server * @throws IllegalArgumentException * If the arguments provided to this operation are invalid */ public String createNode(final ZkNodeCreationArg args) throws KeeperException, InterruptedException { if (!args.isCreateHierarchy()) { return getZooKeeper().create(getNsPath(), args.getData(), args.getAcl(), args.getCreateMode()); } final String[] pathElement = StringUtils.split(getNsPath(), ZkUtilies.SEPARATOR); Preconditions.checkArgument(pathElement.length > 0, "Invalid path: empty"); String tmpPath = StringUtils.EMPTY; final ZkOperation zkOp = new ZkOperation().with(zkClient); // For all parent nodes: for (int i = 0; i < pathElement.length - 1; i++) { tmpPath = ZkUtilies.buildZkPath(tmpPath, pathElement[i]); if (!zkOp.path(tmpPath).nodeExists()) { zkOp.createNode(new ZkNodeCreationArg().setAcl(args.getAcl())); } } // Leaf node if (!nodeExists()) { return createNode(new ZkNodeCreationArg(args).setCreateHierarchy(false)); } return path; } /** * @see ZooKeeper#delete(String, int) * * @param version * * @throws KeeperException * If a ZooKeeper exception occurred * @throws InterruptedException * If the synchronous operation was interrupted * @throws IllegalStateException * If not connected to the ZooKeeper server * @throws IllegalArgumentException * If the arguments provided to this operation are invalid */ public void deleteNode(final int version) throws InterruptedException, KeeperException { Preconditions.checkArgument(version >= -1, "Zk node version needs to be positive or equals to -1"); getZooKeeper().delete(getNsPath(), version); } /** * @see ZooKeeper#delete(String, int) * * @throws KeeperException * If a ZooKeeper exception occurred * @throws InterruptedException * If the synchronous operation was interrupted * @throws IllegalStateException * If not connected to the ZooKeeper server * @throws IllegalArgumentException * If the arguments provided to this operation are invalid */ public void deleteNode() throws InterruptedException, KeeperException { deleteNode(-1); } /** * Deletes the specified node and all its children nodes, if any * * @throws KeeperException * If a ZooKeeper exception occurred * @throws InterruptedException * If the synchronous operation was interrupted * @throws IllegalStateException * If not connected to the ZooKeeper server * @throws IllegalArgumentException * If the arguments provided to this operation are invalid */ public void deleteRecursive() throws InterruptedException, KeeperException { final List<String> children = getChildren(); for (final String child : children) { new ZkOperation(zkClient, ZkUtilies.buildZkPath(path, child)).deleteRecursive(); } deleteNode(); } /** * @see ZooKeeper#getChildren(String, Watcher) * * @param watcher * May be null * @return The list of children of the specified path * * @throws KeeperException * If a ZooKeeper exception occurred * @throws InterruptedException * If the synchronous operation was interrupted * @throws IllegalStateException * If not connected to the ZooKeeper server * @throws IllegalArgumentException * If the arguments provided to this operation are invalid */ public List<String> getChildren(final Watcher watcher) throws KeeperException, InterruptedException { if (watcher == null) { return getZooKeeper().getChildren(getNsPath(), false); } return getZooKeeper().getChildren(getNsPath(), watcher); } /** * @see ZooKeeper#getChildren(String, Watcher) * * @return The list of children of the specified path * * @throws KeeperException * If a ZooKeeper exception occurred * @throws InterruptedException * If the synchronous operation was interrupted * @throws IllegalStateException * If not connected to the ZooKeeper server * @throws IllegalArgumentException * If the arguments provided to this operation are invalid */ public List<String> getChildren() throws KeeperException, InterruptedException { return getChildren(null); } /** * @return A list of the specified node and all its children nodes * * @throws KeeperException * If a ZooKeeper exception occurred * @throws InterruptedException * If the synchronous operation was interrupted * @throws IllegalStateException * If not connected to the ZooKeeper server * @throws IllegalArgumentException * If the arguments provided to this operation are invalid */ public List<String> getChildrenRecursiveList() throws InterruptedException, KeeperException { final List<String> result = new LinkedList<String>(); result.add(path); for (final String child : getChildren()) { result.addAll(new ZkOperation(zkClient, ZkUtilies.buildZkPath(path, child)).getChildrenRecursiveList()); } return result; } /** * @see ZooKeeper#getData(String, Watcher, org.apache.zookeeper.data.Stat) * * @param watcher * May be null * @param stat * @return The contained by the node of the specified path * * @throws KeeperException * If a ZooKeeper exception occurred * @throws InterruptedException * If the synchronous operation was interrupted * @throws IllegalStateException * If not connected to the ZooKeeper server * @throws IllegalArgumentException * If the arguments provided to this operation are invalid */ public byte[] getData(final Watcher watcher, final Stat stat) throws KeeperException, InterruptedException { if (watcher == null) { return getZooKeeper().getData(getNsPath(), false, stat); } return getZooKeeper().getData(getNsPath(), watcher, stat); } /** * @see ZooKeeper#getData(String, Watcher, org.apache.zookeeper.data.Stat) * (String, Watcher) * * @return The contained by the node of the specified path * * @throws KeeperException * If a ZooKeeper exception occurred * @throws InterruptedException * If the synchronous operation was interrupted * @throws IllegalStateException * If not connected to the ZooKeeper server * @throws IllegalArgumentException * If the arguments provided to this operation are invalid */ public byte[] getData() throws KeeperException, InterruptedException { return getData(null, new Stat()); } }