All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.zookeeper.ZooKeeper Maven / Gradle / Ivy

There is a newer version: 3.9.3
Show newest version
/*
 * 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.zookeeper;

import java.io.IOException;
import java.lang.reflect.Constructor;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.jute.Record;
import org.apache.yetus.audience.InterfaceAudience;
import org.apache.zookeeper.AsyncCallback.ACLCallback;
import org.apache.zookeeper.AsyncCallback.Children2Callback;
import org.apache.zookeeper.AsyncCallback.ChildrenCallback;
import org.apache.zookeeper.AsyncCallback.Create2Callback;
import org.apache.zookeeper.AsyncCallback.DataCallback;
import org.apache.zookeeper.AsyncCallback.MultiCallback;
import org.apache.zookeeper.AsyncCallback.StatCallback;
import org.apache.zookeeper.AsyncCallback.StringCallback;
import org.apache.zookeeper.AsyncCallback.VoidCallback;
import org.apache.zookeeper.OpResult.ErrorResult;
import org.apache.zookeeper.Watcher.WatcherType;
import org.apache.zookeeper.client.ConnectStringParser;
import org.apache.zookeeper.client.HostProvider;
import org.apache.zookeeper.client.StaticHostProvider;
import org.apache.zookeeper.client.ZKClientConfig;
import org.apache.zookeeper.client.ZooKeeperSaslClient;
import org.apache.zookeeper.common.PathUtils;
import org.apache.zookeeper.data.ACL;
import org.apache.zookeeper.data.ClientInfo;
import org.apache.zookeeper.data.Stat;
import org.apache.zookeeper.proto.AddWatchRequest;
import org.apache.zookeeper.proto.CheckWatchesRequest;
import org.apache.zookeeper.proto.Create2Response;
import org.apache.zookeeper.proto.CreateRequest;
import org.apache.zookeeper.proto.CreateResponse;
import org.apache.zookeeper.proto.CreateTTLRequest;
import org.apache.zookeeper.proto.DeleteRequest;
import org.apache.zookeeper.proto.ErrorResponse;
import org.apache.zookeeper.proto.ExistsRequest;
import org.apache.zookeeper.proto.GetACLRequest;
import org.apache.zookeeper.proto.GetACLResponse;
import org.apache.zookeeper.proto.GetAllChildrenNumberRequest;
import org.apache.zookeeper.proto.GetAllChildrenNumberResponse;
import org.apache.zookeeper.proto.GetChildren2Request;
import org.apache.zookeeper.proto.GetChildren2Response;
import org.apache.zookeeper.proto.GetChildrenRequest;
import org.apache.zookeeper.proto.GetChildrenResponse;
import org.apache.zookeeper.proto.GetDataRequest;
import org.apache.zookeeper.proto.GetDataResponse;
import org.apache.zookeeper.proto.GetEphemeralsRequest;
import org.apache.zookeeper.proto.GetEphemeralsResponse;
import org.apache.zookeeper.proto.RemoveWatchesRequest;
import org.apache.zookeeper.proto.ReplyHeader;
import org.apache.zookeeper.proto.RequestHeader;
import org.apache.zookeeper.proto.SetACLRequest;
import org.apache.zookeeper.proto.SetACLResponse;
import org.apache.zookeeper.proto.SetDataRequest;
import org.apache.zookeeper.proto.SetDataResponse;
import org.apache.zookeeper.proto.SyncRequest;
import org.apache.zookeeper.proto.SyncResponse;
import org.apache.zookeeper.proto.WhoAmIResponse;
import org.apache.zookeeper.server.DataTree;
import org.apache.zookeeper.server.EphemeralType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * This is the main class of ZooKeeper client library. To use a ZooKeeper
 * service, an application must first instantiate an object of ZooKeeper class.
 * All the iterations will be done by calling the methods of ZooKeeper class.
 * The methods of this class are thread-safe unless otherwise noted.
 * 

* Once a connection to a server is established, a session ID is assigned to the * client. The client will send heart beats to the server periodically to keep * the session valid. *

* The application can call ZooKeeper APIs through a client as long as the * session ID of the client remains valid. *

* If for some reason, the client fails to send heart beats to the server for a * prolonged period of time (exceeding the sessionTimeout value, for instance), * the server will expire the session, and the session ID will become invalid. * The client object will no longer be usable. To make ZooKeeper API calls, the * application must create a new client object. *

* If the ZooKeeper server the client currently connects to fails or otherwise * does not respond, the client will automatically try to connect to another * server before its session ID expires. If successful, the application can * continue to use the client. *

* The ZooKeeper API methods are either synchronous or asynchronous. Synchronous * methods blocks until the server has responded. Asynchronous methods just queue * the request for sending and return immediately. They take a callback object that * will be executed either on successful execution of the request or on error with * an appropriate return code (rc) indicating the error. *

* Some successful ZooKeeper API calls can leave watches on the "data nodes" in * the ZooKeeper server. Other successful ZooKeeper API calls can trigger those * watches. Once a watch is triggered, an event will be delivered to the client * which left the watch at the first place. Each watch can be triggered only * once. Thus, up to one event will be delivered to a client for every watch it * leaves. *

* A client needs an object of a class implementing Watcher interface for * processing the events delivered to the client. * * When a client drops the current connection and re-connects to a server, all the * existing watches are considered as being triggered but the undelivered events * are lost. To emulate this, the client will generate a special event to tell * the event handler a connection has been dropped. This special event has * EventType None and KeeperState Disconnected. * */ /* * We suppress the "try" warning here because the close() method's signature * allows it to throw InterruptedException which is strongly advised against * by AutoCloseable (see: http://docs.oracle.com/javase/7/docs/api/java/lang/AutoCloseable.html#close()). * close() will never throw an InterruptedException but the exception remains in the * signature for backwards compatibility purposes. */ @SuppressWarnings("try") @InterfaceAudience.Public public class ZooKeeper implements AutoCloseable { /** * @deprecated Use {@link ZKClientConfig#ZOOKEEPER_CLIENT_CNXN_SOCKET} * instead. */ @Deprecated public static final String ZOOKEEPER_CLIENT_CNXN_SOCKET = "zookeeper.clientCnxnSocket"; // Setting this to "true" will enable encrypted client-server communication. /** * @deprecated Use {@link ZKClientConfig#SECURE_CLIENT} * instead. */ @Deprecated public static final String SECURE_CLIENT = "zookeeper.client.secure"; protected final ClientCnxn cnxn; private static final Logger LOG; static { //Keep these two lines together to keep the initialization order explicit LOG = LoggerFactory.getLogger(ZooKeeper.class); Environment.logEnv("Client environment:", LOG); } protected final HostProvider hostProvider; /** * This function allows a client to update the connection string by providing * a new comma separated list of host:port pairs, each corresponding to a * ZooKeeper server. *

* The function invokes a * probabilistic load-balancing algorithm which may cause the client to disconnect from * its current host with the goal to achieve expected uniform number of connections per server * in the new list. In case the current host to which the client is connected is not in the new * list this call will always cause the connection to be dropped. Otherwise, the decision * is based on whether the number of servers has increased or decreased and by how much. * For example, if the previous connection string contained 3 hosts and now the list contains * these 3 hosts and 2 more hosts, 40% of clients connected to each of the 3 hosts will * move to one of the new hosts in order to balance the load. The algorithm will disconnect * from the current host with probability 0.4 and in this case cause the client to connect * to one of the 2 new hosts, chosen at random. *

* If the connection is dropped, the client moves to a special mode "reconfigMode" where he chooses * a new server to connect to using the probabilistic algorithm. After finding a server, * or exhausting all servers in the new list after trying all of them and failing to connect, * the client moves back to the normal mode of operation where it will pick an arbitrary server * from the connectString and attempt to connect to it. If establishment of * the connection fails, another server in the connect string will be tried * (the order is non-deterministic, as we random shuffle the list), until a * connection is established. The client will continue attempts until the * session is explicitly closed (or the session is expired by the server). * @param connectString * comma separated host:port pairs, each corresponding to a zk * server. e.g. "127.0.0.1:3000,127.0.0.1:3001,127.0.0.1:3002" * If the optional chroot suffix is used the example would look * like: "127.0.0.1:3000,127.0.0.1:3001,127.0.0.1:3002/app/a" * where the client would be rooted at "/app/a" and all paths * would be relative to this root - ie getting/setting/etc... * "/foo/bar" would result in operations being run on * "/app/a/foo/bar" (from the server perspective). * * @throws IOException in cases of network failure */ public void updateServerList(String connectString) throws IOException { ConnectStringParser connectStringParser = new ConnectStringParser(connectString); Collection serverAddresses = connectStringParser.getServerAddresses(); ClientCnxnSocket clientCnxnSocket = cnxn.sendThread.getClientCnxnSocket(); InetSocketAddress currentHost = (InetSocketAddress) clientCnxnSocket.getRemoteSocketAddress(); boolean reconfigMode = hostProvider.updateServerList(serverAddresses, currentHost); // cause disconnection - this will cause next to be called // which will in turn call nextReconfigMode if (reconfigMode) { clientCnxnSocket.testableCloseSocket(); } } public ZooKeeperSaslClient getSaslClient() { return cnxn.getZooKeeperSaslClient(); } private final ZKClientConfig clientConfig; public ZKClientConfig getClientConfig() { return clientConfig; } protected List getDataWatches() { return getWatchManager().getDataWatchList(); } protected List getExistWatches() { return getWatchManager().getExistWatchList(); } protected List getChildWatches() { return getWatchManager().getChildWatchList(); } protected List getPersistentWatches() { return getWatchManager().getPersistentWatchList(); } protected List getPersistentRecursiveWatches() { return getWatchManager().getPersistentRecursiveWatchList(); } ZKWatchManager getWatchManager() { return cnxn.getWatcherManager(); } /** * Register a watcher for a particular path. */ public abstract static class WatchRegistration { private Watcher watcher; private String clientPath; public WatchRegistration(Watcher watcher, String clientPath) { this.watcher = watcher; this.clientPath = clientPath; } protected abstract Map> getWatches(int rc); /** * Register the watcher with the set of watches on path. * @param rc the result code of the operation that attempted to * add the watch on the path. */ public void register(int rc) { if (shouldAddWatch(rc)) { Map> watches = getWatches(rc); synchronized (watches) { Set watchers = watches.get(clientPath); if (watchers == null) { watchers = new HashSet<>(); watches.put(clientPath, watchers); } watchers.add(watcher); } } } /** * Determine whether the watch should be added based on return code. * @param rc the result code of the operation that attempted to add the * watch on the node * @return true if the watch should be added, otw false */ protected boolean shouldAddWatch(int rc) { return rc == KeeperException.Code.OK.intValue(); } } /** Handle the special case of exists watches - they add a watcher * even in the case where NONODE result code is returned. */ class ExistsWatchRegistration extends WatchRegistration { public ExistsWatchRegistration(Watcher watcher, String clientPath) { super(watcher, clientPath); } @Override protected Map> getWatches(int rc) { return rc == KeeperException.Code.OK.intValue() ? getWatchManager().getDataWatches() : getWatchManager().getExistWatches(); } @Override protected boolean shouldAddWatch(int rc) { return rc == KeeperException.Code.OK.intValue() || rc == KeeperException.Code.NONODE.intValue(); } } class DataWatchRegistration extends WatchRegistration { public DataWatchRegistration(Watcher watcher, String clientPath) { super(watcher, clientPath); } @Override protected Map> getWatches(int rc) { return getWatchManager().getDataWatches(); } } class ChildWatchRegistration extends WatchRegistration { public ChildWatchRegistration(Watcher watcher, String clientPath) { super(watcher, clientPath); } @Override protected Map> getWatches(int rc) { return getWatchManager().getChildWatches(); } } class AddWatchRegistration extends WatchRegistration { private final AddWatchMode mode; public AddWatchRegistration(Watcher watcher, String clientPath, AddWatchMode mode) { super(watcher, clientPath); this.mode = mode; } @Override protected Map> getWatches(int rc) { switch (mode) { case PERSISTENT: return getWatchManager().getPersistentWatches(); case PERSISTENT_RECURSIVE: return getWatchManager().getPersistentRecursiveWatches(); } throw new IllegalArgumentException("Mode not supported: " + mode); } @Override protected boolean shouldAddWatch(int rc) { return rc == KeeperException.Code.OK.intValue() || rc == KeeperException.Code.NONODE.intValue(); } } @InterfaceAudience.Public public enum States { CONNECTING, ASSOCIATING, CONNECTED, CONNECTEDREADONLY, CLOSED, AUTH_FAILED, NOT_CONNECTED; public boolean isAlive() { return this != CLOSED && this != AUTH_FAILED; } /** * Returns whether we are connected to a server (which * could possibly be read-only, if this client is allowed * to go to read-only mode) * */ public boolean isConnected() { return this == CONNECTED || this == CONNECTEDREADONLY; } } /** * To create a ZooKeeper client object, the application needs to pass a * connection string containing a comma separated list of host:port pairs, * each corresponding to a ZooKeeper server. *

* Session establishment is asynchronous. This constructor will initiate * connection to the server and return immediately - potentially (usually) * before the session is fully established. The watcher argument specifies * the watcher that will be notified of any changes in state. This * notification can come at any point before or after the constructor call * has returned. *

* The instantiated ZooKeeper client object will pick an arbitrary server * from the connectString and attempt to connect to it. If establishment of * the connection fails, another server in the connect string will be tried * (the order is non-deterministic, as we random shuffle the list), until a * connection is established. The client will continue attempts until the * session is explicitly closed. *

* Added in 3.2.0: An optional "chroot" suffix may also be appended to the * connection string. This will run the client commands while interpreting * all paths relative to this root (similar to the unix chroot command). * * @param connectString * comma separated host:port pairs, each corresponding to a zk * server. e.g. "127.0.0.1:3000,127.0.0.1:3001,127.0.0.1:3002" If * the optional chroot suffix is used the example would look * like: "127.0.0.1:3000,127.0.0.1:3001,127.0.0.1:3002/app/a" * where the client would be rooted at "/app/a" and all paths * would be relative to this root - ie getting/setting/etc... * "/foo/bar" would result in operations being run on * "/app/a/foo/bar" (from the server perspective). * @param sessionTimeout * session timeout in milliseconds * @param watcher * a watcher object which will be notified of state changes, may * also be notified for node events * * @throws IOException * in cases of network failure * @throws IllegalArgumentException * if an invalid chroot path is specified */ public ZooKeeper(String connectString, int sessionTimeout, Watcher watcher) throws IOException { this(connectString, sessionTimeout, watcher, false); } /** * To create a ZooKeeper client object, the application needs to pass a * connection string containing a comma separated list of host:port pairs, * each corresponding to a ZooKeeper server. *

* Session establishment is asynchronous. This constructor will initiate * connection to the server and return immediately - potentially (usually) * before the session is fully established. The watcher argument specifies * the watcher that will be notified of any changes in state. This * notification can come at any point before or after the constructor call * has returned. *

* The instantiated ZooKeeper client object will pick an arbitrary server * from the connectString and attempt to connect to it. If establishment of * the connection fails, another server in the connect string will be tried * (the order is non-deterministic, as we random shuffle the list), until a * connection is established. The client will continue attempts until the * session is explicitly closed. *

* Added in 3.2.0: An optional "chroot" suffix may also be appended to the * connection string. This will run the client commands while interpreting * all paths relative to this root (similar to the unix chroot command). * * @param connectString * comma separated host:port pairs, each corresponding to a zk * server. e.g. "127.0.0.1:3000,127.0.0.1:3001,127.0.0.1:3002" If * the optional chroot suffix is used the example would look * like: "127.0.0.1:3000,127.0.0.1:3001,127.0.0.1:3002/app/a" * where the client would be rooted at "/app/a" and all paths * would be relative to this root - ie getting/setting/etc... * "/foo/bar" would result in operations being run on * "/app/a/foo/bar" (from the server perspective). * @param sessionTimeout * session timeout in milliseconds * @param watcher * a watcher object which will be notified of state changes, may * also be notified for node events * @param conf * (added in 3.5.2) passing this conf object gives each client the flexibility of * configuring properties differently compared to other instances * @throws IOException * in cases of network failure * @throws IllegalArgumentException * if an invalid chroot path is specified */ public ZooKeeper( String connectString, int sessionTimeout, Watcher watcher, ZKClientConfig conf) throws IOException { this(connectString, sessionTimeout, watcher, false, conf); } /** * To create a ZooKeeper client object, the application needs to pass a * connection string containing a comma separated list of host:port pairs, * each corresponding to a ZooKeeper server. *

* Session establishment is asynchronous. This constructor will initiate * connection to the server and return immediately - potentially (usually) * before the session is fully established. The watcher argument specifies * the watcher that will be notified of any changes in state. This * notification can come at any point before or after the constructor call * has returned. *

* The instantiated ZooKeeper client object will pick an arbitrary server * from the connectString and attempt to connect to it. If establishment of * the connection fails, another server in the connect string will be tried * (the order is non-deterministic, as we random shuffle the list), until a * connection is established. The client will continue attempts until the * session is explicitly closed. *

* Added in 3.2.0: An optional "chroot" suffix may also be appended to the * connection string. This will run the client commands while interpreting * all paths relative to this root (similar to the unix chroot command). *

* For backward compatibility, there is another version * {@link #ZooKeeper(String, int, Watcher, boolean)} which uses * default {@link StaticHostProvider} * * @param connectString * comma separated host:port pairs, each corresponding to a zk * server. e.g. "127.0.0.1:3000,127.0.0.1:3001,127.0.0.1:3002" If * the optional chroot suffix is used the example would look * like: "127.0.0.1:3000,127.0.0.1:3001,127.0.0.1:3002/app/a" * where the client would be rooted at "/app/a" and all paths * would be relative to this root - ie getting/setting/etc... * "/foo/bar" would result in operations being run on * "/app/a/foo/bar" (from the server perspective). * @param sessionTimeout * session timeout in milliseconds * @param watcher * a watcher object which will be notified of state changes, may * also be notified for node events * @param canBeReadOnly * (added in 3.4) whether the created client is allowed to go to * read-only mode in case of partitioning. Read-only mode * basically means that if the client can't find any majority * servers but there's partitioned server it could reach, it * connects to one in read-only mode, i.e. read requests are * allowed while write requests are not. It continues seeking for * majority in the background. * @param aHostProvider * use this as HostProvider to enable custom behaviour. * * @throws IOException * in cases of network failure * @throws IllegalArgumentException * if an invalid chroot path is specified */ public ZooKeeper( String connectString, int sessionTimeout, Watcher watcher, boolean canBeReadOnly, HostProvider aHostProvider) throws IOException { this(connectString, sessionTimeout, watcher, canBeReadOnly, aHostProvider, null); } /** * To create a ZooKeeper client object, the application needs to pass a * connection string containing a comma separated list of host:port pairs, * each corresponding to a ZooKeeper server. *

* Session establishment is asynchronous. This constructor will initiate * connection to the server and return immediately - potentially (usually) * before the session is fully established. The watcher argument specifies * the watcher that will be notified of any changes in state. This * notification can come at any point before or after the constructor call * has returned. *

* The instantiated ZooKeeper client object will pick an arbitrary server * from the connectString and attempt to connect to it. If establishment of * the connection fails, another server in the connect string will be tried * (the order is non-deterministic, as we random shuffle the list), until a * connection is established. The client will continue attempts until the * session is explicitly closed. *

* Added in 3.2.0: An optional "chroot" suffix may also be appended to the * connection string. This will run the client commands while interpreting * all paths relative to this root (similar to the unix chroot command). *

* For backward compatibility, there is another version * {@link #ZooKeeper(String, int, Watcher, boolean)} which uses default * {@link StaticHostProvider} * * @param connectString * comma separated host:port pairs, each corresponding to a zk * server. e.g. "127.0.0.1:3000,127.0.0.1:3001,127.0.0.1:3002" If * the optional chroot suffix is used the example would look * like: "127.0.0.1:3000,127.0.0.1:3001,127.0.0.1:3002/app/a" * where the client would be rooted at "/app/a" and all paths * would be relative to this root - ie getting/setting/etc... * "/foo/bar" would result in operations being run on * "/app/a/foo/bar" (from the server perspective). * @param sessionTimeout * session timeout in milliseconds * @param watcher * a watcher object which will be notified of state changes, may * also be notified for node events * @param canBeReadOnly * (added in 3.4) whether the created client is allowed to go to * read-only mode in case of partitioning. Read-only mode * basically means that if the client can't find any majority * servers but there's partitioned server it could reach, it * connects to one in read-only mode, i.e. read requests are * allowed while write requests are not. It continues seeking for * majority in the background. * @param hostProvider * use this as HostProvider to enable custom behaviour. * @param clientConfig * (added in 3.5.2) passing this conf object gives each client the flexibility of * configuring properties differently compared to other instances * @throws IOException * in cases of network failure * @throws IllegalArgumentException * if an invalid chroot path is specified */ public ZooKeeper( String connectString, int sessionTimeout, Watcher watcher, boolean canBeReadOnly, HostProvider hostProvider, ZKClientConfig clientConfig ) throws IOException { LOG.info( "Initiating client connection, connectString={} sessionTimeout={} watcher={}", connectString, sessionTimeout, watcher); this.clientConfig = clientConfig != null ? clientConfig : new ZKClientConfig(); this.hostProvider = hostProvider; ConnectStringParser connectStringParser = new ConnectStringParser(connectString); cnxn = createConnection( connectStringParser.getChrootPath(), hostProvider, sessionTimeout, this.clientConfig, watcher, getClientCnxnSocket(), canBeReadOnly); cnxn.start(); } ClientCnxn createConnection( String chrootPath, HostProvider hostProvider, int sessionTimeout, ZKClientConfig clientConfig, Watcher defaultWatcher, ClientCnxnSocket clientCnxnSocket, boolean canBeReadOnly ) throws IOException { return new ClientCnxn( chrootPath, hostProvider, sessionTimeout, clientConfig, defaultWatcher, clientCnxnSocket, canBeReadOnly); } /** * To create a ZooKeeper client object, the application needs to pass a * connection string containing a comma separated list of host:port pairs, * each corresponding to a ZooKeeper server. *

* Session establishment is asynchronous. This constructor will initiate * connection to the server and return immediately - potentially (usually) * before the session is fully established. The watcher argument specifies * the watcher that will be notified of any changes in state. This * notification can come at any point before or after the constructor call * has returned. *

* The instantiated ZooKeeper client object will pick an arbitrary server * from the connectString and attempt to connect to it. If establishment of * the connection fails, another server in the connect string will be tried * (the order is non-deterministic, as we random shuffle the list), until a * connection is established. The client will continue attempts until the * session is explicitly closed. *

* Added in 3.2.0: An optional "chroot" suffix may also be appended to the * connection string. This will run the client commands while interpreting * all paths relative to this root (similar to the unix chroot command). *

* * @param connectString * comma separated host:port pairs, each corresponding to a zk * server. e.g. "127.0.0.1:3000,127.0.0.1:3001,127.0.0.1:3002" If * the optional chroot suffix is used the example would look * like: "127.0.0.1:3000,127.0.0.1:3001,127.0.0.1:3002/app/a" * where the client would be rooted at "/app/a" and all paths * would be relative to this root - ie getting/setting/etc... * "/foo/bar" would result in operations being run on * "/app/a/foo/bar" (from the server perspective). * @param sessionTimeout * session timeout in milliseconds * @param watcher * a watcher object which will be notified of state changes, may * also be notified for node events * @param canBeReadOnly * (added in 3.4) whether the created client is allowed to go to * read-only mode in case of partitioning. Read-only mode * basically means that if the client can't find any majority * servers but there's partitioned server it could reach, it * connects to one in read-only mode, i.e. read requests are * allowed while write requests are not. It continues seeking for * majority in the background. * * @throws IOException * in cases of network failure * @throws IllegalArgumentException * if an invalid chroot path is specified */ public ZooKeeper( String connectString, int sessionTimeout, Watcher watcher, boolean canBeReadOnly) throws IOException { this(connectString, sessionTimeout, watcher, canBeReadOnly, createDefaultHostProvider(connectString)); } /** * To create a ZooKeeper client object, the application needs to pass a * connection string containing a comma separated list of host:port pairs, * each corresponding to a ZooKeeper server. *

* Session establishment is asynchronous. This constructor will initiate * connection to the server and return immediately - potentially (usually) * before the session is fully established. The watcher argument specifies * the watcher that will be notified of any changes in state. This * notification can come at any point before or after the constructor call * has returned. *

* The instantiated ZooKeeper client object will pick an arbitrary server * from the connectString and attempt to connect to it. If establishment of * the connection fails, another server in the connect string will be tried * (the order is non-deterministic, as we random shuffle the list), until a * connection is established. The client will continue attempts until the * session is explicitly closed. *

* Added in 3.2.0: An optional "chroot" suffix may also be appended to the * connection string. This will run the client commands while interpreting * all paths relative to this root (similar to the unix chroot command). *

* * @param connectString * comma separated host:port pairs, each corresponding to a zk * server. e.g. "127.0.0.1:3000,127.0.0.1:3001,127.0.0.1:3002" If * the optional chroot suffix is used the example would look * like: "127.0.0.1:3000,127.0.0.1:3001,127.0.0.1:3002/app/a" * where the client would be rooted at "/app/a" and all paths * would be relative to this root - ie getting/setting/etc... * "/foo/bar" would result in operations being run on * "/app/a/foo/bar" (from the server perspective). * @param sessionTimeout * session timeout in milliseconds * @param watcher * a watcher object which will be notified of state changes, may * also be notified for node events * @param canBeReadOnly * (added in 3.4) whether the created client is allowed to go to * read-only mode in case of partitioning. Read-only mode * basically means that if the client can't find any majority * servers but there's partitioned server it could reach, it * connects to one in read-only mode, i.e. read requests are * allowed while write requests are not. It continues seeking for * majority in the background. * @param conf * (added in 3.5.2) passing this conf object gives each client the flexibility of * configuring properties differently compared to other instances * @throws IOException * in cases of network failure * @throws IllegalArgumentException * if an invalid chroot path is specified */ public ZooKeeper( String connectString, int sessionTimeout, Watcher watcher, boolean canBeReadOnly, ZKClientConfig conf) throws IOException { this( connectString, sessionTimeout, watcher, canBeReadOnly, createDefaultHostProvider(connectString), conf); } /** * To create a ZooKeeper client object, the application needs to pass a * connection string containing a comma separated list of host:port pairs, * each corresponding to a ZooKeeper server. *

* Session establishment is asynchronous. This constructor will initiate * connection to the server and return immediately - potentially (usually) * before the session is fully established. The watcher argument specifies * the watcher that will be notified of any changes in state. This * notification can come at any point before or after the constructor call * has returned. *

* The instantiated ZooKeeper client object will pick an arbitrary server * from the connectString and attempt to connect to it. If establishment of * the connection fails, another server in the connect string will be tried * (the order is non-deterministic, as we random shuffle the list), until a * connection is established. The client will continue attempts until the * session is explicitly closed (or the session is expired by the server). *

* Added in 3.2.0: An optional "chroot" suffix may also be appended to the * connection string. This will run the client commands while interpreting * all paths relative to this root (similar to the unix chroot command). *

* Use {@link #getSessionId} and {@link #getSessionPasswd} on an established * client connection, these values must be passed as sessionId and * sessionPasswd respectively if reconnecting. Otherwise, if not * reconnecting, use the other constructor which does not require these * parameters. * * @param connectString * comma separated host:port pairs, each corresponding to a zk * server. e.g. "127.0.0.1:3000,127.0.0.1:3001,127.0.0.1:3002" * If the optional chroot suffix is used the example would look * like: "127.0.0.1:3000,127.0.0.1:3001,127.0.0.1:3002/app/a" * where the client would be rooted at "/app/a" and all paths * would be relative to this root - ie getting/setting/etc... * "/foo/bar" would result in operations being run on * "/app/a/foo/bar" (from the server perspective). * @param sessionTimeout * session timeout in milliseconds * @param watcher * a watcher object which will be notified of state changes, may * also be notified for node events * @param sessionId * specific session id to use if reconnecting * @param sessionPasswd * password for this session * * @throws IOException in cases of network failure * @throws IllegalArgumentException if an invalid chroot path is specified * @throws IllegalArgumentException for an invalid list of ZooKeeper hosts */ public ZooKeeper( String connectString, int sessionTimeout, Watcher watcher, long sessionId, byte[] sessionPasswd) throws IOException { this(connectString, sessionTimeout, watcher, sessionId, sessionPasswd, false); } /** * To create a ZooKeeper client object, the application needs to pass a * connection string containing a comma separated list of host:port pairs, * each corresponding to a ZooKeeper server. *

* Session establishment is asynchronous. This constructor will initiate * connection to the server and return immediately - potentially (usually) * before the session is fully established. The watcher argument specifies * the watcher that will be notified of any changes in state. This * notification can come at any point before or after the constructor call * has returned. *

* The instantiated ZooKeeper client object will pick an arbitrary server * from the connectString and attempt to connect to it. If establishment of * the connection fails, another server in the connect string will be tried * (the order is non-deterministic, as we random shuffle the list), until a * connection is established. The client will continue attempts until the * session is explicitly closed (or the session is expired by the server). *

* Added in 3.2.0: An optional "chroot" suffix may also be appended to the * connection string. This will run the client commands while interpreting * all paths relative to this root (similar to the unix chroot command). *

* Use {@link #getSessionId} and {@link #getSessionPasswd} on an established * client connection, these values must be passed as sessionId and * sessionPasswd respectively if reconnecting. Otherwise, if not * reconnecting, use the other constructor which does not require these * parameters. *

* For backward compatibility, there is another version * {@link #ZooKeeper(String, int, Watcher, long, byte[], boolean)} which uses * default {@link StaticHostProvider} * * @param connectString * comma separated host:port pairs, each corresponding to a zk * server. e.g. "127.0.0.1:3000,127.0.0.1:3001,127.0.0.1:3002" * If the optional chroot suffix is used the example would look * like: "127.0.0.1:3000,127.0.0.1:3001,127.0.0.1:3002/app/a" * where the client would be rooted at "/app/a" and all paths * would be relative to this root - ie getting/setting/etc... * "/foo/bar" would result in operations being run on * "/app/a/foo/bar" (from the server perspective). * @param sessionTimeout * session timeout in milliseconds * @param watcher * a watcher object which will be notified of state changes, may * also be notified for node events * @param sessionId * specific session id to use if reconnecting * @param sessionPasswd * password for this session * @param canBeReadOnly * (added in 3.4) whether the created client is allowed to go to * read-only mode in case of partitioning. Read-only mode * basically means that if the client can't find any majority * servers but there's partitioned server it could reach, it * connects to one in read-only mode, i.e. read requests are * allowed while write requests are not. It continues seeking for * majority in the background. * @param aHostProvider * use this as HostProvider to enable custom behaviour. * @throws IOException in cases of network failure * @throws IllegalArgumentException if an invalid chroot path is specified */ public ZooKeeper( String connectString, int sessionTimeout, Watcher watcher, long sessionId, byte[] sessionPasswd, boolean canBeReadOnly, HostProvider aHostProvider) throws IOException { this( connectString, sessionTimeout, watcher, sessionId, sessionPasswd, canBeReadOnly, aHostProvider, null); } /** * To create a ZooKeeper client object, the application needs to pass a * connection string containing a comma separated list of host:port pairs, * each corresponding to a ZooKeeper server. *

* Session establishment is asynchronous. This constructor will initiate * connection to the server and return immediately - potentially (usually) * before the session is fully established. The watcher argument specifies * the watcher that will be notified of any changes in state. This * notification can come at any point before or after the constructor call * has returned. *

* The instantiated ZooKeeper client object will pick an arbitrary server * from the connectString and attempt to connect to it. If establishment of * the connection fails, another server in the connect string will be tried * (the order is non-deterministic, as we random shuffle the list), until a * connection is established. The client will continue attempts until the * session is explicitly closed (or the session is expired by the server). *

* Added in 3.2.0: An optional "chroot" suffix may also be appended to the * connection string. This will run the client commands while interpreting * all paths relative to this root (similar to the unix chroot command). *

* Use {@link #getSessionId} and {@link #getSessionPasswd} on an established * client connection, these values must be passed as sessionId and * sessionPasswd respectively if reconnecting. Otherwise, if not * reconnecting, use the other constructor which does not require these * parameters. *

* For backward compatibility, there is another version * {@link #ZooKeeper(String, int, Watcher, long, byte[], boolean)} which uses * default {@link StaticHostProvider} * * @param connectString * comma separated host:port pairs, each corresponding to a zk * server. e.g. "127.0.0.1:3000,127.0.0.1:3001,127.0.0.1:3002" * If the optional chroot suffix is used the example would look * like: "127.0.0.1:3000,127.0.0.1:3001,127.0.0.1:3002/app/a" * where the client would be rooted at "/app/a" and all paths * would be relative to this root - ie getting/setting/etc... * "/foo/bar" would result in operations being run on * "/app/a/foo/bar" (from the server perspective). * @param sessionTimeout * session timeout in milliseconds * @param watcher * a watcher object which will be notified of state changes, may * also be notified for node events * @param sessionId * specific session id to use if reconnecting * @param sessionPasswd * password for this session * @param canBeReadOnly * (added in 3.4) whether the created client is allowed to go to * read-only mode in case of partitioning. Read-only mode * basically means that if the client can't find any majority * servers but there's partitioned server it could reach, it * connects to one in read-only mode, i.e. read requests are * allowed while write requests are not. It continues seeking for * majority in the background. * @param hostProvider * use this as HostProvider to enable custom behaviour. * @param clientConfig * (added in 3.5.2) passing this conf object gives each client the flexibility of * configuring properties differently compared to other instances * @throws IOException in cases of network failure * @throws IllegalArgumentException if an invalid chroot path is specified * * @since 3.5.5 */ public ZooKeeper( String connectString, int sessionTimeout, Watcher watcher, long sessionId, byte[] sessionPasswd, boolean canBeReadOnly, HostProvider hostProvider, ZKClientConfig clientConfig) throws IOException { LOG.info( "Initiating client connection, connectString={} " + "sessionTimeout={} watcher={} sessionId=0x{} sessionPasswd={}", connectString, sessionTimeout, watcher, Long.toHexString(sessionId), (sessionPasswd == null ? "" : "")); this.clientConfig = clientConfig != null ? clientConfig : new ZKClientConfig(); ConnectStringParser connectStringParser = new ConnectStringParser(connectString); this.hostProvider = hostProvider; cnxn = new ClientCnxn( connectStringParser.getChrootPath(), hostProvider, sessionTimeout, this.clientConfig, watcher, getClientCnxnSocket(), sessionId, sessionPasswd, canBeReadOnly); cnxn.seenRwServerBefore = true; // since user has provided sessionId cnxn.start(); } /** * To create a ZooKeeper client object, the application needs to pass a * connection string containing a comma separated list of host:port pairs, * each corresponding to a ZooKeeper server. *

* Session establishment is asynchronous. This constructor will initiate * connection to the server and return immediately - potentially (usually) * before the session is fully established. The watcher argument specifies * the watcher that will be notified of any changes in state. This * notification can come at any point before or after the constructor call * has returned. *

* The instantiated ZooKeeper client object will pick an arbitrary server * from the connectString and attempt to connect to it. If establishment of * the connection fails, another server in the connect string will be tried * (the order is non-deterministic, as we random shuffle the list), until a * connection is established. The client will continue attempts until the * session is explicitly closed (or the session is expired by the server). *

* Added in 3.2.0: An optional "chroot" suffix may also be appended to the * connection string. This will run the client commands while interpreting * all paths relative to this root (similar to the unix chroot command). *

* Use {@link #getSessionId} and {@link #getSessionPasswd} on an established * client connection, these values must be passed as sessionId and * sessionPasswd respectively if reconnecting. Otherwise, if not * reconnecting, use the other constructor which does not require these * parameters. *

* This constructor uses a StaticHostProvider; there is another one * to enable custom behaviour. * * @param connectString * comma separated host:port pairs, each corresponding to a zk * server. e.g. "127.0.0.1:3000,127.0.0.1:3001,127.0.0.1:3002" * If the optional chroot suffix is used the example would look * like: "127.0.0.1:3000,127.0.0.1:3001,127.0.0.1:3002/app/a" * where the client would be rooted at "/app/a" and all paths * would be relative to this root - ie getting/setting/etc... * "/foo/bar" would result in operations being run on * "/app/a/foo/bar" (from the server perspective). * @param sessionTimeout * session timeout in milliseconds * @param watcher * a watcher object which will be notified of state changes, may * also be notified for node events * @param sessionId * specific session id to use if reconnecting * @param sessionPasswd * password for this session * @param canBeReadOnly * (added in 3.4) whether the created client is allowed to go to * read-only mode in case of partitioning. Read-only mode * basically means that if the client can't find any majority * servers but there's partitioned server it could reach, it * connects to one in read-only mode, i.e. read requests are * allowed while write requests are not. It continues seeking for * majority in the background. * @throws IOException in cases of network failure * @throws IllegalArgumentException if an invalid chroot path is specified */ public ZooKeeper( String connectString, int sessionTimeout, Watcher watcher, long sessionId, byte[] sessionPasswd, boolean canBeReadOnly) throws IOException { this( connectString, sessionTimeout, watcher, sessionId, sessionPasswd, canBeReadOnly, createDefaultHostProvider(connectString)); } // default hostprovider private static HostProvider createDefaultHostProvider(String connectString) { return new StaticHostProvider(new ConnectStringParser(connectString).getServerAddresses()); } // VisibleForTesting public Testable getTestable() { return new ZooKeeperTestable(cnxn); } /** * The session id for this ZooKeeper client instance. The value returned is * not valid until the client connects to a server and may change after a * re-connect. * * This method is NOT thread safe * * @return current session id */ public long getSessionId() { return cnxn.getSessionId(); } /** * The session password for this ZooKeeper client instance. The value * returned is not valid until the client connects to a server and may * change after a re-connect. * * This method is NOT thread safe * * @return current session password */ public byte[] getSessionPasswd() { return cnxn.getSessionPasswd(); } /** * The negotiated session timeout for this ZooKeeper client instance. The * value returned is not valid until the client connects to a server and * may change after a re-connect. * * This method is NOT thread safe * * @return current session timeout */ public int getSessionTimeout() { return cnxn.getSessionTimeout(); } /** * Add the specified scheme:auth information to this connection. * * This method is NOT thread safe * * @param scheme * @param auth */ public void addAuthInfo(String scheme, byte[] auth) { cnxn.addAuthInfo(scheme, auth); } /** * Specify the default watcher for the connection (overrides the one * specified during construction). */ public synchronized void register(Watcher watcher) { getWatchManager().setDefaultWatcher(watcher); } /** * Close this client object. Once the client is closed, its session becomes * invalid. All the ephemeral nodes in the ZooKeeper server associated with * the session will be removed. The watches left on those nodes (and on * their parents) will be triggered. *

* Added in 3.5.3: try-with-resources * may be used instead of calling close directly. *

*

* This method does not wait for all internal threads to exit. * Use the {@link #close(int) } method to wait for all resources to be released *

* * @throws InterruptedException */ public synchronized void close() throws InterruptedException { if (!cnxn.getState().isAlive()) { LOG.debug("Close called on already closed client"); return; } LOG.debug("Closing session: 0x" + Long.toHexString(getSessionId())); try { cnxn.close(); } catch (IOException e) { LOG.debug("Ignoring unexpected exception during close", e); } LOG.info("Session: 0x{} closed", Long.toHexString(getSessionId())); } /** * Close this client object as the {@link #close() } method. * This method will wait for internal resources to be released. * * @param waitForShutdownTimeoutMs timeout (in milliseconds) to wait for resources to be released. * Use zero or a negative value to skip the wait * @throws InterruptedException * @return true if waitForShutdownTimeout is greater than zero and all of the resources have been released * * @since 3.5.4 */ public boolean close(int waitForShutdownTimeoutMs) throws InterruptedException { close(); return testableWaitForShutdown(waitForShutdownTimeoutMs); } /** * Prepend the chroot to the client path (if present). The expectation of * this function is that the client path has been validated before this * function is called * @param clientPath path to the node * @return server view of the path (chroot prepended to client path) */ private String prependChroot(String clientPath) { if (cnxn.chrootPath != null) { // handle clientPath = "/" if (clientPath.length() == 1) { return cnxn.chrootPath; } return cnxn.chrootPath + clientPath; } else { return clientPath; } } /** * Create a node with the given path. The node data will be the given data, * and node acl will be the given acl. *

* The flags argument specifies whether the created node will be ephemeral * or not. *

* An ephemeral node will be removed by the ZooKeeper automatically when the * session associated with the creation of the node expires. *

* The flags argument can also specify to create a sequential node. The * actual path name of a sequential node will be the given path plus a * suffix "i" where i is the current sequential number of the node. The sequence * number is always fixed length of 10 digits, 0 padded. Once * such a node is created, the sequential number will be incremented by one. *

* If a node with the same actual path already exists in the ZooKeeper, a * KeeperException with error code KeeperException.NodeExists will be * thrown. Note that since a different actual path is used for each * invocation of creating sequential node with the same path argument, the * call will never throw "file exists" KeeperException. *

* If the parent node does not exist in the ZooKeeper, a KeeperException * with error code KeeperException.NoNode will be thrown. *

* An ephemeral node cannot have children. If the parent node of the given * path is ephemeral, a KeeperException with error code * KeeperException.NoChildrenForEphemerals will be thrown. *

* This operation, if successful, will trigger all the watches left on the * node of the given path by exists and getData API calls, and the watches * left on the parent node by getChildren API calls. *

* If a node is created successfully, the ZooKeeper server will trigger the * watches on the path left by exists calls, and the watches on the parent * of the node by getChildren calls. *

* The maximum allowable size of the data array is 1 MB (1,048,576 bytes). * Arrays larger than this will cause a KeeperExecption to be thrown. * * @param path * the path for the node * @param data * the initial data for the node * @param acl * the acl for the node * @param createMode * specifying whether the node to be created is ephemeral * and/or sequential * @return the actual path of the created node * @throws KeeperException if the server returns a non-zero error code * @throws KeeperException.InvalidACLException if the ACL is invalid, null, or empty * @throws InterruptedException if the transaction is interrupted * @throws IllegalArgumentException if an invalid path is specified */ public String create( final String path, byte[] data, List acl, CreateMode createMode) throws KeeperException, InterruptedException { final String clientPath = path; PathUtils.validatePath(clientPath, createMode.isSequential()); EphemeralType.validateTTL(createMode, -1); validateACL(acl); final String serverPath = prependChroot(clientPath); RequestHeader h = new RequestHeader(); h.setType(createMode.isContainer() ? ZooDefs.OpCode.createContainer : ZooDefs.OpCode.create); CreateRequest request = new CreateRequest(); CreateResponse response = new CreateResponse(); request.setData(data); request.setFlags(createMode.toFlag()); request.setPath(serverPath); request.setAcl(acl); ReplyHeader r = cnxn.submitRequest(h, request, response, null); if (r.getErr() != 0) { throw KeeperException.create(KeeperException.Code.get(r.getErr()), clientPath); } if (cnxn.chrootPath == null) { return response.getPath(); } else { return response.getPath().substring(cnxn.chrootPath.length()); } } /** * Create a node with the given path and returns the Stat of that node. The * node data will be the given data and node acl will be the given acl. *

* The flags argument specifies whether the created node will be ephemeral * or not. *

* An ephemeral node will be removed by the ZooKeeper automatically when the * session associated with the creation of the node expires. *

* The flags argument can also specify to create a sequential node. The * actual path name of a sequential node will be the given path plus a * suffix "i" where i is the current sequential number of the node. The sequence * number is always fixed length of 10 digits, 0 padded. Once * such a node is created, the sequential number will be incremented by one. *

* If a node with the same actual path already exists in the ZooKeeper, a * KeeperException with error code KeeperException.NodeExists will be * thrown. Note that since a different actual path is used for each * invocation of creating sequential node with the same path argument, the * call will never throw "file exists" KeeperException. *

* If the parent node does not exist in the ZooKeeper, a KeeperException * with error code KeeperException.NoNode will be thrown. *

* An ephemeral node cannot have children. If the parent node of the given * path is ephemeral, a KeeperException with error code * KeeperException.NoChildrenForEphemerals will be thrown. *

* This operation, if successful, will trigger all the watches left on the * node of the given path by exists and getData API calls, and the watches * left on the parent node by getChildren API calls. *

* If a node is created successfully, the ZooKeeper server will trigger the * watches on the path left by exists calls, and the watches on the parent * of the node by getChildren calls. *

* The maximum allowable size of the data array is 1 MB (1,048,576 bytes). * Arrays larger than this will cause a KeeperExecption to be thrown. * * @param path * the path for the node * @param data * the initial data for the node * @param acl * the acl for the node * @param createMode * specifying whether the node to be created is ephemeral * and/or sequential * @param stat * The output Stat object. * @return the actual path of the created node * @throws KeeperException if the server returns a non-zero error code * @throws KeeperException.InvalidACLException if the ACL is invalid, null, or empty * @throws InterruptedException if the transaction is interrupted * @throws IllegalArgumentException if an invalid path is specified */ public String create( final String path, byte[] data, List acl, CreateMode createMode, Stat stat) throws KeeperException, InterruptedException { return create(path, data, acl, createMode, stat, -1); } /** * same as {@link #create(String, byte[], List, CreateMode, Stat)} but * allows for specifying a TTL when mode is {@link CreateMode#PERSISTENT_WITH_TTL} * or {@link CreateMode#PERSISTENT_SEQUENTIAL_WITH_TTL}. If the znode has not been modified * within the given TTL, it will be deleted once it has no children. The TTL unit is * milliseconds and must be greater than 0 and less than or equal to * {@link EphemeralType#maxValue()} for {@link EphemeralType#TTL}. */ public String create( final String path, byte[] data, List acl, CreateMode createMode, Stat stat, long ttl) throws KeeperException, InterruptedException { final String clientPath = path; PathUtils.validatePath(clientPath, createMode.isSequential()); EphemeralType.validateTTL(createMode, ttl); validateACL(acl); final String serverPath = prependChroot(clientPath); RequestHeader h = new RequestHeader(); setCreateHeader(createMode, h); Create2Response response = new Create2Response(); Record record = makeCreateRecord(createMode, serverPath, data, acl, ttl); ReplyHeader r = cnxn.submitRequest(h, record, response, null); if (r.getErr() != 0) { throw KeeperException.create(KeeperException.Code.get(r.getErr()), clientPath); } if (stat != null) { DataTree.copyStat(response.getStat(), stat); } if (cnxn.chrootPath == null) { return response.getPath(); } else { return response.getPath().substring(cnxn.chrootPath.length()); } } private void setCreateHeader(CreateMode createMode, RequestHeader h) { if (createMode.isTTL()) { h.setType(ZooDefs.OpCode.createTTL); } else { h.setType(createMode.isContainer() ? ZooDefs.OpCode.createContainer : ZooDefs.OpCode.create2); } } private Record makeCreateRecord(CreateMode createMode, String serverPath, byte[] data, List acl, long ttl) { Record record; if (createMode.isTTL()) { CreateTTLRequest request = new CreateTTLRequest(); request.setData(data); request.setFlags(createMode.toFlag()); request.setPath(serverPath); request.setAcl(acl); request.setTtl(ttl); record = request; } else { CreateRequest request = new CreateRequest(); request.setData(data); request.setFlags(createMode.toFlag()); request.setPath(serverPath); request.setAcl(acl); record = request; } return record; } /** * The asynchronous version of create. * * @see #create(String, byte[], List, CreateMode) */ public void create( final String path, byte[] data, List acl, CreateMode createMode, StringCallback cb, Object ctx) { final String clientPath = path; PathUtils.validatePath(clientPath, createMode.isSequential()); EphemeralType.validateTTL(createMode, -1); final String serverPath = prependChroot(clientPath); RequestHeader h = new RequestHeader(); h.setType(createMode.isContainer() ? ZooDefs.OpCode.createContainer : ZooDefs.OpCode.create); CreateRequest request = new CreateRequest(); CreateResponse response = new CreateResponse(); ReplyHeader r = new ReplyHeader(); request.setData(data); request.setFlags(createMode.toFlag()); request.setPath(serverPath); request.setAcl(acl); cnxn.queuePacket(h, r, request, response, cb, clientPath, serverPath, ctx, null); } /** * The asynchronous version of create. * * @see #create(String, byte[], List, CreateMode, Stat) */ public void create( final String path, byte[] data, List acl, CreateMode createMode, Create2Callback cb, Object ctx) { create(path, data, acl, createMode, cb, ctx, -1); } /** * The asynchronous version of create with ttl. * * @see #create(String, byte[], List, CreateMode, Stat, long) */ public void create( final String path, byte[] data, List acl, CreateMode createMode, Create2Callback cb, Object ctx, long ttl) { final String clientPath = path; PathUtils.validatePath(clientPath, createMode.isSequential()); EphemeralType.validateTTL(createMode, ttl); final String serverPath = prependChroot(clientPath); RequestHeader h = new RequestHeader(); setCreateHeader(createMode, h); ReplyHeader r = new ReplyHeader(); Create2Response response = new Create2Response(); Record record = makeCreateRecord(createMode, serverPath, data, acl, ttl); cnxn.queuePacket(h, r, record, response, cb, clientPath, serverPath, ctx, null); } /** * Delete the node with the given path. The call will succeed if such a node * exists, and the given version matches the node's version (if the given * version is -1, it matches any node's versions). *

* A KeeperException with error code KeeperException.NoNode will be thrown * if the nodes does not exist. *

* A KeeperException with error code KeeperException.BadVersion will be * thrown if the given version does not match the node's version. *

* A KeeperException with error code KeeperException.NotEmpty will be thrown * if the node has children. *

* This operation, if successful, will trigger all the watches on the node * of the given path left by exists API calls, and the watches on the parent * node left by getChildren API calls. * * @param path * the path of the node to be deleted. * @param version * the expected node version. * @throws InterruptedException IF the server transaction is interrupted * @throws KeeperException If the server signals an error with a non-zero * return code. * @throws IllegalArgumentException if an invalid path is specified */ public void delete(final String path, int version) throws InterruptedException, KeeperException { final String clientPath = path; PathUtils.validatePath(clientPath); final String serverPath; // maintain semantics even in chroot case // specifically - root cannot be deleted // I think this makes sense even in chroot case. if (clientPath.equals("/")) { // a bit of a hack, but delete(/) will never succeed and ensures // that the same semantics are maintained serverPath = clientPath; } else { serverPath = prependChroot(clientPath); } RequestHeader h = new RequestHeader(); h.setType(ZooDefs.OpCode.delete); DeleteRequest request = new DeleteRequest(); request.setPath(serverPath); request.setVersion(version); ReplyHeader r = cnxn.submitRequest(h, request, null, null); if (r.getErr() != 0) { throw KeeperException.create(KeeperException.Code.get(r.getErr()), clientPath); } } /** * Executes multiple ZooKeeper operations. In case of transactions all of them or none of them will be executed. *

* On success, a list of results is returned. * On failure, an exception is raised which contains partial results and * error details, see {@link KeeperException#getResults} *

* Note: The maximum allowable size of all of the data arrays in all of * the setData operations in this single request is typically 1 MB * (1,048,576 bytes). This limit is specified on the server via * jute.maxbuffer. * Requests larger than this will cause a KeeperException to be * thrown. * * @param ops An iterable that contains the operations to be done. * These should be created using the factory methods on {@link Op} and must be the same kind of ops. * @return A list of results, one for each input Op, the order of * which exactly matches the order of the ops input * operations. * @throws InterruptedException If the operation was interrupted. * The operation may or may not have succeeded, but will not have * partially succeeded if this exception is thrown. * @throws KeeperException If the operation could not be completed * due to some error in doing one of the specified ops. * @throws IllegalArgumentException if an invalid path is specified or different kind of ops are mixed * * @since 3.4.0 */ public List multi(Iterable ops) throws InterruptedException, KeeperException { for (Op op : ops) { op.validate(); } return multiInternal(generateMultiTransaction(ops)); } /** * The asynchronous version of multi. * * @see #multi(Iterable) */ public void multi(Iterable ops, MultiCallback cb, Object ctx) { List results = validatePath(ops); if (results.size() > 0) { cb.processResult(KeeperException.Code.BADARGUMENTS.intValue(), null, ctx, results); return; } multiInternal(generateMultiTransaction(ops), cb, ctx); } private List validatePath(Iterable ops) { List results = new ArrayList<>(); boolean error = false; for (Op op : ops) { try { op.validate(); } catch (IllegalArgumentException iae) { LOG.error("Unexpected exception", iae); ErrorResult err = new ErrorResult(KeeperException.Code.BADARGUMENTS.intValue()); results.add(err); error = true; continue; } catch (KeeperException ke) { LOG.error("Unexpected exception", ke); ErrorResult err = new ErrorResult(ke.code().intValue()); results.add(err); error = true; continue; } ErrorResult err = new ErrorResult(KeeperException.Code.RUNTIMEINCONSISTENCY.intValue()); results.add(err); } if (!error) { results.clear(); } return results; } private MultiOperationRecord generateMultiTransaction(Iterable ops) { // reconstructing transaction with the chroot prefix List transaction = new ArrayList<>(); for (Op op : ops) { transaction.add(withRootPrefix(op)); } return new MultiOperationRecord(transaction); } private Op withRootPrefix(Op op) { if (null != op.getPath()) { final String serverPath = prependChroot(op.getPath()); if (!op.getPath().equals(serverPath)) { return op.withChroot(serverPath); } } return op; } protected void multiInternal( MultiOperationRecord request, MultiCallback cb, Object ctx) throws IllegalArgumentException { if (request.size() == 0) { // nothing to do, early exit cnxn.queueCallback(cb, KeeperException.Code.OK.intValue(), null, ctx); return; } RequestHeader h = new RequestHeader(); switch (request.getOpKind()) { case TRANSACTION: h.setType(ZooDefs.OpCode.multi); break; case READ: h.setType(ZooDefs.OpCode.multiRead); break; default: throw new IllegalArgumentException("Unsupported OpKind: " + request.getOpKind()); } MultiResponse response = new MultiResponse(); cnxn.queuePacket(h, new ReplyHeader(), request, response, cb, null, null, ctx, null); } protected List multiInternal( MultiOperationRecord request) throws InterruptedException, KeeperException, IllegalArgumentException { RequestHeader h = new RequestHeader(); if (request.size() == 0) { // nothing to do, early exit return Collections.emptyList(); } switch (request.getOpKind()) { case TRANSACTION: h.setType(ZooDefs.OpCode.multi); break; case READ: h.setType(ZooDefs.OpCode.multiRead); break; default: throw new IllegalArgumentException("Unsupported OpKind: " + request.getOpKind()); } MultiResponse response = new MultiResponse(); ReplyHeader r = cnxn.submitRequest(h, request, response, null); if (r.getErr() != 0) { throw KeeperException.create(KeeperException.Code.get(r.getErr())); } List results = response.getResultList(); // In case of only read operations there is no need to throw an exception // as the subResults are still possibly valid. if (request.getOpKind() == Op.OpKind.READ) { return results; } ErrorResult fatalError = null; for (OpResult result : results) { if (result instanceof ErrorResult && ((ErrorResult) result).getErr() != KeeperException.Code.OK.intValue()) { fatalError = (ErrorResult) result; break; } } if (fatalError != null) { KeeperException ex = KeeperException.create(KeeperException.Code.get(fatalError.getErr())); ex.setMultiResults(results); throw ex; } return results; } /** * A Transaction is a thin wrapper on the {@link #multi} method * which provides a builder object that can be used to construct * and commit an atomic set of operations. * * @since 3.4.0 * * @return a Transaction builder object */ public Transaction transaction() { return new Transaction(this); } /** * The asynchronous version of delete. * * @see #delete(String, int) */ public void delete(final String path, int version, VoidCallback cb, Object ctx) { final String clientPath = path; PathUtils.validatePath(clientPath); final String serverPath; // maintain semantics even in chroot case // specifically - root cannot be deleted // I think this makes sense even in chroot case. if (clientPath.equals("/")) { // a bit of a hack, but delete(/) will never succeed and ensures // that the same semantics are maintained serverPath = clientPath; } else { serverPath = prependChroot(clientPath); } RequestHeader h = new RequestHeader(); h.setType(ZooDefs.OpCode.delete); DeleteRequest request = new DeleteRequest(); request.setPath(serverPath); request.setVersion(version); cnxn.queuePacket(h, new ReplyHeader(), request, null, cb, clientPath, serverPath, ctx, null); } /** * Return the stat of the node of the given path. Return null if no such a * node exists. *

* If the watch is non-null and the call is successful (no exception is thrown), * a watch will be left on the node with the given path. The watch will be * triggered by a successful operation that creates/delete the node or sets * the data on the node. * * @param path the node path * @param watcher explicit watcher * @return the stat of the node of the given path; return null if no such a * node exists. * @throws KeeperException If the server signals an error * @throws InterruptedException If the server transaction is interrupted. * @throws IllegalArgumentException if an invalid path is specified */ public Stat exists(final String path, Watcher watcher) throws KeeperException, InterruptedException { final String clientPath = path; PathUtils.validatePath(clientPath); // the watch contains the un-chroot path WatchRegistration wcb = null; if (watcher != null) { wcb = new ExistsWatchRegistration(watcher, clientPath); } final String serverPath = prependChroot(clientPath); RequestHeader h = new RequestHeader(); h.setType(ZooDefs.OpCode.exists); ExistsRequest request = new ExistsRequest(); request.setPath(serverPath); request.setWatch(watcher != null); SetDataResponse response = new SetDataResponse(); ReplyHeader r = cnxn.submitRequest(h, request, response, wcb); if (r.getErr() != 0) { if (r.getErr() == KeeperException.Code.NONODE.intValue()) { return null; } throw KeeperException.create(KeeperException.Code.get(r.getErr()), clientPath); } return response.getStat().getCzxid() == -1 ? null : response.getStat(); } /** * Return the stat of the node of the given path. Return null if no such a * node exists. * *

If the watch is true and the call is successful (no exception is thrown), * a watch will be left on the node with the given path. The watch will be * triggered by a successful operation that creates/delete the node or sets * the data on the node. * * @param path the node path * @param watch whether need to watch this node * @return the stat of the node of the given path; return null if no such a * node exists. * @throws KeeperException If the server signals an error * @throws IllegalStateException if watch this node with a null default watcher * @throws InterruptedException If the server transaction is interrupted. */ public Stat exists(String path, boolean watch) throws KeeperException, InterruptedException { return exists(path, getDefaultWatcher(watch)); } /** * The asynchronous version of exists. * * @see #exists(String, Watcher) */ public void exists(final String path, Watcher watcher, StatCallback cb, Object ctx) { final String clientPath = path; PathUtils.validatePath(clientPath); // the watch contains the un-chroot path WatchRegistration wcb = null; if (watcher != null) { wcb = new ExistsWatchRegistration(watcher, clientPath); } final String serverPath = prependChroot(clientPath); RequestHeader h = new RequestHeader(); h.setType(ZooDefs.OpCode.exists); ExistsRequest request = new ExistsRequest(); request.setPath(serverPath); request.setWatch(watcher != null); SetDataResponse response = new SetDataResponse(); cnxn.queuePacket(h, new ReplyHeader(), request, response, cb, clientPath, serverPath, ctx, wcb); } /** * The asynchronous version of exists. * * @throws IllegalStateException if watch this node with a null default watcher * * @see #exists(String, boolean) */ public void exists(String path, boolean watch, StatCallback cb, Object ctx) { exists(path, getDefaultWatcher(watch), cb, ctx); } /** * Return the data and the stat of the node of the given path. *

* If the watch is non-null and the call is successful (no exception is * thrown), a watch will be left on the node with the given path. The watch * will be triggered by a successful operation that sets data on the node, or * deletes the node. *

* A KeeperException with error code KeeperException.NoNode will be thrown * if no node with the given path exists. * * @param path the given path * @param watcher explicit watcher * @param stat the stat of the node * @return the data of the node * @throws KeeperException If the server signals an error with a non-zero error code * @throws InterruptedException If the server transaction is interrupted. * @throws IllegalArgumentException if an invalid path is specified */ public byte[] getData(final String path, Watcher watcher, Stat stat) throws KeeperException, InterruptedException { final String clientPath = path; PathUtils.validatePath(clientPath); // the watch contains the un-chroot path WatchRegistration wcb = null; if (watcher != null) { wcb = new DataWatchRegistration(watcher, clientPath); } final String serverPath = prependChroot(clientPath); RequestHeader h = new RequestHeader(); h.setType(ZooDefs.OpCode.getData); GetDataRequest request = new GetDataRequest(); request.setPath(serverPath); request.setWatch(watcher != null); GetDataResponse response = new GetDataResponse(); ReplyHeader r = cnxn.submitRequest(h, request, response, wcb); if (r.getErr() != 0) { throw KeeperException.create(KeeperException.Code.get(r.getErr()), clientPath); } if (stat != null) { DataTree.copyStat(response.getStat(), stat); } return response.getData(); } /** * Return the data and the stat of the node of the given path. *

* If the watch is true and the call is successful (no exception is * thrown), a watch will be left on the node with the given path. The watch * will be triggered by a successful operation that sets data on the node, or * deletes the node. *

* A KeeperException with error code KeeperException.NoNode will be thrown * if no node with the given path exists. * * @param path the given path * @param watch whether need to watch this node * @param stat the stat of the node * @return the data of the node * @throws KeeperException If the server signals an error with a non-zero error code * @throws IllegalStateException if watch this node with a null default watcher * @throws InterruptedException If the server transaction is interrupted. */ public byte[] getData(String path, boolean watch, Stat stat) throws KeeperException, InterruptedException { return getData(path, getDefaultWatcher(watch), stat); } /** * The asynchronous version of getData. * * @see #getData(String, Watcher, Stat) */ public void getData(final String path, Watcher watcher, DataCallback cb, Object ctx) { final String clientPath = path; PathUtils.validatePath(clientPath); // the watch contains the un-chroot path WatchRegistration wcb = null; if (watcher != null) { wcb = new DataWatchRegistration(watcher, clientPath); } final String serverPath = prependChroot(clientPath); RequestHeader h = new RequestHeader(); h.setType(ZooDefs.OpCode.getData); GetDataRequest request = new GetDataRequest(); request.setPath(serverPath); request.setWatch(watcher != null); GetDataResponse response = new GetDataResponse(); cnxn.queuePacket(h, new ReplyHeader(), request, response, cb, clientPath, serverPath, ctx, wcb); } /** * The asynchronous version of getData. * * @throws IllegalStateException if watch this node with a null default watcher * * @see #getData(String, boolean, Stat) */ public void getData(String path, boolean watch, DataCallback cb, Object ctx) { getData(path, getDefaultWatcher(watch), cb, ctx); } /** * Return the last committed configuration (as known to the server to which the client is connected) * and the stat of the configuration. *

* If the watch is non-null and the call is successful (no exception is * thrown), a watch will be left on the configuration node (ZooDefs.CONFIG_NODE). The watch * will be triggered by a successful reconfig operation *

* A KeeperException with error code KeeperException.NoNode will be thrown * if the configuration node doesn't exists. * * @param watcher explicit watcher * @param stat the stat of the configuration node ZooDefs.CONFIG_NODE * @return configuration data stored in ZooDefs.CONFIG_NODE * @throws KeeperException If the server signals an error with a non-zero error code * @throws InterruptedException If the server transaction is interrupted. */ public byte[] getConfig(Watcher watcher, Stat stat) throws KeeperException, InterruptedException { final String configZnode = ZooDefs.CONFIG_NODE; // the watch contains the un-chroot path WatchRegistration wcb = null; if (watcher != null) { wcb = new DataWatchRegistration(watcher, configZnode); } RequestHeader h = new RequestHeader(); h.setType(ZooDefs.OpCode.getData); GetDataRequest request = new GetDataRequest(); request.setPath(configZnode); request.setWatch(watcher != null); GetDataResponse response = new GetDataResponse(); ReplyHeader r = cnxn.submitRequest(h, request, response, wcb); if (r.getErr() != 0) { throw KeeperException.create(KeeperException.Code.get(r.getErr()), configZnode); } if (stat != null) { DataTree.copyStat(response.getStat(), stat); } return response.getData(); } /** * The asynchronous version of getConfig. * * @see #getConfig(Watcher, Stat) */ public void getConfig(Watcher watcher, DataCallback cb, Object ctx) { final String configZnode = ZooDefs.CONFIG_NODE; // the watch contains the un-chroot path WatchRegistration wcb = null; if (watcher != null) { wcb = new DataWatchRegistration(watcher, configZnode); } RequestHeader h = new RequestHeader(); h.setType(ZooDefs.OpCode.getData); GetDataRequest request = new GetDataRequest(); request.setPath(configZnode); request.setWatch(watcher != null); GetDataResponse response = new GetDataResponse(); cnxn.queuePacket(h, new ReplyHeader(), request, response, cb, configZnode, configZnode, ctx, wcb); } /** * Return the last committed configuration (as known to the server to which the client is connected) * and the stat of the configuration. *

* If the watch is true and the call is successful (no exception is * thrown), a watch will be left on the configuration node (ZooDefs.CONFIG_NODE). The watch * will be triggered by a successful reconfig operation *

* A KeeperException with error code KeeperException.NoNode will be thrown * if no node with the given path exists. * * @param watch whether need to watch this node * @param stat the stat of the configuration node ZooDefs.CONFIG_NODE * @return configuration data stored in ZooDefs.CONFIG_NODE * @throws KeeperException If the server signals an error with a non-zero error code * @throws IllegalStateException if watch this node with a null default watcher * @throws InterruptedException If the server transaction is interrupted. */ public byte[] getConfig(boolean watch, Stat stat) throws KeeperException, InterruptedException { return getConfig(getDefaultWatcher(watch), stat); } /** * The Asynchronous version of getConfig. * * @throws IllegalStateException if watch this node with a null default watcher * * @see #getData(String, boolean, Stat) */ public void getConfig(boolean watch, DataCallback cb, Object ctx) { getConfig(getDefaultWatcher(watch), cb, ctx); } /** * Set the data for the node of the given path if such a node exists and the * given version matches the version of the node (if the given version is * -1, it matches any node's versions). Return the stat of the node. *

* This operation, if successful, will trigger all the watches on the node * of the given path left by getData calls. *

* A KeeperException with error code KeeperException.NoNode will be thrown * if no node with the given path exists. *

* A KeeperException with error code KeeperException.BadVersion will be * thrown if the given version does not match the node's version. *

* The maximum allowable size of the data array is 1 MB (1,048,576 bytes). * Arrays larger than this will cause a KeeperException to be thrown. * * @param path * the path of the node * @param data * the data to set * @param version * the expected matching version * @return the state of the node * @throws InterruptedException If the server transaction is interrupted. * @throws KeeperException If the server signals an error with a non-zero error code. * @throws IllegalArgumentException if an invalid path is specified */ public Stat setData(final String path, byte[] data, int version) throws KeeperException, InterruptedException { final String clientPath = path; PathUtils.validatePath(clientPath); final String serverPath = prependChroot(clientPath); RequestHeader h = new RequestHeader(); h.setType(ZooDefs.OpCode.setData); SetDataRequest request = new SetDataRequest(); request.setPath(serverPath); request.setData(data); request.setVersion(version); SetDataResponse response = new SetDataResponse(); ReplyHeader r = cnxn.submitRequest(h, request, response, null); if (r.getErr() != 0) { throw KeeperException.create(KeeperException.Code.get(r.getErr()), clientPath); } return response.getStat(); } /** * The asynchronous version of setData. * * @see #setData(String, byte[], int) */ public void setData(final String path, byte[] data, int version, StatCallback cb, Object ctx) { final String clientPath = path; PathUtils.validatePath(clientPath); final String serverPath = prependChroot(clientPath); RequestHeader h = new RequestHeader(); h.setType(ZooDefs.OpCode.setData); SetDataRequest request = new SetDataRequest(); request.setPath(serverPath); request.setData(data); request.setVersion(version); SetDataResponse response = new SetDataResponse(); cnxn.queuePacket(h, new ReplyHeader(), request, response, cb, clientPath, serverPath, ctx, null); } /** * Return the ACL and stat of the node of the given path. *

* A KeeperException with error code KeeperException.NoNode will be thrown * if no node with the given path exists. * * @param path * the given path for the node * @param stat * the stat of the node will be copied to this parameter if * not null. * @return the ACL array of the given node. * @throws InterruptedException If the server transaction is interrupted. * @throws KeeperException If the server signals an error with a non-zero error code. * @throws IllegalArgumentException if an invalid path is specified */ public List getACL(final String path, Stat stat) throws KeeperException, InterruptedException { final String clientPath = path; PathUtils.validatePath(clientPath); final String serverPath = prependChroot(clientPath); RequestHeader h = new RequestHeader(); h.setType(ZooDefs.OpCode.getACL); GetACLRequest request = new GetACLRequest(); request.setPath(serverPath); GetACLResponse response = new GetACLResponse(); ReplyHeader r = cnxn.submitRequest(h, request, response, null); if (r.getErr() != 0) { throw KeeperException.create(KeeperException.Code.get(r.getErr()), clientPath); } if (stat != null) { DataTree.copyStat(response.getStat(), stat); } return response.getAcl(); } /** * The asynchronous version of getACL. * * @see #getACL(String, Stat) */ public void getACL(final String path, Stat stat, ACLCallback cb, Object ctx) { final String clientPath = path; PathUtils.validatePath(clientPath); final String serverPath = prependChroot(clientPath); RequestHeader h = new RequestHeader(); h.setType(ZooDefs.OpCode.getACL); GetACLRequest request = new GetACLRequest(); request.setPath(serverPath); GetACLResponse response = new GetACLResponse(); cnxn.queuePacket(h, new ReplyHeader(), request, response, cb, clientPath, serverPath, ctx, null); } /** * Set the ACL for the node of the given path if such a node exists and the * given aclVersion matches the acl version of the node. Return the stat of the * node. *

* A KeeperException with error code KeeperException.NoNode will be thrown * if no node with the given path exists. *

* A KeeperException with error code KeeperException.BadVersion will be * thrown if the given aclVersion does not match the node's aclVersion. * * @param path the given path for the node * @param acl the given acl for the node * @param aclVersion the given acl version of the node * @return the stat of the node. * @throws InterruptedException If the server transaction is interrupted. * @throws KeeperException If the server signals an error with a non-zero error code. * @throws org.apache.zookeeper.KeeperException.InvalidACLException If the acl is invalide. * @throws IllegalArgumentException if an invalid path is specified */ public Stat setACL(final String path, List acl, int aclVersion) throws KeeperException, InterruptedException { final String clientPath = path; PathUtils.validatePath(clientPath); validateACL(acl); final String serverPath = prependChroot(clientPath); RequestHeader h = new RequestHeader(); h.setType(ZooDefs.OpCode.setACL); SetACLRequest request = new SetACLRequest(); request.setPath(serverPath); request.setAcl(acl); request.setVersion(aclVersion); SetACLResponse response = new SetACLResponse(); ReplyHeader r = cnxn.submitRequest(h, request, response, null); if (r.getErr() != 0) { throw KeeperException.create(KeeperException.Code.get(r.getErr()), clientPath); } return response.getStat(); } /** * The asynchronous version of setACL. * * @see #setACL(String, List, int) */ public void setACL(final String path, List acl, int version, StatCallback cb, Object ctx) { final String clientPath = path; PathUtils.validatePath(clientPath); final String serverPath = prependChroot(clientPath); RequestHeader h = new RequestHeader(); h.setType(ZooDefs.OpCode.setACL); SetACLRequest request = new SetACLRequest(); request.setPath(serverPath); request.setAcl(acl); request.setVersion(version); SetACLResponse response = new SetACLResponse(); cnxn.queuePacket(h, new ReplyHeader(), request, response, cb, clientPath, serverPath, ctx, null); } /** * Return the list of the children of the node of the given path. *

* If the watch is non-null and the call is successful (no exception is thrown), * a watch will be left on the node with the given path. The watch will be * triggered by a successful operation that deletes the node of the given * path or creates/delete a child under the node. *

* The list of children returned is not sorted and no guarantee is provided * as to its natural or lexical order. *

* A KeeperException with error code KeeperException.NoNode will be thrown * if no node with the given path exists. * * @param path * @param watcher explicit watcher * @return an unordered array of children of the node with the given path * @throws InterruptedException If the server transaction is interrupted. * @throws KeeperException If the server signals an error with a non-zero error code. * @throws IllegalArgumentException if an invalid path is specified */ public List getChildren(final String path, Watcher watcher) throws KeeperException, InterruptedException { final String clientPath = path; PathUtils.validatePath(clientPath); // the watch contains the un-chroot path WatchRegistration wcb = null; if (watcher != null) { wcb = new ChildWatchRegistration(watcher, clientPath); } final String serverPath = prependChroot(clientPath); RequestHeader h = new RequestHeader(); h.setType(ZooDefs.OpCode.getChildren); GetChildrenRequest request = new GetChildrenRequest(); request.setPath(serverPath); request.setWatch(watcher != null); GetChildrenResponse response = new GetChildrenResponse(); ReplyHeader r = cnxn.submitRequest(h, request, response, wcb); if (r.getErr() != 0) { throw KeeperException.create(KeeperException.Code.get(r.getErr()), clientPath); } return response.getChildren(); } /** * Return the list of the children of the node of the given path. *

* If the watch is true and the call is successful (no exception is thrown), * a watch will be left on the node with the given path. The watch will be * triggered by a successful operation that deletes the node of the given * path or creates/delete a child under the node. *

* The list of children returned is not sorted and no guarantee is provided * as to its natural or lexical order. *

* A KeeperException with error code KeeperException.NoNode will be thrown * if no node with the given path exists. * * @param path the node path * @param watch whether need to watch this node * @return an unordered array of children of the node with the given path * @throws IllegalStateException if watch this node with a null default watcher * @throws InterruptedException If the server transaction is interrupted. * @throws KeeperException If the server signals an error with a non-zero error code. */ public List getChildren(String path, boolean watch) throws KeeperException, InterruptedException { return getChildren(path, getDefaultWatcher(watch)); } /** * The asynchronous version of getChildren. * * @see #getChildren(String, Watcher) */ public void getChildren(final String path, Watcher watcher, ChildrenCallback cb, Object ctx) { final String clientPath = path; PathUtils.validatePath(clientPath); // the watch contains the un-chroot path WatchRegistration wcb = null; if (watcher != null) { wcb = new ChildWatchRegistration(watcher, clientPath); } final String serverPath = prependChroot(clientPath); RequestHeader h = new RequestHeader(); h.setType(ZooDefs.OpCode.getChildren); GetChildrenRequest request = new GetChildrenRequest(); request.setPath(serverPath); request.setWatch(watcher != null); GetChildrenResponse response = new GetChildrenResponse(); cnxn.queuePacket(h, new ReplyHeader(), request, response, cb, clientPath, serverPath, ctx, wcb); } /** * The asynchronous version of getChildren. * * @throws IllegalStateException if watch this node with a null default watcher * * @see #getChildren(String, boolean) */ public void getChildren(String path, boolean watch, ChildrenCallback cb, Object ctx) { getChildren(path, getDefaultWatcher(watch), cb, ctx); } /** * For the given znode path return the stat and children list. *

* If the watch is non-null and the call is successful (no exception is thrown), * a watch will be left on the node with the given path. The watch will be * triggered by a successful operation that deletes the node of the given * path or creates/delete a child under the node. *

* The list of children returned is not sorted and no guarantee is provided * as to its natural or lexical order. *

* A KeeperException with error code KeeperException.NoNode will be thrown * if no node with the given path exists. * * @since 3.3.0 * * @param path * @param watcher explicit watcher * @param stat stat of the znode designated by path * @return an unordered array of children of the node with the given path * @throws InterruptedException If the server transaction is interrupted. * @throws KeeperException If the server signals an error with a non-zero error code. * @throws IllegalArgumentException if an invalid path is specified */ public List getChildren( final String path, Watcher watcher, Stat stat) throws KeeperException, InterruptedException { final String clientPath = path; PathUtils.validatePath(clientPath); // the watch contains the un-chroot path WatchRegistration wcb = null; if (watcher != null) { wcb = new ChildWatchRegistration(watcher, clientPath); } final String serverPath = prependChroot(clientPath); RequestHeader h = new RequestHeader(); h.setType(ZooDefs.OpCode.getChildren2); GetChildren2Request request = new GetChildren2Request(); request.setPath(serverPath); request.setWatch(watcher != null); GetChildren2Response response = new GetChildren2Response(); ReplyHeader r = cnxn.submitRequest(h, request, response, wcb); if (r.getErr() != 0) { throw KeeperException.create(KeeperException.Code.get(r.getErr()), clientPath); } if (stat != null) { DataTree.copyStat(response.getStat(), stat); } return response.getChildren(); } /** * For the given znode path return the stat and children list. *

* If the watch is true and the call is successful (no exception is thrown), * a watch will be left on the node with the given path. The watch will be * triggered by a successful operation that deletes the node of the given * path or creates/delete a child under the node. *

* The list of children returned is not sorted and no guarantee is provided * as to its natural or lexical order. *

* A KeeperException with error code KeeperException.NoNode will be thrown * if no node with the given path exists. * * @since 3.3.0 * * @param path the node path * @param watch whether need to watch this node * @param stat stat of the znode designated by path * @return an unordered array of children of the node with the given path * @throws IllegalStateException if watch this node with a null default watcher * @throws InterruptedException If the server transaction is interrupted. * @throws KeeperException If the server signals an error with a non-zero * error code. */ public List getChildren( String path, boolean watch, Stat stat) throws KeeperException, InterruptedException { return getChildren(path, getDefaultWatcher(watch), stat); } /** * The asynchronous version of getChildren. * * @since 3.3.0 * * @see #getChildren(String, Watcher, Stat) */ public void getChildren(final String path, Watcher watcher, Children2Callback cb, Object ctx) { final String clientPath = path; PathUtils.validatePath(clientPath); // the watch contains the un-chroot path WatchRegistration wcb = null; if (watcher != null) { wcb = new ChildWatchRegistration(watcher, clientPath); } final String serverPath = prependChroot(clientPath); RequestHeader h = new RequestHeader(); h.setType(ZooDefs.OpCode.getChildren2); GetChildren2Request request = new GetChildren2Request(); request.setPath(serverPath); request.setWatch(watcher != null); GetChildren2Response response = new GetChildren2Response(); cnxn.queuePacket(h, new ReplyHeader(), request, response, cb, clientPath, serverPath, ctx, wcb); } /** * The asynchronous version of getChildren. * * @since 3.3.0 * * @throws IllegalStateException if watch this node with a null default watcher * * @see #getChildren(String, boolean, Stat) */ public void getChildren(String path, boolean watch, Children2Callback cb, Object ctx) { getChildren(path, getDefaultWatcher(watch), cb, ctx); } /** * Synchronously gets all numbers of children nodes under a specific path * * @since 3.6.0 * @param path * @return Children nodes count under path * @throws KeeperException * @throws InterruptedException */ public int getAllChildrenNumber(final String path) throws KeeperException, InterruptedException { final String clientPath = path; PathUtils.validatePath(clientPath); final String serverPath = prependChroot(clientPath); RequestHeader h = new RequestHeader(); h.setType(ZooDefs.OpCode.getAllChildrenNumber); GetAllChildrenNumberRequest request = new GetAllChildrenNumberRequest(serverPath); GetAllChildrenNumberResponse response = new GetAllChildrenNumberResponse(); ReplyHeader r = cnxn.submitRequest(h, request, response, null); if (r.getErr() != 0) { throw KeeperException.create(KeeperException.Code.get(r.getErr()), clientPath); } return response.getTotalNumber(); } /** * Asynchronously gets all numbers of children nodes under a specific path * * @since 3.6.0 * @param path */ public void getAllChildrenNumber(final String path, AsyncCallback.AllChildrenNumberCallback cb, Object ctx) { final String clientPath = path; PathUtils.validatePath(clientPath); final String serverPath = prependChroot(clientPath); RequestHeader h = new RequestHeader(); h.setType(ZooDefs.OpCode.getAllChildrenNumber); GetAllChildrenNumberRequest request = new GetAllChildrenNumberRequest(serverPath); GetAllChildrenNumberResponse response = new GetAllChildrenNumberResponse(); cnxn.queuePacket(h, new ReplyHeader(), request, response, cb, clientPath, serverPath, ctx, null); } /** * Synchronously gets all the ephemeral nodes created by this session. * * @since 3.6.0 * */ public List getEphemerals() throws KeeperException, InterruptedException { return getEphemerals("/"); } /** * Synchronously gets all the ephemeral nodes matching prefixPath * created by this session. If prefixPath is "/" then it returns all * ephemerals * * @since 3.6.0 * */ public List getEphemerals(String prefixPath) throws KeeperException, InterruptedException { PathUtils.validatePath(prefixPath); RequestHeader h = new RequestHeader(); h.setType(ZooDefs.OpCode.getEphemerals); GetEphemeralsRequest request = new GetEphemeralsRequest(prefixPath); GetEphemeralsResponse response = new GetEphemeralsResponse(); ReplyHeader r = cnxn.submitRequest(h, request, response, null); if (r.getErr() != 0) { throw KeeperException.create(KeeperException.Code.get(r.getErr())); } return response.getEphemerals(); } /** * Asynchronously gets all the ephemeral nodes matching prefixPath * created by this session. If prefixPath is "/" then it returns all * ephemerals * * @since 3.6.0 * */ public void getEphemerals(String prefixPath, AsyncCallback.EphemeralsCallback cb, Object ctx) { PathUtils.validatePath(prefixPath); RequestHeader h = new RequestHeader(); h.setType(ZooDefs.OpCode.getEphemerals); GetEphemeralsRequest request = new GetEphemeralsRequest(prefixPath); GetEphemeralsResponse response = new GetEphemeralsResponse(); cnxn.queuePacket(h, new ReplyHeader(), request, response, cb, null, null, ctx, null); } /** * Asynchronously gets all the ephemeral nodes created by this session. * ephemerals * * @since 3.6.0 * */ public void getEphemerals(AsyncCallback.EphemeralsCallback cb, Object ctx) { getEphemerals("/", cb, ctx); } /** * Asynchronous sync. Flushes channel between process and leader. * @param path * @param cb a handler for the callback * @param ctx context to be provided to the callback * @throws IllegalArgumentException if an invalid path is specified */ public void sync(final String path, VoidCallback cb, Object ctx) { final String clientPath = path; PathUtils.validatePath(clientPath); final String serverPath = prependChroot(clientPath); RequestHeader h = new RequestHeader(); h.setType(ZooDefs.OpCode.sync); SyncRequest request = new SyncRequest(); SyncResponse response = new SyncResponse(); request.setPath(serverPath); cnxn.queuePacket(h, new ReplyHeader(), request, response, cb, clientPath, serverPath, ctx, null); } /** * For the given znode path, removes the specified watcher of given * watcherType. * *

* Watcher shouldn't be null. A successful call guarantees that, the * removed watcher won't be triggered. *

* * @param path * - the path of the node * @param watcher * - a concrete watcher * @param watcherType * - the type of watcher to be removed * @param local * - whether the watcher can be removed locally when there is no * server connection * @throws InterruptedException * if the server transaction is interrupted. * @throws KeeperException.NoWatcherException * if no watcher exists that match the specified parameters * @throws KeeperException * if the server signals an error with a non-zero error code. * @throws IllegalArgumentException * if any of the following is true: *
    *
  • {@code path} is invalid *
  • {@code watcher} is null *
* * @since 3.5.0 */ public void removeWatches( String path, Watcher watcher, WatcherType watcherType, boolean local) throws InterruptedException, KeeperException { validateWatcher(watcher); removeWatches(ZooDefs.OpCode.checkWatches, path, watcher, watcherType, local); } /** * The asynchronous version of removeWatches. * * @see #removeWatches */ public void removeWatches( String path, Watcher watcher, WatcherType watcherType, boolean local, VoidCallback cb, Object ctx) { validateWatcher(watcher); removeWatches(ZooDefs.OpCode.checkWatches, path, watcher, watcherType, local, cb, ctx); } /** * For the given znode path, removes all the registered watchers of given * watcherType. * *

* A successful call guarantees that, the removed watchers won't be * triggered. *

* * @param path * - the path of the node * @param watcherType * - the type of watcher to be removed * @param local * - whether watches can be removed locally when there is no * server connection * @throws InterruptedException * if the server transaction is interrupted. * @throws KeeperException.NoWatcherException * if no watcher exists that match the specified parameters * @throws KeeperException * if the server signals an error with a non-zero error code. * @throws IllegalArgumentException * if an invalid {@code path} is specified * * @since 3.5.0 */ public void removeAllWatches( String path, WatcherType watcherType, boolean local) throws InterruptedException, KeeperException { removeWatches(ZooDefs.OpCode.removeWatches, path, null, watcherType, local); } /** * The asynchronous version of removeAllWatches. * * @see #removeAllWatches */ public void removeAllWatches(String path, WatcherType watcherType, boolean local, VoidCallback cb, Object ctx) { removeWatches(ZooDefs.OpCode.removeWatches, path, null, watcherType, local, cb, ctx); } /** * Add a watch to the given znode using the given mode. Note: not all * watch types can be set with this method. Only the modes available * in {@link AddWatchMode} can be set with this method. * * @param basePath the path that the watcher applies to * @param watcher the watcher * @param mode type of watcher to add * @throws InterruptedException If the server transaction is interrupted. * @throws KeeperException If the server signals an error with a non-zero * error code. * @since 3.6.0 */ public void addWatch(String basePath, Watcher watcher, AddWatchMode mode) throws KeeperException, InterruptedException { PathUtils.validatePath(basePath); validateWatcher(watcher); String serverPath = prependChroot(basePath); RequestHeader h = new RequestHeader(); h.setType(ZooDefs.OpCode.addWatch); AddWatchRequest request = new AddWatchRequest(serverPath, mode.getMode()); ReplyHeader r = cnxn.submitRequest(h, request, new ErrorResponse(), new AddWatchRegistration(watcher, basePath, mode)); if (r.getErr() != 0) { throw KeeperException.create(KeeperException.Code.get(r.getErr()), basePath); } } /** * Add a watch to the given znode using the given mode. Note: not all * watch types can be set with this method. Only the modes available * in {@link AddWatchMode} can be set with this method. In this version of the method, * the default watcher is used * * @param basePath the path that the watcher applies to * @param mode type of watcher to add * @throws InterruptedException If the server transaction is interrupted. * @throws KeeperException If the server signals an error with a non-zero * error code. * @since 3.6.0 */ public void addWatch( String basePath, AddWatchMode mode ) throws KeeperException, InterruptedException { addWatch(basePath, getWatchManager().getDefaultWatcher(), mode); } /** * Async version of {@link #addWatch(String, Watcher, AddWatchMode)} (see it for details) * * @param basePath the path that the watcher applies to * @param watcher the watcher * @param mode type of watcher to add * @param cb a handler for the callback * @param ctx context to be provided to the callback * @throws IllegalArgumentException if an invalid path is specified * @since 3.6.0 */ public void addWatch( String basePath, Watcher watcher, AddWatchMode mode, VoidCallback cb, Object ctx ) { PathUtils.validatePath(basePath); validateWatcher(watcher); String serverPath = prependChroot(basePath); RequestHeader h = new RequestHeader(); h.setType(ZooDefs.OpCode.addWatch); AddWatchRequest request = new AddWatchRequest(serverPath, mode.getMode()); cnxn.queuePacket(h, new ReplyHeader(), request, new ErrorResponse(), cb, basePath, serverPath, ctx, new AddWatchRegistration(watcher, basePath, mode)); } /** * Async version of {@link #addWatch(String, AddWatchMode)} (see it for details) * * @param basePath the path that the watcher applies to * @param mode type of watcher to add * @param cb a handler for the callback * @param ctx context to be provided to the callback * @throws IllegalArgumentException if an invalid path is specified * @since 3.6.0 */ public void addWatch(String basePath, AddWatchMode mode, VoidCallback cb, Object ctx) { addWatch(basePath, getWatchManager().getDefaultWatcher(), mode, cb, ctx); } private void validateWatcher(Watcher watcher) { if (watcher == null) { throw new IllegalArgumentException("Invalid Watcher, shouldn't be null!"); } } private void removeWatches( int opCode, String path, Watcher watcher, WatcherType watcherType, boolean local) throws InterruptedException, KeeperException { PathUtils.validatePath(path); final String clientPath = path; final String serverPath = prependChroot(clientPath); WatchDeregistration wcb = new WatchDeregistration(clientPath, watcher, watcherType, local, getWatchManager()); RequestHeader h = new RequestHeader(); h.setType(opCode); Record request = getRemoveWatchesRequest(opCode, watcherType, serverPath); ReplyHeader r = cnxn.submitRequest(h, request, null, null, wcb); if (r.getErr() != 0) { throw KeeperException.create(KeeperException.Code.get(r.getErr()), clientPath); } } private void removeWatches( int opCode, String path, Watcher watcher, WatcherType watcherType, boolean local, VoidCallback cb, Object ctx) { PathUtils.validatePath(path); final String clientPath = path; final String serverPath = prependChroot(clientPath); WatchDeregistration wcb = new WatchDeregistration(clientPath, watcher, watcherType, local, getWatchManager()); RequestHeader h = new RequestHeader(); h.setType(opCode); Record request = getRemoveWatchesRequest(opCode, watcherType, serverPath); cnxn.queuePacket(h, new ReplyHeader(), request, null, cb, clientPath, serverPath, ctx, null, wcb); } private Record getRemoveWatchesRequest(int opCode, WatcherType watcherType, final String serverPath) { Record request = null; switch (opCode) { case ZooDefs.OpCode.checkWatches: CheckWatchesRequest chkReq = new CheckWatchesRequest(); chkReq.setPath(serverPath); chkReq.setType(watcherType.getIntValue()); request = chkReq; break; case ZooDefs.OpCode.removeWatches: RemoveWatchesRequest rmReq = new RemoveWatchesRequest(); rmReq.setPath(serverPath); rmReq.setType(watcherType.getIntValue()); request = rmReq; break; default: LOG.warn("unknown type " + opCode); break; } return request; } public States getState() { return cnxn.getState(); } /** * String representation of this ZooKeeper client. Suitable for things * like logging. * * Do NOT count on the format of this string, it may change without * warning. * * @since 3.3.0 */ @Override public String toString() { States state = getState(); return ("State:" + state.toString() + (state.isConnected() ? " Timeout:" + getSessionTimeout() + " " : " ") + cnxn); } /* * Methods to aid in testing follow. * * THESE METHODS ARE EXPECTED TO BE USED FOR TESTING ONLY!!! */ /** * Wait up to wait milliseconds for the underlying threads to shutdown. * THIS METHOD IS EXPECTED TO BE USED FOR TESTING ONLY!!! * * @since 3.3.0 * * @param wait max wait in milliseconds * @return true iff all threads are shutdown, otw false */ protected boolean testableWaitForShutdown(int wait) throws InterruptedException { cnxn.sendThread.join(wait); if (cnxn.sendThread.isAlive()) { return false; } cnxn.eventThread.join(wait); return !cnxn.eventThread.isAlive(); } /** * Returns the address to which the socket is connected. Useful for testing * against an ensemble - test client may need to know which server * to shutdown if interested in verifying that the code handles * disconnection/reconnection correctly. * THIS METHOD IS EXPECTED TO BE USED FOR TESTING ONLY!!! * * @since 3.3.0 * * @return ip address of the remote side of the connection or null if * not connected */ protected SocketAddress testableRemoteSocketAddress() { return cnxn.sendThread.getClientCnxnSocket().getRemoteSocketAddress(); } /** * Returns the local address to which the socket is bound. * THIS METHOD IS EXPECTED TO BE USED FOR TESTING ONLY!!! * * @since 3.3.0 * * @return ip address of the remote side of the connection or null if * not connected */ protected SocketAddress testableLocalSocketAddress() { return cnxn.sendThread.getClientCnxnSocket().getLocalSocketAddress(); } private ClientCnxnSocket getClientCnxnSocket() throws IOException { String clientCnxnSocketName = getClientConfig().getProperty(ZKClientConfig.ZOOKEEPER_CLIENT_CNXN_SOCKET); if (clientCnxnSocketName == null || clientCnxnSocketName.equals(ClientCnxnSocketNIO.class.getSimpleName())) { clientCnxnSocketName = ClientCnxnSocketNIO.class.getName(); } else if (clientCnxnSocketName.equals(ClientCnxnSocketNetty.class.getSimpleName())) { clientCnxnSocketName = ClientCnxnSocketNetty.class.getName(); } try { Constructor clientCxnConstructor = Class.forName(clientCnxnSocketName) .getDeclaredConstructor(ZKClientConfig.class); ClientCnxnSocket clientCxnSocket = (ClientCnxnSocket) clientCxnConstructor.newInstance(getClientConfig()); return clientCxnSocket; } catch (Exception e) { throw new IOException("Couldn't instantiate " + clientCnxnSocketName, e); } } /** * Return the default watcher of this instance if required. * * @param required if the default watcher required * @return the default watcher if required, otherwise {@code null}. * @throws IllegalStateException if a null default watcher is required */ private Watcher getDefaultWatcher(boolean required) { if (required) { final Watcher defaultWatcher = getWatchManager().getDefaultWatcher(); if (defaultWatcher != null) { return defaultWatcher; } else { throw new IllegalStateException("Default watcher is required, but it is null."); } } return null; } /** * Validates the provided ACL list for null, empty or null value in it. * * @param acl * ACL list * @throws KeeperException.InvalidACLException * if ACL list is not valid */ private void validateACL(List acl) throws KeeperException.InvalidACLException { if (acl == null || acl.isEmpty() || acl.contains(null)) { throw new KeeperException.InvalidACLException(); } } /** * Gives all authentication information added into the current session. * * @return list of authentication info * @throws InterruptedException when interrupted */ public synchronized List whoAmI() throws InterruptedException { RequestHeader h = new RequestHeader(); h.setType(ZooDefs.OpCode.whoAmI); WhoAmIResponse response = new WhoAmIResponse(); cnxn.submitRequest(h, null, response, null); return response.getClientInfo(); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy