[KYUUBI-SHADED #4] Copy StaticHostProvider from Zookeeper 3.4.14

### _Why are the changes needed?_

Simply copy `StaticHostProvider` from Zookeeper 3.4.14, to pave the way for fixing ZOOKEEPER-3779

### _How was this patch tested?_
- [ ] Add some test cases that check the changes thoroughly including negative and positive cases if possible

- [ ] Add screenshots for manual tests if appropriate

- [ ] [Run test](https://kyuubi.readthedocs.io/en/master/develop_tools/testing.html#running-tests) locally before make a pull request

Closes #4 from pan3793/zk-34.

6c588c9 [Cheng Pan] Copy StaticHostProvider from Zookeeper 3.4.14

Authored-by: Cheng Pan <chengpan@apache.org>
Signed-off-by: Cheng Pan <chengpan@apache.org>
diff --git a/kyuubi-shaded-zookeeper-parent/kyuubi-shaded-zookeeper-34/pom.xml b/kyuubi-shaded-zookeeper-parent/kyuubi-shaded-zookeeper-34/pom.xml
index 3faf27d..c6b8e1d 100644
--- a/kyuubi-shaded-zookeeper-parent/kyuubi-shaded-zookeeper-34/pom.xml
+++ b/kyuubi-shaded-zookeeper-parent/kyuubi-shaded-zookeeper-34/pom.xml
@@ -33,6 +33,8 @@
     <properties>
         <zookeeper.version>3.4.14</zookeeper.version>
         <curator.version>4.2.0</curator.version>
+        <slf4j.version>1.7.25</slf4j.version>
+        <yetus.version>0.5.0</yetus.version>
     </properties>
 
     <dependencyManagement>
@@ -47,6 +49,18 @@
 
     <dependencies>
         <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+            <version>${slf4j.version}</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.yetus</groupId>
+            <artifactId>audience-annotations</artifactId>
+            <version>${yetus.version}</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
             <groupId>org.apache.zookeeper</groupId>
             <artifactId>zookeeper</artifactId>
             <exclusions>
diff --git a/kyuubi-shaded-zookeeper-parent/kyuubi-shaded-zookeeper-34/src/main/java/org/apache/zookeeper/client/StaticHostProvider.java b/kyuubi-shaded-zookeeper-parent/kyuubi-shaded-zookeeper-34/src/main/java/org/apache/zookeeper/client/StaticHostProvider.java
new file mode 100644
index 0000000..8a24783
--- /dev/null
+++ b/kyuubi-shaded-zookeeper-parent/kyuubi-shaded-zookeeper-34/src/main/java/org/apache/zookeeper/client/StaticHostProvider.java
@@ -0,0 +1,170 @@
+/**
+ * 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
+ *
+ * <p>http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * <p>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.client;
+
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import org.apache.yetus.audience.InterfaceAudience;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Most simple HostProvider, resolves on every next() call.
+ *
+ * <p>Please be aware that although this class doesn't do any DNS caching, there're multiple levels
+ * of caching already present across the stack like in JVM, OS level, hardware, etc. The best we
+ * could do here is to get the most recent address from the underlying system which is considered
+ * up-to-date.
+ */
+@InterfaceAudience.Public
+public final class StaticHostProvider implements HostProvider {
+  public interface Resolver {
+    InetAddress[] getAllByName(String name) throws UnknownHostException;
+  }
+
+  private static final Logger LOG = LoggerFactory.getLogger(StaticHostProvider.class);
+
+  private final List<InetSocketAddress> serverAddresses = new ArrayList<InetSocketAddress>(5);
+
+  private int lastIndex = -1;
+
+  private int currentIndex = -1;
+
+  private Resolver resolver;
+
+  /**
+   * Constructs a SimpleHostSet.
+   *
+   * @param serverAddresses possibly unresolved ZooKeeper server addresses
+   * @throws IllegalArgumentException if serverAddresses is empty or resolves to an empty list
+   */
+  public StaticHostProvider(Collection<InetSocketAddress> serverAddresses) {
+    this.resolver =
+        new Resolver() {
+          @Override
+          public InetAddress[] getAllByName(String name) throws UnknownHostException {
+            return InetAddress.getAllByName(name);
+          }
+        };
+    init(serverAddresses);
+  }
+
+  /**
+   * Introduced for testing purposes. getAllByName() is a static method of InetAddress, therefore
+   * cannot be easily mocked. By abstraction of Resolver interface we can easily inject a mocked
+   * implementation in tests.
+   *
+   * @param serverAddresses possibly unresolved ZooKeeper server addresses
+   * @param resolver custom resolver implementation
+   * @throws IllegalArgumentException if serverAddresses is empty or resolves to an empty list
+   */
+  public StaticHostProvider(Collection<InetSocketAddress> serverAddresses, Resolver resolver) {
+    this.resolver = resolver;
+    init(serverAddresses);
+  }
+
+  /**
+   * Common init method for all constructors. Resolve all unresolved server addresses, put them in a
+   * list and shuffle.
+   */
+  private void init(Collection<InetSocketAddress> serverAddresses) {
+    if (serverAddresses.isEmpty()) {
+      throw new IllegalArgumentException("A HostProvider may not be empty!");
+    }
+
+    this.serverAddresses.addAll(serverAddresses);
+    Collections.shuffle(this.serverAddresses);
+  }
+
+  /**
+   * Evaluate to a hostname if one is available and otherwise it returns the string representation
+   * of the IP address.
+   *
+   * <p>In Java 7, we have a method getHostString, but earlier versions do not support it. This
+   * method is to provide a replacement for InetSocketAddress.getHostString().
+   *
+   * @param addr
+   * @return Hostname string of address parameter
+   */
+  private String getHostString(InetSocketAddress addr) {
+    String hostString = "";
+
+    if (addr == null) {
+      return hostString;
+    }
+    if (!addr.isUnresolved()) {
+      InetAddress ia = addr.getAddress();
+
+      // If the string starts with '/', then it has no hostname
+      // and we want to avoid the reverse lookup, so we return
+      // the string representation of the address.
+      if (ia.toString().startsWith("/")) {
+        hostString = ia.getHostAddress();
+      } else {
+        hostString = addr.getHostName();
+      }
+    } else {
+      // According to the Java 6 documentation, if the hostname is
+      // unresolved, then the string before the colon is the hostname.
+      String addrString = addr.toString();
+      hostString = addrString.substring(0, addrString.lastIndexOf(':'));
+    }
+
+    return hostString;
+  }
+
+  public int size() {
+    return serverAddresses.size();
+  }
+
+  public InetSocketAddress next(long spinDelay) {
+    currentIndex = ++currentIndex % serverAddresses.size();
+    if (currentIndex == lastIndex && spinDelay > 0) {
+      try {
+        Thread.sleep(spinDelay);
+      } catch (InterruptedException e) {
+        LOG.warn("Unexpected exception", e);
+      }
+    } else if (lastIndex == -1) {
+      // We don't want to sleep on the first ever connect attempt.
+      lastIndex = 0;
+    }
+
+    InetSocketAddress curAddr = serverAddresses.get(currentIndex);
+    try {
+      String curHostString = getHostString(curAddr);
+      List<InetAddress> resolvedAddresses =
+          new ArrayList<InetAddress>(Arrays.asList(this.resolver.getAllByName(curHostString)));
+      if (resolvedAddresses.isEmpty()) {
+        return curAddr;
+      }
+      Collections.shuffle(resolvedAddresses);
+      return new InetSocketAddress(resolvedAddresses.get(0), curAddr.getPort());
+    } catch (UnknownHostException e) {
+      return curAddr;
+    }
+  }
+
+  @Override
+  public void onConnected() {
+    lastIndex = currentIndex;
+  }
+}