You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@helix.apache.org by hu...@apache.org on 2020/01/12 02:26:49 UTC

[helix] 03/03: Implement ZkAccessor

This is an automated email from the ASF dual-hosted git repository.

hulee pushed a commit to branch rest0
in repository https://gitbox.apache.org/repos/asf/helix.git

commit e1f13b81089637f92b7beb5c6bf9b521ec857a4a
Author: Hunter Lee <hu...@linkedin.com>
AuthorDate: Sat Jan 11 18:25:55 2020 -0800

    Implement ZkAccessor
---
 .../org/apache/helix/rest/common/ServletType.java  | 12 +++-
 .../resources/zookeeper/ZooKeeperAccessor.java     | 82 +++++++++++++++-------
 .../helix/rest/server/TestZooKeeperAccessor.java   |  2 +-
 3 files changed, 68 insertions(+), 28 deletions(-)

diff --git a/helix-rest/src/main/java/org/apache/helix/rest/common/ServletType.java b/helix-rest/src/main/java/org/apache/helix/rest/common/ServletType.java
index bbff2d6..f068f95 100644
--- a/helix-rest/src/main/java/org/apache/helix/rest/common/ServletType.java
+++ b/helix-rest/src/main/java/org/apache/helix/rest/common/ServletType.java
@@ -21,21 +21,27 @@ package org.apache.helix.rest.common;
 
 import org.apache.helix.rest.server.resources.helix.AbstractHelixResource;
 import org.apache.helix.rest.server.resources.metadata.NamespacesAccessor;
+import org.apache.helix.rest.server.resources.zookeeper.ZooKeeperAccessor;
+
 
 public enum ServletType {
   /**
    * Servlet serving default API endpoints (/admin/v2/clusters/...)
    */
   DEFAULT_SERVLET(HelixRestNamespace.DEFAULT_NAMESPACE_PATH_SPEC,
-      new String[] { AbstractHelixResource.class.getPackage().getName(),
-          NamespacesAccessor.class.getPackage().getName()
+      new String[] {
+          AbstractHelixResource.class.getPackage().getName(),
+          NamespacesAccessor.class.getPackage().getName(),
+          ZooKeeperAccessor.class.getPackage().getName()
       }),
 
   /**
    * Servlet serving namespaced API endpoints (/admin/v2/namespaces/{namespaceName})
    */
   COMMON_SERVLET("/namespaces/%s/*",
-      new String[] { AbstractHelixResource.class.getPackage().getName(),
+      new String[] {
+          AbstractHelixResource.class.getPackage().getName(),
+          ZooKeeperAccessor.class.getPackage().getName()
       });
 
   private final String _servletPathSpecTemplate;
diff --git a/helix-rest/src/main/java/org/apache/helix/rest/server/resources/zookeeper/ZooKeeperAccessor.java b/helix-rest/src/main/java/org/apache/helix/rest/server/resources/zookeeper/ZooKeeperAccessor.java
index 4752168..fc2abe0 100644
--- a/helix-rest/src/main/java/org/apache/helix/rest/server/resources/zookeeper/ZooKeeperAccessor.java
+++ b/helix-rest/src/main/java/org/apache/helix/rest/server/resources/zookeeper/ZooKeeperAccessor.java
@@ -19,24 +19,21 @@ package org.apache.helix.rest.server.resources.zookeeper;
  * under the License.
  */
 
-import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import javax.ws.rs.GET;
 import javax.ws.rs.Path;
 import javax.ws.rs.PathParam;
+import javax.ws.rs.QueryParam;
 import javax.ws.rs.WebApplicationException;
 import javax.ws.rs.core.Response;
 
+import com.google.common.collect.ImmutableMap;
 import org.apache.helix.AccessOption;
-import org.apache.helix.HelixAdmin;
-import org.apache.helix.ZNRecord;
 import org.apache.helix.manager.zk.ZkBaseDataAccessor;
 import org.apache.helix.rest.common.ContextPropertyKeys;
 import org.apache.helix.rest.server.ServerContext;
 import org.apache.helix.rest.server.resources.AbstractResource;
-import org.apache.helix.rest.server.resources.helix.ClusterAccessor;
-import org.codehaus.jackson.node.ObjectNode;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -48,42 +45,68 @@ import org.slf4j.LoggerFactory;
 @Path("/zookeeper")
 public class ZooKeeperAccessor extends AbstractResource {
   private static final Logger LOG = LoggerFactory.getLogger(ZooKeeperAccessor.class.getName());
+  private ZkBaseDataAccessor<byte[]> _zkBaseDataAccessor;
 
-  private ServerContext _serverContext =
-      (ServerContext) _application.getProperties().get(ContextPropertyKeys.SERVER_CONTEXT.name());
-  private ZkBaseDataAccessor<byte[]> _zkBaseDataAccessor =
-      _serverContext.getByteArrayZkBaseDataAccessor();
+  public enum ZooKeeperCommand {
+    exists, getBinaryData, getStringData, getChildren
+  }
 
   @GET
   @Path("{path: .+}")
-  public Response get(@PathParam("path") String path)
+  public Response get(@PathParam("path") String path, @QueryParam("command") String commandStr) {
+    ZooKeeperCommand cmd;
+    try {
+      cmd = ZooKeeperCommand.valueOf(commandStr);
+    } catch (Exception e) {
+      return badRequest("Invalid ZooKeeper command: " + commandStr);
+    }
+
+    // Lazily initialize ZkBaseDataAccessor
+    ServerContext _serverContext =
+        (ServerContext) _application.getProperties().get(ContextPropertyKeys.SERVER_CONTEXT.name());
+    _zkBaseDataAccessor = _serverContext.getByteArrayZkBaseDataAccessor();
+
+    // Need to prepend a "/" since JAX-RS regex removes it
+    path = "/" + path;
+    switch (cmd) {
+      case exists:
+        return exists(path);
+      case getBinaryData:
+        return getData(path, cmd);
+      case getStringData:
+        return getData(path, cmd);
+      case getChildren:
+        return getChildren(path);
+      default:
+        LOG.error("Unsupported command :" + commandStr);
+        return badRequest("Unsupported command :" + commandStr);
+    }
+  }
 
   /**
    * Checks if a ZNode exists in the given path.
    * @param path
    * @return true if a ZNode exists, false otherwise
    */
-  @GET
-  @Path("exists/{path: .+}")
-  public Response exists(@PathParam("path") String path) {
+  private Response exists(String path) {
     if (!isPathValid(path)) {
       String errMsg = "exists(): The given path {} is not a valid ZooKeeper path!" + path;
       LOG.error(errMsg);
       return badRequest(errMsg);
     }
 
-    boolean exists = _zkBaseDataAccessor.exists(path, AccessOption.PERSISTENT);
-    return JSONRepresentation(exists);
+    Map<String, Boolean> result = ImmutableMap.of(ZooKeeperCommand.exists.name(),
+        _zkBaseDataAccessor.exists(path, AccessOption.PERSISTENT));
+    return JSONRepresentation(result);
   }
 
   /**
    * Reads the given path from ZooKeeper and returns the binary data for the ZNode.
    * @param path
+   * @param command denotes whether return type should be binary or String
    * @return binary data in the ZNode
    */
-  @GET
-  @Path("getData/{path: .+}")
-  public Response getData(@PathParam("path") String path) {
+  private Response getData(String path, ZooKeeperCommand command) {
     if (!isPathValid(path)) {
       String errMsg = "getData(): The given path {} is not a valid ZooKeeper path!" + path;
       LOG.error(errMsg);
@@ -92,7 +115,19 @@ public class ZooKeeperAccessor extends AbstractResource {
 
     if (_zkBaseDataAccessor.exists(path, AccessOption.PERSISTENT)) {
       byte[] bytes = _zkBaseDataAccessor.get(path, null, AccessOption.PERSISTENT);
-      return JSONRepresentation(bytes);
+      switch (command) {
+        case getBinaryData:
+          Map<String, byte[]> binaryResult =
+              ImmutableMap.of(ZooKeeperCommand.getBinaryData.name(), bytes);
+          return JSONRepresentation(binaryResult);
+        case getStringData:
+          Map<String, String> stringResult =
+              ImmutableMap.of(ZooKeeperCommand.getStringData.name(), new String(bytes));
+          return JSONRepresentation(stringResult);
+        default:
+          LOG.error("Unsupported command :" + command);
+          return badRequest("Unsupported command :" + command);
+      }
     } else {
       throw new WebApplicationException(Response.status(Response.Status.NOT_FOUND)
           .entity(String.format("The ZNode at path %s does not exist", path)).build());
@@ -104,9 +139,7 @@ public class ZooKeeperAccessor extends AbstractResource {
    * @param path
    * @return list of child ZNodes
    */
-  @GET
-  @Path("getChildren/{path: .+}")
-  public Response getChildren(@PathParam("path") String path) {
+  private Response getChildren(String path) {
     if (!isPathValid(path)) {
       String errMsg = "getChildren(): The given path {} is not a valid ZooKeeper path!" + path;
       LOG.error(errMsg);
@@ -114,8 +147,9 @@ public class ZooKeeperAccessor extends AbstractResource {
     }
 
     if (_zkBaseDataAccessor.exists(path, AccessOption.PERSISTENT)) {
-      List<String> children = _zkBaseDataAccessor.getChildNames(path, AccessOption.PERSISTENT);
-      return JSONRepresentation(children);
+      Map<String, List<String>> result = ImmutableMap.of(ZooKeeperCommand.getChildren.name(),
+          _zkBaseDataAccessor.getChildNames(path, AccessOption.PERSISTENT));
+      return JSONRepresentation(result);
     } else {
       throw new WebApplicationException(Response.status(Response.Status.NOT_FOUND)
           .entity(String.format("The ZNode at path %s does not exist", path)).build());
diff --git a/helix-rest/src/test/java/org/apache/helix/rest/server/TestZooKeeperAccessor.java b/helix-rest/src/test/java/org/apache/helix/rest/server/TestZooKeeperAccessor.java
index a46f0fd..175f0b2 100644
--- a/helix-rest/src/test/java/org/apache/helix/rest/server/TestZooKeeperAccessor.java
+++ b/helix-rest/src/test/java/org/apache/helix/rest/server/TestZooKeeperAccessor.java
@@ -67,7 +67,7 @@ public class TestZooKeeperAccessor extends AbstractTestClass {
     Assert.assertTrue(_testBaseDataAccessor.create(path, content.getBytes(), AccessOption.PERSISTENT));
     Assert.assertTrue(_testBaseDataAccessor.exists(path, AccessOption.PERSISTENT));
 
-    String data = new JerseyUriRequestBuilder("zookeeper/exists{}").format(path)
+    String data = new JerseyUriRequestBuilder("zookeeper{}?command=exists").format(path)
         .isBodyReturnExpected(true).get(this);
 
     // Clean up