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

liuxun pushed a commit to branch branch-0.6
in repository https://gitbox.apache.org/repos/asf/gravitino.git


The following commit(s) were added to refs/heads/branch-0.6 by this push:
     new 4e05383f1 [#4154] improvment(client): Move access control function to 
GravitinoClient (#4391)
4e05383f1 is described below

commit 4e05383f15bdc3b18ab51ec3e2f190eb7b8c17b9
Author: roryqi <[email protected]>
AuthorDate: Tue Aug 6 17:41:15 2024 +0800

    [#4154] improvment(client): Move access control function to GravitinoClient 
(#4391)
    
    ### What changes were proposed in this pull request?
    
     Move access control function to GravitinoClient
    
    ### Why are the changes needed?
    
    Fix: #4154
    
    ### Does this PR introduce _any_ user-facing change? No.
    
    ### How was this patch tested?
    Modified the UTs.
---
 .../gravitino/client/GravitinoAdminClient.java     | 361 ---------------------
 .../apache/gravitino/client/GravitinoClient.java   | 195 +++++++++++
 .../apache/gravitino/client/GravitinoMetalake.java | 351 ++++++++++++++++++++
 .../apache/gravitino/client/TestPermission.java    |  38 ++-
 .../java/org/apache/gravitino/client/TestRole.java |  68 ++--
 .../org/apache/gravitino/client/TestUserGroup.java |  71 ++--
 6 files changed, 659 insertions(+), 425 deletions(-)

diff --git 
a/clients/client-java/src/main/java/org/apache/gravitino/client/GravitinoAdminClient.java
 
b/clients/client-java/src/main/java/org/apache/gravitino/client/GravitinoAdminClient.java
index b70839733..936edcf3c 100644
--- 
a/clients/client-java/src/main/java/org/apache/gravitino/client/GravitinoAdminClient.java
+++ 
b/clients/client-java/src/main/java/org/apache/gravitino/client/GravitinoAdminClient.java
@@ -27,35 +27,14 @@ import java.util.Map;
 import java.util.stream.Collectors;
 import org.apache.gravitino.MetalakeChange;
 import org.apache.gravitino.SupportsMetalakes;
-import org.apache.gravitino.authorization.Group;
-import org.apache.gravitino.authorization.Role;
-import org.apache.gravitino.authorization.SecurableObject;
-import org.apache.gravitino.authorization.User;
-import org.apache.gravitino.dto.authorization.SecurableObjectDTO;
-import org.apache.gravitino.dto.requests.GroupAddRequest;
 import org.apache.gravitino.dto.requests.MetalakeCreateRequest;
 import org.apache.gravitino.dto.requests.MetalakeUpdateRequest;
 import org.apache.gravitino.dto.requests.MetalakeUpdatesRequest;
-import org.apache.gravitino.dto.requests.RoleCreateRequest;
-import org.apache.gravitino.dto.requests.RoleGrantRequest;
-import org.apache.gravitino.dto.requests.RoleRevokeRequest;
-import org.apache.gravitino.dto.requests.UserAddRequest;
-import org.apache.gravitino.dto.responses.DeleteResponse;
 import org.apache.gravitino.dto.responses.DropResponse;
-import org.apache.gravitino.dto.responses.GroupResponse;
 import org.apache.gravitino.dto.responses.MetalakeListResponse;
 import org.apache.gravitino.dto.responses.MetalakeResponse;
-import org.apache.gravitino.dto.responses.RemoveResponse;
-import org.apache.gravitino.dto.responses.RoleResponse;
-import org.apache.gravitino.dto.responses.UserResponse;
-import org.apache.gravitino.exceptions.GroupAlreadyExistsException;
 import org.apache.gravitino.exceptions.MetalakeAlreadyExistsException;
-import org.apache.gravitino.exceptions.NoSuchGroupException;
 import org.apache.gravitino.exceptions.NoSuchMetalakeException;
-import org.apache.gravitino.exceptions.NoSuchRoleException;
-import org.apache.gravitino.exceptions.NoSuchUserException;
-import org.apache.gravitino.exceptions.RoleAlreadyExistsException;
-import org.apache.gravitino.exceptions.UserAlreadyExistsException;
 
 /**
  * Apache Gravitino Client for the administrator to interact with the 
Gravitino API, allowing the
@@ -64,11 +43,6 @@ import 
org.apache.gravitino.exceptions.UserAlreadyExistsException;
  * <p>Normal users should use {@link GravitinoClient} to connect with the 
Gravitino server.
  */
 public class GravitinoAdminClient extends GravitinoClientBase implements 
SupportsMetalakes {
-  private static final String API_METALAKES_USERS_PATH = 
"api/metalakes/%s/users/%s";
-  private static final String API_METALAKES_GROUPS_PATH = 
"api/metalakes/%s/groups/%s";
-  private static final String API_METALAKES_ROLES_PATH = 
"api/metalakes/%s/roles/%s";
-  private static final String API_PERMISSION_PATH = 
"api/metalakes/%s/permissions/%s";
-  private static final String BLANK_PLACE_HOLDER = "";
 
   /**
    * Constructs a new GravitinoClient with the given URI, authenticator and 
AuthDataProvider.
@@ -189,341 +163,6 @@ public class GravitinoAdminClient extends 
GravitinoClientBase implements Support
     return resp.dropped();
   }
 
-  /**
-   * Adds a new User.
-   *
-   * @param metalake The Metalake of the User.
-   * @param user The name of the User.
-   * @return The added User instance.
-   * @throws UserAlreadyExistsException If a User with the same name already 
exists.
-   * @throws NoSuchMetalakeException If the Metalake with the given name does 
not exist.
-   * @throws RuntimeException If adding the User encounters storage issues.
-   */
-  public User addUser(String metalake, String user)
-      throws UserAlreadyExistsException, NoSuchMetalakeException {
-    UserAddRequest req = new UserAddRequest(user);
-    req.validate();
-
-    UserResponse resp =
-        restClient.post(
-            String.format(API_METALAKES_USERS_PATH, metalake, 
BLANK_PLACE_HOLDER),
-            req,
-            UserResponse.class,
-            Collections.emptyMap(),
-            ErrorHandlers.userErrorHandler());
-    resp.validate();
-
-    return resp.getUser();
-  }
-
-  /**
-   * Removes a User.
-   *
-   * @param metalake The Metalake of the User.
-   * @param user The name of the User.
-   * @return True if the User was successfully removed, false only when 
there's no such user,
-   *     otherwise it will throw an exception.
-   * @throws NoSuchMetalakeException If the Metalake with the given name does 
not exist.
-   * @throws RuntimeException If removing the User encounters storage issues.
-   */
-  public boolean removeUser(String metalake, String user) throws 
NoSuchMetalakeException {
-    RemoveResponse resp =
-        restClient.delete(
-            String.format(API_METALAKES_USERS_PATH, metalake, user),
-            RemoveResponse.class,
-            Collections.emptyMap(),
-            ErrorHandlers.userErrorHandler());
-    resp.validate();
-
-    return resp.removed();
-  }
-
-  /**
-   * Gets a User.
-   *
-   * @param metalake The Metalake of the User.
-   * @param user The name of the User.
-   * @return The getting User instance.
-   * @throws NoSuchUserException If the User with the given name does not 
exist.
-   * @throws NoSuchMetalakeException If the Metalake with the given name does 
not exist.
-   * @throws RuntimeException If getting the User encounters storage issues.
-   */
-  public User getUser(String metalake, String user)
-      throws NoSuchUserException, NoSuchMetalakeException {
-    UserResponse resp =
-        restClient.get(
-            String.format(API_METALAKES_USERS_PATH, metalake, user),
-            UserResponse.class,
-            Collections.emptyMap(),
-            ErrorHandlers.userErrorHandler());
-    resp.validate();
-
-    return resp.getUser();
-  }
-
-  /**
-   * Adds a new Group.
-   *
-   * @param metalake The Metalake of the Group.
-   * @param group The name of the Group.
-   * @return The Added Group instance.
-   * @throws GroupAlreadyExistsException If a Group with the same name already 
exists.
-   * @throws NoSuchMetalakeException If the Metalake with the given name does 
not exist.
-   * @throws RuntimeException If adding the Group encounters storage issues.
-   */
-  public Group addGroup(String metalake, String group)
-      throws GroupAlreadyExistsException, NoSuchMetalakeException {
-    GroupAddRequest req = new GroupAddRequest(group);
-    req.validate();
-
-    GroupResponse resp =
-        restClient.post(
-            String.format(API_METALAKES_GROUPS_PATH, metalake, 
BLANK_PLACE_HOLDER),
-            req,
-            GroupResponse.class,
-            Collections.emptyMap(),
-            ErrorHandlers.groupErrorHandler());
-    resp.validate();
-
-    return resp.getGroup();
-  }
-
-  /**
-   * Removes a Group.
-   *
-   * @param metalake The Metalake of the Group.
-   * @param group THe name of the Group.
-   * @return True if the Group was successfully removed, false only when 
there's no such group,
-   *     otherwise it will throw an exception.
-   * @throws NoSuchMetalakeException If the Metalake with the given name does 
not exist.
-   * @throws RuntimeException If removing the Group encounters storage issues.
-   */
-  public boolean removeGroup(String metalake, String group) throws 
NoSuchMetalakeException {
-    RemoveResponse resp =
-        restClient.delete(
-            String.format(API_METALAKES_GROUPS_PATH, metalake, group),
-            RemoveResponse.class,
-            Collections.emptyMap(),
-            ErrorHandlers.groupErrorHandler());
-    resp.validate();
-
-    return resp.removed();
-  }
-
-  /**
-   * Gets a Group.
-   *
-   * @param metalake The Metalake of the Group.
-   * @param group The name of the Group.
-   * @return The getting Group instance.
-   * @throws NoSuchGroupException If the Group with the given name does not 
exist.
-   * @throws NoSuchMetalakeException If the Metalake with the given name does 
not exist.
-   * @throws RuntimeException If getting the Group encounters storage issues.
-   */
-  public Group getGroup(String metalake, String group)
-      throws NoSuchGroupException, NoSuchMetalakeException {
-    GroupResponse resp =
-        restClient.get(
-            String.format(API_METALAKES_GROUPS_PATH, metalake, group),
-            GroupResponse.class,
-            Collections.emptyMap(),
-            ErrorHandlers.groupErrorHandler());
-    resp.validate();
-
-    return resp.getGroup();
-  }
-
-  /**
-   * Gets a Role.
-   *
-   * @param metalake The Metalake of the Role.
-   * @param role The name of the Role.
-   * @return The getting Role instance.
-   * @throws NoSuchRoleException If the Role with the given name does not 
exist.
-   * @throws NoSuchMetalakeException If the Metalake with the given name does 
not exist.
-   * @throws RuntimeException If getting the Role encounters storage issues.
-   */
-  public Role getRole(String metalake, String role)
-      throws NoSuchRoleException, NoSuchMetalakeException {
-    RoleResponse resp =
-        restClient.get(
-            String.format(API_METALAKES_ROLES_PATH, metalake, role),
-            RoleResponse.class,
-            Collections.emptyMap(),
-            ErrorHandlers.roleErrorHandler());
-    resp.validate();
-
-    return resp.getRole();
-  }
-
-  /**
-   * Deletes a Role.
-   *
-   * @param metalake The Metalake of the Role.
-   * @param role The name of the Role.
-   * @return True if the Role was successfully deleted, false only when 
there's no such role,
-   *     otherwise it will throw an exception.
-   * @throws NoSuchMetalakeException If the Metalake with the given name does 
not exist.
-   * @throws RuntimeException If deleting the Role encounters storage issues.
-   */
-  public boolean deleteRole(String metalake, String role) throws 
NoSuchMetalakeException {
-    DeleteResponse resp =
-        restClient.delete(
-            String.format(API_METALAKES_ROLES_PATH, metalake, role),
-            DeleteResponse.class,
-            Collections.emptyMap(),
-            ErrorHandlers.roleErrorHandler());
-    resp.validate();
-
-    return resp.deleted();
-  }
-
-  /**
-   * Creates a new Role.
-   *
-   * @param metalake The Metalake of the Role.
-   * @param role The name of the Role.
-   * @param properties The properties of the Role.
-   * @param securableObjects The securable objects of the Role.
-   * @return The created Role instance.
-   * @throws RoleAlreadyExistsException If a Role with the same name already 
exists.
-   * @throws NoSuchMetalakeException If the Metalake with the given name does 
not exist.
-   * @throws RuntimeException If creating the Role encounters storage issues.
-   */
-  public Role createRole(
-      String metalake,
-      String role,
-      Map<String, String> properties,
-      List<SecurableObject> securableObjects)
-      throws RoleAlreadyExistsException, NoSuchMetalakeException {
-    RoleCreateRequest req =
-        new RoleCreateRequest(
-            role,
-            properties,
-            securableObjects.stream()
-                .map(DTOConverters::toSecurableObject)
-                .toArray(SecurableObjectDTO[]::new));
-    req.validate();
-
-    RoleResponse resp =
-        restClient.post(
-            String.format(API_METALAKES_ROLES_PATH, metalake, 
BLANK_PLACE_HOLDER),
-            req,
-            RoleResponse.class,
-            Collections.emptyMap(),
-            ErrorHandlers.roleErrorHandler());
-    resp.validate();
-
-    return resp.getRole();
-  }
-  /**
-   * Grant roles to a user.
-   *
-   * @param metalake The metalake of the User.
-   * @param user The name of the User.
-   * @param roles The names of the Role.
-   * @return The Group after granted.
-   * @throws NoSuchUserException If the User with the given name does not 
exist.
-   * @throws NoSuchRoleException If the Role with the given name does not 
exist.
-   * @throws NoSuchMetalakeException If the Metalake with the given name does 
not exist.
-   * @throws RuntimeException If granting roles to a user encounters storage 
issues.
-   */
-  public User grantRolesToUser(String metalake, List<String> roles, String 
user)
-      throws NoSuchUserException, NoSuchRoleException, NoSuchMetalakeException 
{
-    RoleGrantRequest request = new RoleGrantRequest(roles);
-    UserResponse resp =
-        restClient.put(
-            String.format(API_PERMISSION_PATH, metalake, 
String.format("users/%s/grant", user)),
-            request,
-            UserResponse.class,
-            Collections.emptyMap(),
-            ErrorHandlers.permissionOperationErrorHandler());
-    resp.validate();
-
-    return resp.getUser();
-  }
-
-  /**
-   * Grant roles to a group.
-   *
-   * @param metalake The metalake of the Group.
-   * @param group The name of the Group.
-   * @param roles The names of the Role.
-   * @return The Group after granted.
-   * @throws NoSuchGroupException If the Group with the given name does not 
exist.
-   * @throws NoSuchRoleException If the Role with the given name does not 
exist.
-   * @throws NoSuchMetalakeException If the Metalake with the given name does 
not exist.
-   * @throws RuntimeException If granting roles to a group encounters storage 
issues.
-   */
-  public Group grantRolesToGroup(String metalake, List<String> roles, String 
group)
-      throws NoSuchGroupException, NoSuchRoleException, 
NoSuchMetalakeException {
-    RoleGrantRequest request = new RoleGrantRequest(roles);
-    GroupResponse resp =
-        restClient.put(
-            String.format(API_PERMISSION_PATH, metalake, 
String.format("groups/%s/grant", group)),
-            request,
-            GroupResponse.class,
-            Collections.emptyMap(),
-            ErrorHandlers.permissionOperationErrorHandler());
-    resp.validate();
-
-    return resp.getGroup();
-  }
-
-  /**
-   * Revoke roles from a user.
-   *
-   * @param metalake The metalake of the User.
-   * @param user The name of the User.
-   * @param roles The names of the Role.
-   * @return The User after revoked.
-   * @throws NoSuchUserException If the User with the given name does not 
exist.
-   * @throws NoSuchRoleException If the Role with the given name does not 
exist.
-   * @throws NoSuchMetalakeException If the Metalake with the given name does 
not exist.
-   * @throws RuntimeException If revoking roles from a user encounters storage 
issues.
-   */
-  public User revokeRolesFromUser(String metalake, List<String> roles, String 
user)
-      throws NoSuchUserException, NoSuchRoleException, NoSuchMetalakeException 
{
-    RoleRevokeRequest request = new RoleRevokeRequest(roles);
-    UserResponse resp =
-        restClient.put(
-            String.format(API_PERMISSION_PATH, metalake, 
String.format("users/%s/revoke", user)),
-            request,
-            UserResponse.class,
-            Collections.emptyMap(),
-            ErrorHandlers.permissionOperationErrorHandler());
-    resp.validate();
-
-    return resp.getUser();
-  }
-
-  /**
-   * Revoke roles from a group.
-   *
-   * @param metalake The metalake of the Group.
-   * @param group The name of the Group.
-   * @param roles The names of the Role.
-   * @return The Group after revoked.
-   * @throws NoSuchGroupException If the Group with the given name does not 
exist.
-   * @throws NoSuchRoleException If the Role with the given name does not 
exist.
-   * @throws NoSuchMetalakeException If the Metalake with the given name does 
not exist.
-   * @throws RuntimeException If revoking roles from a group encounters 
storage issues.
-   */
-  public Group revokeRolesFromGroup(String metalake, List<String> roles, 
String group)
-      throws NoSuchGroupException, NoSuchRoleException, 
NoSuchMetalakeException {
-    RoleRevokeRequest request = new RoleRevokeRequest(roles);
-    GroupResponse resp =
-        restClient.put(
-            String.format(API_PERMISSION_PATH, metalake, 
String.format("groups/%s/revoke", group)),
-            request,
-            GroupResponse.class,
-            Collections.emptyMap(),
-            ErrorHandlers.permissionOperationErrorHandler());
-    resp.validate();
-
-    return resp.getGroup();
-  }
-
   /**
    * Creates a new builder for constructing a GravitinoClient.
    *
diff --git 
a/clients/client-java/src/main/java/org/apache/gravitino/client/GravitinoClient.java
 
b/clients/client-java/src/main/java/org/apache/gravitino/client/GravitinoClient.java
index a66987f66..335117cac 100644
--- 
a/clients/client-java/src/main/java/org/apache/gravitino/client/GravitinoClient.java
+++ 
b/clients/client-java/src/main/java/org/apache/gravitino/client/GravitinoClient.java
@@ -20,15 +20,26 @@
 package org.apache.gravitino.client;
 
 import com.google.common.base.Preconditions;
+import java.util.List;
 import java.util.Map;
 import org.apache.gravitino.Catalog;
 import org.apache.gravitino.CatalogChange;
 import org.apache.gravitino.SupportsCatalogs;
+import org.apache.gravitino.authorization.Group;
+import org.apache.gravitino.authorization.Role;
+import org.apache.gravitino.authorization.SecurableObject;
+import org.apache.gravitino.authorization.User;
 import org.apache.gravitino.exceptions.CatalogAlreadyExistsException;
+import org.apache.gravitino.exceptions.GroupAlreadyExistsException;
 import org.apache.gravitino.exceptions.NoSuchCatalogException;
+import org.apache.gravitino.exceptions.NoSuchGroupException;
 import org.apache.gravitino.exceptions.NoSuchMetalakeException;
+import org.apache.gravitino.exceptions.NoSuchRoleException;
 import org.apache.gravitino.exceptions.NoSuchTagException;
+import org.apache.gravitino.exceptions.NoSuchUserException;
+import org.apache.gravitino.exceptions.RoleAlreadyExistsException;
 import org.apache.gravitino.exceptions.TagAlreadyExistsException;
+import org.apache.gravitino.exceptions.UserAlreadyExistsException;
 import org.apache.gravitino.tag.Tag;
 import org.apache.gravitino.tag.TagChange;
 import org.apache.gravitino.tag.TagOperations;
@@ -113,6 +124,190 @@ public class GravitinoClient extends GravitinoClientBase
     return getMetalake().dropCatalog(catalogName);
   }
 
+  /**
+   * Adds a new User.
+   *
+   * @param user The name of the User.
+   * @return The added User instance.
+   * @throws UserAlreadyExistsException If a User with the same name already 
exists.
+   * @throws NoSuchMetalakeException If the Metalake with the given name does 
not exist.
+   * @throws RuntimeException If adding the User encounters storage issues.
+   */
+  public User addUser(String user) throws UserAlreadyExistsException, 
NoSuchMetalakeException {
+    return getMetalake().addUser(user);
+  }
+
+  /**
+   * Removes a User.
+   *
+   * @param user The name of the User.
+   * @return True if the User was successfully removed, false only when 
there's no such user,
+   *     otherwise it will throw an exception.
+   * @throws NoSuchMetalakeException If the Metalake with the given name does 
not exist.
+   * @throws RuntimeException If removing the User encounters storage issues.
+   */
+  public boolean removeUser(String user) throws NoSuchMetalakeException {
+    return getMetalake().removeUser(user);
+  }
+
+  /**
+   * Gets a User.
+   *
+   * @param user The name of the User.
+   * @return The getting User instance.
+   * @throws NoSuchUserException If the User with the given name does not 
exist.
+   * @throws NoSuchMetalakeException If the Metalake with the given name does 
not exist.
+   * @throws RuntimeException If getting the User encounters storage issues.
+   */
+  public User getUser(String user) throws NoSuchUserException, 
NoSuchMetalakeException {
+    return getMetalake().getUser(user);
+  }
+
+  /**
+   * Adds a new Group.
+   *
+   * @param group The name of the Group.
+   * @return The Added Group instance.
+   * @throws GroupAlreadyExistsException If a Group with the same name already 
exists.
+   * @throws NoSuchMetalakeException If the Metalake with the given name does 
not exist.
+   * @throws RuntimeException If adding the Group encounters storage issues.
+   */
+  public Group addGroup(String group) throws GroupAlreadyExistsException, 
NoSuchMetalakeException {
+    return getMetalake().addGroup(group);
+  }
+
+  /**
+   * Removes a Group.
+   *
+   * @param group THe name of the Group.
+   * @return True if the Group was successfully removed, false only when 
there's no such group,
+   *     otherwise it will throw an exception.
+   * @throws NoSuchMetalakeException If the Metalake with the given name does 
not exist.
+   * @throws RuntimeException If removing the Group encounters storage issues.
+   */
+  public boolean removeGroup(String group) throws NoSuchMetalakeException {
+    return getMetalake().removeGroup(group);
+  }
+
+  /**
+   * Gets a Group.
+   *
+   * @param group The name of the Group.
+   * @return The getting Group instance.
+   * @throws NoSuchGroupException If the Group with the given name does not 
exist.
+   * @throws NoSuchMetalakeException If the Metalake with the given name does 
not exist.
+   * @throws RuntimeException If getting the Group encounters storage issues.
+   */
+  public Group getGroup(String group) throws NoSuchGroupException, 
NoSuchMetalakeException {
+    return getMetalake().getGroup(group);
+  }
+
+  /**
+   * Gets a Role.
+   *
+   * @param role The name of the Role.
+   * @return The getting Role instance.
+   * @throws NoSuchRoleException If the Role with the given name does not 
exist.
+   * @throws NoSuchMetalakeException If the Metalake with the given name does 
not exist.
+   * @throws RuntimeException If getting the Role encounters storage issues.
+   */
+  public Role getRole(String role) throws NoSuchRoleException, 
NoSuchMetalakeException {
+    return getMetalake().getRole(role);
+  }
+
+  /**
+   * Deletes a Role.
+   *
+   * @param role The name of the Role.
+   * @return True if the Role was successfully deleted, false only when 
there's no such role,
+   *     otherwise it will throw an exception.
+   * @throws NoSuchMetalakeException If the Metalake with the given name does 
not exist.
+   * @throws RuntimeException If deleting the Role encounters storage issues.
+   */
+  public boolean deleteRole(String role) throws NoSuchMetalakeException {
+    return getMetalake().deleteRole(role);
+  }
+
+  /**
+   * Creates a new Role.
+   *
+   * @param role The name of the Role.
+   * @param properties The properties of the Role.
+   * @param securableObjects The securable objects of the Role.
+   * @return The created Role instance.
+   * @throws RoleAlreadyExistsException If a Role with the same name already 
exists.
+   * @throws NoSuchMetalakeException If the Metalake with the given name does 
not exist.
+   * @throws RuntimeException If creating the Role encounters storage issues.
+   */
+  public Role createRole(
+      String role, Map<String, String> properties, List<SecurableObject> 
securableObjects)
+      throws RoleAlreadyExistsException, NoSuchMetalakeException {
+    return getMetalake().createRole(role, properties, securableObjects);
+  }
+  /**
+   * Grant roles to a user.
+   *
+   * @param user The name of the User.
+   * @param roles The names of the Role.
+   * @return The Group after granted.
+   * @throws NoSuchUserException If the User with the given name does not 
exist.
+   * @throws NoSuchRoleException If the Role with the given name does not 
exist.
+   * @throws NoSuchMetalakeException If the Metalake with the given name does 
not exist.
+   * @throws RuntimeException If granting roles to a user encounters storage 
issues.
+   */
+  public User grantRolesToUser(List<String> roles, String user)
+      throws NoSuchUserException, NoSuchRoleException, NoSuchMetalakeException 
{
+    return getMetalake().grantRolesToUser(roles, user);
+  }
+
+  /**
+   * Grant roles to a group.
+   *
+   * @param group The name of the Group.
+   * @param roles The names of the Role.
+   * @return The Group after granted.
+   * @throws NoSuchGroupException If the Group with the given name does not 
exist.
+   * @throws NoSuchRoleException If the Role with the given name does not 
exist.
+   * @throws NoSuchMetalakeException If the Metalake with the given name does 
not exist.
+   * @throws RuntimeException If granting roles to a group encounters storage 
issues.
+   */
+  public Group grantRolesToGroup(List<String> roles, String group)
+      throws NoSuchGroupException, NoSuchRoleException, 
NoSuchMetalakeException {
+    return getMetalake().grantRolesToGroup(roles, group);
+  }
+
+  /**
+   * Revoke roles from a user.
+   *
+   * @param user The name of the User.
+   * @param roles The names of the Role.
+   * @return The User after revoked.
+   * @throws NoSuchUserException If the User with the given name does not 
exist.
+   * @throws NoSuchRoleException If the Role with the given name does not 
exist.
+   * @throws NoSuchMetalakeException If the Metalake with the given name does 
not exist.
+   * @throws RuntimeException If revoking roles from a user encounters storage 
issues.
+   */
+  public User revokeRolesFromUser(List<String> roles, String user)
+      throws NoSuchUserException, NoSuchRoleException, NoSuchMetalakeException 
{
+    return getMetalake().revokeRolesFromUser(roles, user);
+  }
+
+  /**
+   * Revoke roles from a group.
+   *
+   * @param group The name of the Group.
+   * @param roles The names of the Role.
+   * @return The Group after revoked.
+   * @throws NoSuchGroupException If the Group with the given name does not 
exist.
+   * @throws NoSuchRoleException If the Role with the given name does not 
exist.
+   * @throws NoSuchMetalakeException If the Metalake with the given name does 
not exist.
+   * @throws RuntimeException If revoking roles from a group encounters 
storage issues.
+   */
+  public Group revokeRolesFromGroup(List<String> roles, String group)
+      throws NoSuchGroupException, NoSuchRoleException, 
NoSuchMetalakeException {
+    return getMetalake().revokeRolesFromGroup(roles, group);
+  }
+
   /**
    * Creates a new builder for constructing a GravitinoClient.
    *
diff --git 
a/clients/client-java/src/main/java/org/apache/gravitino/client/GravitinoMetalake.java
 
b/clients/client-java/src/main/java/org/apache/gravitino/client/GravitinoMetalake.java
index 0c908a506..7d527b1ec 100644
--- 
a/clients/client-java/src/main/java/org/apache/gravitino/client/GravitinoMetalake.java
+++ 
b/clients/client-java/src/main/java/org/apache/gravitino/client/GravitinoMetalake.java
@@ -31,27 +31,48 @@ import org.apache.gravitino.Catalog;
 import org.apache.gravitino.CatalogChange;
 import org.apache.gravitino.NameIdentifier;
 import org.apache.gravitino.SupportsCatalogs;
+import org.apache.gravitino.authorization.Group;
+import org.apache.gravitino.authorization.Role;
+import org.apache.gravitino.authorization.SecurableObject;
+import org.apache.gravitino.authorization.User;
 import org.apache.gravitino.dto.AuditDTO;
 import org.apache.gravitino.dto.MetalakeDTO;
+import org.apache.gravitino.dto.authorization.SecurableObjectDTO;
 import org.apache.gravitino.dto.requests.CatalogCreateRequest;
 import org.apache.gravitino.dto.requests.CatalogUpdateRequest;
 import org.apache.gravitino.dto.requests.CatalogUpdatesRequest;
+import org.apache.gravitino.dto.requests.GroupAddRequest;
+import org.apache.gravitino.dto.requests.RoleCreateRequest;
+import org.apache.gravitino.dto.requests.RoleGrantRequest;
+import org.apache.gravitino.dto.requests.RoleRevokeRequest;
 import org.apache.gravitino.dto.requests.TagCreateRequest;
 import org.apache.gravitino.dto.requests.TagUpdateRequest;
 import org.apache.gravitino.dto.requests.TagUpdatesRequest;
+import org.apache.gravitino.dto.requests.UserAddRequest;
 import org.apache.gravitino.dto.responses.CatalogListResponse;
 import org.apache.gravitino.dto.responses.CatalogResponse;
+import org.apache.gravitino.dto.responses.DeleteResponse;
 import org.apache.gravitino.dto.responses.DropResponse;
 import org.apache.gravitino.dto.responses.EntityListResponse;
 import org.apache.gravitino.dto.responses.ErrorResponse;
+import org.apache.gravitino.dto.responses.GroupResponse;
 import org.apache.gravitino.dto.responses.NameListResponse;
+import org.apache.gravitino.dto.responses.RemoveResponse;
+import org.apache.gravitino.dto.responses.RoleResponse;
 import org.apache.gravitino.dto.responses.TagListResponse;
 import org.apache.gravitino.dto.responses.TagResponse;
+import org.apache.gravitino.dto.responses.UserResponse;
 import org.apache.gravitino.exceptions.CatalogAlreadyExistsException;
+import org.apache.gravitino.exceptions.GroupAlreadyExistsException;
 import org.apache.gravitino.exceptions.NoSuchCatalogException;
+import org.apache.gravitino.exceptions.NoSuchGroupException;
 import org.apache.gravitino.exceptions.NoSuchMetalakeException;
+import org.apache.gravitino.exceptions.NoSuchRoleException;
 import org.apache.gravitino.exceptions.NoSuchTagException;
+import org.apache.gravitino.exceptions.NoSuchUserException;
+import org.apache.gravitino.exceptions.RoleAlreadyExistsException;
 import org.apache.gravitino.exceptions.TagAlreadyExistsException;
+import org.apache.gravitino.exceptions.UserAlreadyExistsException;
 import org.apache.gravitino.tag.Tag;
 import org.apache.gravitino.tag.TagChange;
 import org.apache.gravitino.tag.TagOperations;
@@ -63,6 +84,11 @@ import org.apache.gravitino.tag.TagOperations;
  */
 public class GravitinoMetalake extends MetalakeDTO implements 
SupportsCatalogs, TagOperations {
   private static final String API_METALAKES_CATALOGS_PATH = 
"api/metalakes/%s/catalogs/%s";
+  private static final String API_PERMISSION_PATH = 
"api/metalakes/%s/permissions/%s";
+  private static final String API_METALAKES_USERS_PATH = 
"api/metalakes/%s/users/%s";
+  private static final String API_METALAKES_GROUPS_PATH = 
"api/metalakes/%s/groups/%s";
+  private static final String API_METALAKES_ROLES_PATH = 
"api/metalakes/%s/roles/%s";
+  private static final String BLANK_PLACE_HOLDER = "";
 
   private static final String API_METALAKES_TAGS_PATH = 
"api/metalakes/%s/tags";
 
@@ -411,6 +437,331 @@ public class GravitinoMetalake extends MetalakeDTO 
implements SupportsCatalogs,
     return resp.dropped();
   }
 
+  /**
+   * Adds a new User.
+   *
+   * @param user The name of the User.
+   * @return The added User instance.
+   * @throws UserAlreadyExistsException If a User with the same name already 
exists.
+   * @throws NoSuchMetalakeException If the Metalake with the given name does 
not exist.
+   * @throws RuntimeException If adding the User encounters storage issues.
+   */
+  public User addUser(String user) throws UserAlreadyExistsException, 
NoSuchMetalakeException {
+    UserAddRequest req = new UserAddRequest(user);
+    req.validate();
+
+    UserResponse resp =
+        restClient.post(
+            String.format(API_METALAKES_USERS_PATH, this.name(), 
BLANK_PLACE_HOLDER),
+            req,
+            UserResponse.class,
+            Collections.emptyMap(),
+            ErrorHandlers.userErrorHandler());
+    resp.validate();
+
+    return resp.getUser();
+  }
+
+  /**
+   * Removes a User.
+   *
+   * @param user The name of the User.
+   * @return True if the User was successfully removed, false only when 
there's no such user,
+   *     otherwise it will throw an exception.
+   * @throws NoSuchMetalakeException If the Metalake with the given name does 
not exist.
+   * @throws RuntimeException If removing the User encounters storage issues.
+   */
+  public boolean removeUser(String user) throws NoSuchMetalakeException {
+    RemoveResponse resp =
+        restClient.delete(
+            String.format(API_METALAKES_USERS_PATH, this.name(), user),
+            RemoveResponse.class,
+            Collections.emptyMap(),
+            ErrorHandlers.userErrorHandler());
+    resp.validate();
+
+    return resp.removed();
+  }
+
+  /**
+   * Gets a User.
+   *
+   * @param user The name of the User.
+   * @return The getting User instance.
+   * @throws NoSuchUserException If the User with the given name does not 
exist.
+   * @throws NoSuchMetalakeException If the Metalake with the given name does 
not exist.
+   * @throws RuntimeException If getting the User encounters storage issues.
+   */
+  public User getUser(String user) throws NoSuchUserException, 
NoSuchMetalakeException {
+    UserResponse resp =
+        restClient.get(
+            String.format(API_METALAKES_USERS_PATH, this.name(), user),
+            UserResponse.class,
+            Collections.emptyMap(),
+            ErrorHandlers.userErrorHandler());
+    resp.validate();
+
+    return resp.getUser();
+  }
+
+  /**
+   * Adds a new Group.
+   *
+   * @param group The name of the Group.
+   * @return The Added Group instance.
+   * @throws GroupAlreadyExistsException If a Group with the same name already 
exists.
+   * @throws NoSuchMetalakeException If the Metalake with the given name does 
not exist.
+   * @throws RuntimeException If adding the Group encounters storage issues.
+   */
+  public Group addGroup(String group) throws GroupAlreadyExistsException, 
NoSuchMetalakeException {
+    GroupAddRequest req = new GroupAddRequest(group);
+    req.validate();
+
+    GroupResponse resp =
+        restClient.post(
+            String.format(API_METALAKES_GROUPS_PATH, this.name(), 
BLANK_PLACE_HOLDER),
+            req,
+            GroupResponse.class,
+            Collections.emptyMap(),
+            ErrorHandlers.groupErrorHandler());
+    resp.validate();
+
+    return resp.getGroup();
+  }
+
+  /**
+   * Removes a Group.
+   *
+   * @param group THe name of the Group.
+   * @return True if the Group was successfully removed, false only when 
there's no such group,
+   *     otherwise it will throw an exception.
+   * @throws NoSuchMetalakeException If the Metalake with the given name does 
not exist.
+   * @throws RuntimeException If removing the Group encounters storage issues.
+   */
+  public boolean removeGroup(String group) throws NoSuchMetalakeException {
+    RemoveResponse resp =
+        restClient.delete(
+            String.format(API_METALAKES_GROUPS_PATH, this.name(), group),
+            RemoveResponse.class,
+            Collections.emptyMap(),
+            ErrorHandlers.groupErrorHandler());
+    resp.validate();
+
+    return resp.removed();
+  }
+
+  /**
+   * Gets a Group.
+   *
+   * @param group The name of the Group.
+   * @return The getting Group instance.
+   * @throws NoSuchGroupException If the Group with the given name does not 
exist.
+   * @throws NoSuchMetalakeException If the Metalake with the given name does 
not exist.
+   * @throws RuntimeException If getting the Group encounters storage issues.
+   */
+  public Group getGroup(String group) throws NoSuchGroupException, 
NoSuchMetalakeException {
+    GroupResponse resp =
+        restClient.get(
+            String.format(API_METALAKES_GROUPS_PATH, this.name(), group),
+            GroupResponse.class,
+            Collections.emptyMap(),
+            ErrorHandlers.groupErrorHandler());
+    resp.validate();
+
+    return resp.getGroup();
+  }
+
+  /**
+   * Gets a Role.
+   *
+   * @param role The name of the Role.
+   * @return The getting Role instance.
+   * @throws NoSuchRoleException If the Role with the given name does not 
exist.
+   * @throws NoSuchMetalakeException If the Metalake with the given name does 
not exist.
+   * @throws RuntimeException If getting the Role encounters storage issues.
+   */
+  public Role getRole(String role) throws NoSuchRoleException, 
NoSuchMetalakeException {
+    RoleResponse resp =
+        restClient.get(
+            String.format(API_METALAKES_ROLES_PATH, this.name(), role),
+            RoleResponse.class,
+            Collections.emptyMap(),
+            ErrorHandlers.roleErrorHandler());
+    resp.validate();
+
+    return resp.getRole();
+  }
+
+  /**
+   * Deletes a Role.
+   *
+   * @param role The name of the Role.
+   * @return True if the Role was successfully deleted, false only when 
there's no such role,
+   *     otherwise it will throw an exception.
+   * @throws NoSuchMetalakeException If the Metalake with the given name does 
not exist.
+   * @throws RuntimeException If deleting the Role encounters storage issues.
+   */
+  public boolean deleteRole(String role) throws NoSuchMetalakeException {
+    DeleteResponse resp =
+        restClient.delete(
+            String.format(API_METALAKES_ROLES_PATH, this.name(), role),
+            DeleteResponse.class,
+            Collections.emptyMap(),
+            ErrorHandlers.roleErrorHandler());
+    resp.validate();
+
+    return resp.deleted();
+  }
+
+  /**
+   * Creates a new Role.
+   *
+   * @param role The name of the Role.
+   * @param properties The properties of the Role.
+   * @param securableObjects The securable objects of the Role.
+   * @return The created Role instance.
+   * @throws RoleAlreadyExistsException If a Role with the same name already 
exists.
+   * @throws NoSuchMetalakeException If the Metalake with the given name does 
not exist.
+   * @throws RuntimeException If creating the Role encounters storage issues.
+   */
+  public Role createRole(
+      String role, Map<String, String> properties, List<SecurableObject> 
securableObjects)
+      throws RoleAlreadyExistsException, NoSuchMetalakeException {
+    RoleCreateRequest req =
+        new RoleCreateRequest(
+            role,
+            properties,
+            securableObjects.stream()
+                .map(DTOConverters::toSecurableObject)
+                .toArray(SecurableObjectDTO[]::new));
+    req.validate();
+
+    RoleResponse resp =
+        restClient.post(
+            String.format(API_METALAKES_ROLES_PATH, this.name(), 
BLANK_PLACE_HOLDER),
+            req,
+            RoleResponse.class,
+            Collections.emptyMap(),
+            ErrorHandlers.roleErrorHandler());
+    resp.validate();
+
+    return resp.getRole();
+  }
+
+  /**
+   * Grant roles to a user.
+   *
+   * @param user The name of the User.
+   * @param roles The names of the Role.
+   * @return The Group after granted.
+   * @throws NoSuchUserException If the User with the given name does not 
exist.
+   * @throws NoSuchRoleException If the Role with the given name does not 
exist.
+   * @throws NoSuchMetalakeException If the Metalake with the given name does 
not exist.
+   * @throws RuntimeException If granting roles to a user encounters storage 
issues.
+   */
+  public User grantRolesToUser(List<String> roles, String user)
+      throws NoSuchUserException, NoSuchRoleException, NoSuchMetalakeException 
{
+    RoleGrantRequest request = new RoleGrantRequest(roles);
+    request.validate();
+
+    UserResponse resp =
+        restClient.put(
+            String.format(API_PERMISSION_PATH, this.name(), 
String.format("users/%s/grant", user)),
+            request,
+            UserResponse.class,
+            Collections.emptyMap(),
+            ErrorHandlers.permissionOperationErrorHandler());
+    resp.validate();
+
+    return resp.getUser();
+  }
+
+  /**
+   * Grant roles to a group.
+   *
+   * @param group The name of the Group.
+   * @param roles The names of the Role.
+   * @return The Group after granted.
+   * @throws NoSuchGroupException If the Group with the given name does not 
exist.
+   * @throws NoSuchRoleException If the Role with the given name does not 
exist.
+   * @throws NoSuchMetalakeException If the Metalake with the given name does 
not exist.
+   * @throws RuntimeException If granting roles to a group encounters storage 
issues.
+   */
+  public Group grantRolesToGroup(List<String> roles, String group)
+      throws NoSuchGroupException, NoSuchRoleException, 
NoSuchMetalakeException {
+    RoleGrantRequest request = new RoleGrantRequest(roles);
+    request.validate();
+
+    GroupResponse resp =
+        restClient.put(
+            String.format(
+                API_PERMISSION_PATH, this.name(), 
String.format("groups/%s/grant", group)),
+            request,
+            GroupResponse.class,
+            Collections.emptyMap(),
+            ErrorHandlers.permissionOperationErrorHandler());
+    resp.validate();
+
+    return resp.getGroup();
+  }
+
+  /**
+   * Revoke roles from a user.
+   *
+   * @param user The name of the User.
+   * @param roles The names of the Role.
+   * @return The User after revoked.
+   * @throws NoSuchUserException If the User with the given name does not 
exist.
+   * @throws NoSuchRoleException If the Role with the given name does not 
exist.
+   * @throws NoSuchMetalakeException If the Metalake with the given name does 
not exist.
+   * @throws RuntimeException If revoking roles from a user encounters storage 
issues.
+   */
+  public User revokeRolesFromUser(List<String> roles, String user)
+      throws NoSuchUserException, NoSuchRoleException, NoSuchMetalakeException 
{
+    RoleRevokeRequest request = new RoleRevokeRequest(roles);
+    request.validate();
+
+    UserResponse resp =
+        restClient.put(
+            String.format(API_PERMISSION_PATH, this.name(), 
String.format("users/%s/revoke", user)),
+            request,
+            UserResponse.class,
+            Collections.emptyMap(),
+            ErrorHandlers.permissionOperationErrorHandler());
+    resp.validate();
+
+    return resp.getUser();
+  }
+
+  /**
+   * Revoke roles from a group.
+   *
+   * @param group The name of the Group.
+   * @param roles The names of the Role.
+   * @return The Group after revoked.
+   * @throws NoSuchGroupException If the Group with the given name does not 
exist.
+   * @throws NoSuchRoleException If the Role with the given name does not 
exist.
+   * @throws NoSuchMetalakeException If the Metalake with the given name does 
not exist.
+   * @throws RuntimeException If revoking roles from a group encounters 
storage issues.
+   */
+  public Group revokeRolesFromGroup(List<String> roles, String group)
+      throws NoSuchGroupException, NoSuchRoleException, 
NoSuchMetalakeException {
+    RoleRevokeRequest request = new RoleRevokeRequest(roles);
+    request.validate();
+
+    GroupResponse resp =
+        restClient.put(
+            String.format(
+                API_PERMISSION_PATH, this.name(), 
String.format("groups/%s/revoke", group)),
+            request,
+            GroupResponse.class,
+            Collections.emptyMap(),
+            ErrorHandlers.permissionOperationErrorHandler());
+    resp.validate();
+
+    return resp.getGroup();
+  }
+
   static class Builder extends MetalakeDTO.Builder<Builder> {
     private RESTClient restClient;
 
diff --git 
a/clients/client-java/src/test/java/org/apache/gravitino/client/TestPermission.java
 
b/clients/client-java/src/test/java/org/apache/gravitino/client/TestPermission.java
index 8f2cce429..70912e9b5 100644
--- 
a/clients/client-java/src/test/java/org/apache/gravitino/client/TestPermission.java
+++ 
b/clients/client-java/src/test/java/org/apache/gravitino/client/TestPermission.java
@@ -27,13 +27,16 @@ import java.util.List;
 import org.apache.gravitino.authorization.Group;
 import org.apache.gravitino.authorization.User;
 import org.apache.gravitino.dto.AuditDTO;
+import org.apache.gravitino.dto.MetalakeDTO;
 import org.apache.gravitino.dto.authorization.GroupDTO;
 import org.apache.gravitino.dto.authorization.UserDTO;
 import org.apache.gravitino.dto.requests.RoleGrantRequest;
 import org.apache.gravitino.dto.requests.RoleRevokeRequest;
 import org.apache.gravitino.dto.responses.ErrorResponse;
 import org.apache.gravitino.dto.responses.GroupResponse;
+import org.apache.gravitino.dto.responses.MetalakeResponse;
 import org.apache.gravitino.dto.responses.UserResponse;
+import org.apache.hc.core5.http.HttpStatus;
 import org.apache.hc.core5.http.Method;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.BeforeAll;
@@ -43,10 +46,29 @@ public class TestPermission extends TestBase {
 
   private static final String metalakeName = "testMetalake";
   private static final String API_PERMISSION_PATH = 
"/api/metalakes/%s/permissions/%s";
+  private static GravitinoClient gravitinoClient;
 
   @BeforeAll
   public static void setUp() throws Exception {
     TestBase.setUp();
+
+    TestGravitinoMetalake.createMetalake(client, metalakeName);
+
+    MetalakeDTO mockMetalake =
+        MetalakeDTO.builder()
+            .withName(metalakeName)
+            .withComment("comment")
+            .withAudit(
+                
AuditDTO.builder().withCreator("creator").withCreateTime(Instant.now()).build())
+            .build();
+    MetalakeResponse resp = new MetalakeResponse(mockMetalake);
+    buildMockResource(Method.GET, "/api/metalakes/" + metalakeName, null, 
resp, HttpStatus.SC_OK);
+
+    gravitinoClient =
+        GravitinoClient.builder("http://127.0.0.1:"; + 
mockServer.getLocalPort())
+            .withMetalake(metalakeName)
+            .withVersionCheckDisabled()
+            .build();
   }
 
   @Test
@@ -65,7 +87,7 @@ public class TestPermission extends TestBase {
     UserResponse response = new UserResponse(userDTO);
 
     buildMockResource(Method.PUT, userPath, request, response, SC_OK);
-    User grantedUser = client.grantRolesToUser(metalakeName, roles, user);
+    User grantedUser = gravitinoClient.grantRolesToUser(roles, user);
     Assertions.assertEquals(grantedUser.roles(), userDTO.roles());
     Assertions.assertEquals(grantedUser.name(), userDTO.name());
 
@@ -73,7 +95,7 @@ public class TestPermission extends TestBase {
     ErrorResponse errResp2 = ErrorResponse.internalError("internal error");
     buildMockResource(Method.PUT, userPath, request, errResp2, 
SC_SERVER_ERROR);
     Assertions.assertThrows(
-        RuntimeException.class, () -> client.grantRolesToUser(metalakeName, 
roles, user));
+        RuntimeException.class, () -> gravitinoClient.grantRolesToUser(roles, 
user));
   }
 
   @Test
@@ -92,7 +114,7 @@ public class TestPermission extends TestBase {
     RoleRevokeRequest request = new RoleRevokeRequest(roles);
 
     buildMockResource(Method.PUT, userPath, request, response, SC_OK);
-    User revokedUser = client.revokeRolesFromUser(metalakeName, roles, user);
+    User revokedUser = gravitinoClient.revokeRolesFromUser(roles, user);
     Assertions.assertEquals(revokedUser.roles(), userDTO.roles());
     Assertions.assertEquals(revokedUser.name(), userDTO.name());
 
@@ -100,7 +122,7 @@ public class TestPermission extends TestBase {
     ErrorResponse errResp2 = ErrorResponse.internalError("internal error");
     buildMockResource(Method.PUT, userPath, null, errResp2, SC_SERVER_ERROR);
     Assertions.assertThrows(
-        RuntimeException.class, () -> client.revokeRolesFromUser(metalakeName, 
roles, user));
+        RuntimeException.class, () -> 
gravitinoClient.revokeRolesFromUser(roles, user));
   }
 
   @Test
@@ -119,7 +141,7 @@ public class TestPermission extends TestBase {
     GroupResponse response = new GroupResponse(groupDTO);
 
     buildMockResource(Method.PUT, groupPath, request, response, SC_OK);
-    Group grantedGroup = client.grantRolesToGroup(metalakeName, roles, group);
+    Group grantedGroup = gravitinoClient.grantRolesToGroup(roles, group);
     Assertions.assertEquals(grantedGroup.roles(), groupDTO.roles());
     Assertions.assertEquals(grantedGroup.name(), groupDTO.name());
 
@@ -127,7 +149,7 @@ public class TestPermission extends TestBase {
     ErrorResponse errResp = ErrorResponse.internalError("internal error");
     buildMockResource(Method.POST, groupPath, request, errResp, 
SC_SERVER_ERROR);
     Assertions.assertThrows(
-        RuntimeException.class, () -> client.grantRolesToGroup(metalakeName, 
roles, group));
+        RuntimeException.class, () -> gravitinoClient.grantRolesToGroup(roles, 
group));
   }
 
   @Test
@@ -146,7 +168,7 @@ public class TestPermission extends TestBase {
     RoleRevokeRequest request = new RoleRevokeRequest(roles);
 
     buildMockResource(Method.PUT, groupPath, request, response, SC_OK);
-    Group revokedGroup = client.revokeRolesFromGroup(metalakeName, roles, 
group);
+    Group revokedGroup = gravitinoClient.revokeRolesFromGroup(roles, group);
     Assertions.assertEquals(revokedGroup.roles(), groupDTO.roles());
     Assertions.assertEquals(revokedGroup.name(), groupDTO.name());
 
@@ -154,6 +176,6 @@ public class TestPermission extends TestBase {
     ErrorResponse errResp = ErrorResponse.internalError("internal error");
     buildMockResource(Method.DELETE, groupPath, null, errResp, 
SC_SERVER_ERROR);
     Assertions.assertThrows(
-        RuntimeException.class, () -> 
client.revokeRolesFromGroup(metalakeName, roles, group));
+        RuntimeException.class, () -> 
gravitinoClient.revokeRolesFromGroup(roles, group));
   }
 }
diff --git 
a/clients/client-java/src/test/java/org/apache/gravitino/client/TestRole.java 
b/clients/client-java/src/test/java/org/apache/gravitino/client/TestRole.java
index eabbf5971..370f1941d 100644
--- 
a/clients/client-java/src/test/java/org/apache/gravitino/client/TestRole.java
+++ 
b/clients/client-java/src/test/java/org/apache/gravitino/client/TestRole.java
@@ -32,16 +32,19 @@ import org.apache.gravitino.authorization.Role;
 import org.apache.gravitino.authorization.SecurableObject;
 import org.apache.gravitino.authorization.SecurableObjects;
 import org.apache.gravitino.dto.AuditDTO;
+import org.apache.gravitino.dto.MetalakeDTO;
 import org.apache.gravitino.dto.authorization.PrivilegeDTO;
 import org.apache.gravitino.dto.authorization.RoleDTO;
 import org.apache.gravitino.dto.authorization.SecurableObjectDTO;
 import org.apache.gravitino.dto.requests.RoleCreateRequest;
 import org.apache.gravitino.dto.responses.DeleteResponse;
 import org.apache.gravitino.dto.responses.ErrorResponse;
+import org.apache.gravitino.dto.responses.MetalakeResponse;
 import org.apache.gravitino.dto.responses.RoleResponse;
 import org.apache.gravitino.exceptions.NoSuchMetalakeException;
 import org.apache.gravitino.exceptions.NoSuchRoleException;
 import org.apache.gravitino.exceptions.RoleAlreadyExistsException;
+import org.apache.hc.core5.http.HttpStatus;
 import org.apache.hc.core5.http.Method;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.BeforeAll;
@@ -50,11 +53,30 @@ import org.junit.jupiter.api.Test;
 public class TestRole extends TestBase {
 
   private static final String API_METALAKES_ROLES_PATH = 
"api/metalakes/%s/roles/%s";
-  protected static final String metalakeName = "testMetalake";
+  private static final String metalakeName = "testMetalake";
+  private static GravitinoClient gravitinoClient;
 
   @BeforeAll
   public static void setUp() throws Exception {
     TestBase.setUp();
+
+    TestGravitinoMetalake.createMetalake(client, metalakeName);
+
+    MetalakeDTO mockMetalake =
+        MetalakeDTO.builder()
+            .withName(metalakeName)
+            .withComment("comment")
+            .withAudit(
+                
AuditDTO.builder().withCreator("creator").withCreateTime(Instant.now()).build())
+            .build();
+    MetalakeResponse resp = new MetalakeResponse(mockMetalake);
+    buildMockResource(Method.GET, "/api/metalakes/" + metalakeName, null, 
resp, HttpStatus.SC_OK);
+
+    gravitinoClient =
+        GravitinoClient.builder("http://127.0.0.1:"; + 
mockServer.getLocalPort())
+            .withMetalake(metalakeName)
+            .withVersionCheckDisabled()
+            .build();
   }
 
   @Test
@@ -81,11 +103,8 @@ public class TestRole extends TestBase {
         SecurableObjects.ofCatalog("catalog", 
Lists.newArrayList(Privileges.UseCatalog.allow()));
 
     Role createdRole =
-        client.createRole(
-            metalakeName,
-            roleName,
-            ImmutableMap.of("k1", "v1"),
-            Lists.newArrayList(securableObject));
+        gravitinoClient.createRole(
+            roleName, ImmutableMap.of("k1", "v1"), 
Lists.newArrayList(securableObject));
     Assertions.assertEquals(1L, 
Privileges.CreateCatalog.allow().name().getLowBits());
     Assertions.assertEquals(0L, 
Privileges.CreateCatalog.allow().name().getHighBits());
     Assertions.assertNotNull(createdRole);
@@ -100,11 +119,8 @@ public class TestRole extends TestBase {
         Assertions.assertThrows(
             RoleAlreadyExistsException.class,
             () ->
-                client.createRole(
-                    metalakeName,
-                    roleName,
-                    ImmutableMap.of("k1", "v1"),
-                    Lists.newArrayList(securableObject)));
+                gravitinoClient.createRole(
+                    roleName, ImmutableMap.of("k1", "v1"), 
Lists.newArrayList(securableObject)));
     Assertions.assertEquals("role already exists", ex.getMessage());
 
     // test NoSuchMetalakeException
@@ -115,11 +131,8 @@ public class TestRole extends TestBase {
         Assertions.assertThrows(
             NoSuchMetalakeException.class,
             () ->
-                client.createRole(
-                    metalakeName,
-                    roleName,
-                    ImmutableMap.of("k1", "v1"),
-                    Lists.newArrayList(securableObject)));
+                gravitinoClient.createRole(
+                    roleName, ImmutableMap.of("k1", "v1"), 
Lists.newArrayList(securableObject)));
     Assertions.assertEquals("metalake not found", ex.getMessage());
 
     // test RuntimeException
@@ -128,11 +141,8 @@ public class TestRole extends TestBase {
     Assertions.assertThrows(
         RuntimeException.class,
         () ->
-            client.createRole(
-                metalakeName,
-                roleName,
-                ImmutableMap.of("k1", "v1"),
-                Lists.newArrayList(securableObject)),
+            gravitinoClient.createRole(
+                roleName, ImmutableMap.of("k1", "v1"), 
Lists.newArrayList(securableObject)),
         "internal error");
   }
 
@@ -145,7 +155,7 @@ public class TestRole extends TestBase {
     RoleResponse roleResponse = new RoleResponse(mockRole);
     buildMockResource(Method.GET, rolePath, null, roleResponse, SC_OK);
 
-    Role loadedRole = client.getRole(metalakeName, roleName);
+    Role loadedRole = gravitinoClient.getRole(roleName);
     Assertions.assertNotNull(loadedRole);
     assertRole(mockRole, loadedRole);
 
@@ -154,8 +164,7 @@ public class TestRole extends TestBase {
         ErrorResponse.notFound(NoSuchRoleException.class.getSimpleName(), 
"role not found");
     buildMockResource(Method.GET, rolePath, null, errResp1, SC_NOT_FOUND);
     Exception ex =
-        Assertions.assertThrows(
-            NoSuchRoleException.class, () -> client.getRole(metalakeName, 
roleName));
+        Assertions.assertThrows(NoSuchRoleException.class, () -> 
gravitinoClient.getRole(roleName));
     Assertions.assertEquals("role not found", ex.getMessage());
 
     // test NoSuchMetalakeException
@@ -164,14 +173,14 @@ public class TestRole extends TestBase {
     buildMockResource(Method.GET, rolePath, null, errResp2, SC_NOT_FOUND);
     ex =
         Assertions.assertThrows(
-            NoSuchMetalakeException.class, () -> client.getRole(metalakeName, 
roleName));
+            NoSuchMetalakeException.class, () -> 
gravitinoClient.getRole(roleName));
     Assertions.assertEquals("metalake not found", ex.getMessage());
 
     // test RuntimeException
     ErrorResponse errResp3 = ErrorResponse.internalError("internal error");
     buildMockResource(Method.GET, rolePath, null, errResp3, SC_SERVER_ERROR);
     Assertions.assertThrows(
-        RuntimeException.class, () -> client.getRole(metalakeName, roleName), 
"internal error");
+        RuntimeException.class, () -> gravitinoClient.getRole(roleName), 
"internal error");
 
     // test SecurableDTO use parent method
     Role testParentRole = mockHasParentRoleDTO("test");
@@ -190,17 +199,16 @@ public class TestRole extends TestBase {
     DeleteResponse deleteResponse = new DeleteResponse(true);
     buildMockResource(Method.DELETE, rolePath, null, deleteResponse, SC_OK);
 
-    Assertions.assertTrue(client.deleteRole(metalakeName, roleName));
+    Assertions.assertTrue(gravitinoClient.deleteRole(roleName));
 
     deleteResponse = new DeleteResponse(false);
     buildMockResource(Method.DELETE, rolePath, null, deleteResponse, SC_OK);
-    Assertions.assertFalse(client.deleteRole(metalakeName, roleName));
+    Assertions.assertFalse(gravitinoClient.deleteRole(roleName));
 
     // test RuntimeException
     ErrorResponse errResp = ErrorResponse.internalError("internal error");
     buildMockResource(Method.DELETE, rolePath, null, errResp, SC_SERVER_ERROR);
-    Assertions.assertThrows(
-        RuntimeException.class, () -> client.deleteRole(metalakeName, 
roleName));
+    Assertions.assertThrows(RuntimeException.class, () -> 
gravitinoClient.deleteRole(roleName));
   }
 
   private RoleDTO mockRoleDTO(String name) {
diff --git 
a/clients/client-java/src/test/java/org/apache/gravitino/client/TestUserGroup.java
 
b/clients/client-java/src/test/java/org/apache/gravitino/client/TestUserGroup.java
index 4aa2e9f73..f3885a05f 100644
--- 
a/clients/client-java/src/test/java/org/apache/gravitino/client/TestUserGroup.java
+++ 
b/clients/client-java/src/test/java/org/apache/gravitino/client/TestUserGroup.java
@@ -27,12 +27,14 @@ import java.time.Instant;
 import org.apache.gravitino.authorization.Group;
 import org.apache.gravitino.authorization.User;
 import org.apache.gravitino.dto.AuditDTO;
+import org.apache.gravitino.dto.MetalakeDTO;
 import org.apache.gravitino.dto.authorization.GroupDTO;
 import org.apache.gravitino.dto.authorization.UserDTO;
 import org.apache.gravitino.dto.requests.GroupAddRequest;
 import org.apache.gravitino.dto.requests.UserAddRequest;
 import org.apache.gravitino.dto.responses.ErrorResponse;
 import org.apache.gravitino.dto.responses.GroupResponse;
+import org.apache.gravitino.dto.responses.MetalakeResponse;
 import org.apache.gravitino.dto.responses.RemoveResponse;
 import org.apache.gravitino.dto.responses.UserResponse;
 import org.apache.gravitino.exceptions.GroupAlreadyExistsException;
@@ -40,6 +42,7 @@ import org.apache.gravitino.exceptions.NoSuchGroupException;
 import org.apache.gravitino.exceptions.NoSuchMetalakeException;
 import org.apache.gravitino.exceptions.NoSuchUserException;
 import org.apache.gravitino.exceptions.UserAlreadyExistsException;
+import org.apache.hc.core5.http.HttpStatus;
 import org.apache.hc.core5.http.Method;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.BeforeAll;
@@ -49,11 +52,30 @@ public class TestUserGroup extends TestBase {
 
   private static final String API_METALAKES_USERS_PATH = 
"api/metalakes/%s/users/%s";
   private static final String API_METALAKES_GROUPS_PATH = 
"api/metalakes/%s/groups/%s";
-  protected static final String metalakeName = "testMetalake";
+  private static GravitinoClient gravitinoClient;
+  private static final String metalakeName = "testMetalake";
 
   @BeforeAll
   public static void setUp() throws Exception {
     TestBase.setUp();
+
+    TestGravitinoMetalake.createMetalake(client, metalakeName);
+
+    MetalakeDTO mockMetalake =
+        MetalakeDTO.builder()
+            .withName(metalakeName)
+            .withComment("comment")
+            .withAudit(
+                
AuditDTO.builder().withCreator("creator").withCreateTime(Instant.now()).build())
+            .build();
+    MetalakeResponse resp = new MetalakeResponse(mockMetalake);
+    buildMockResource(Method.GET, "/api/metalakes/" + metalakeName, null, 
resp, HttpStatus.SC_OK);
+
+    gravitinoClient =
+        GravitinoClient.builder("http://127.0.0.1:"; + 
mockServer.getLocalPort())
+            .withMetalake(metalakeName)
+            .withVersionCheckDisabled()
+            .build();
   }
 
   @Test
@@ -66,7 +88,7 @@ public class TestUserGroup extends TestBase {
     UserResponse userResponse = new UserResponse(mockUser);
     buildMockResource(Method.POST, userPath, request, userResponse, SC_OK);
 
-    User addedUser = client.addUser(metalakeName, username);
+    User addedUser = gravitinoClient.addUser(username);
     Assertions.assertNotNull(addedUser);
     assertUser(addedUser, mockUser);
 
@@ -77,7 +99,7 @@ public class TestUserGroup extends TestBase {
     buildMockResource(Method.POST, userPath, request, errResp1, SC_CONFLICT);
     Exception ex =
         Assertions.assertThrows(
-            UserAlreadyExistsException.class, () -> 
client.addUser(metalakeName, username));
+            UserAlreadyExistsException.class, () -> 
gravitinoClient.addUser(username));
     Assertions.assertEquals("user already exists", ex.getMessage());
 
     // test NoSuchMetalakeException
@@ -86,14 +108,14 @@ public class TestUserGroup extends TestBase {
     buildMockResource(Method.POST, userPath, request, errResp2, SC_NOT_FOUND);
     ex =
         Assertions.assertThrows(
-            NoSuchMetalakeException.class, () -> client.addUser(metalakeName, 
username));
+            NoSuchMetalakeException.class, () -> 
gravitinoClient.addUser(username));
     Assertions.assertEquals("metalake not found", ex.getMessage());
 
     // test RuntimeException
     ErrorResponse errResp3 = ErrorResponse.internalError("internal error");
     buildMockResource(Method.POST, userPath, request, errResp3, 
SC_SERVER_ERROR);
     Assertions.assertThrows(
-        RuntimeException.class, () -> client.addUser(metalakeName, username), 
"internal error");
+        RuntimeException.class, () -> gravitinoClient.addUser(username), 
"internal error");
   }
 
   @Test
@@ -105,7 +127,7 @@ public class TestUserGroup extends TestBase {
     UserResponse userResponse = new UserResponse(mockUser);
     buildMockResource(Method.GET, userPath, null, userResponse, SC_OK);
 
-    User loadedUser = client.getUser(metalakeName, username);
+    User loadedUser = gravitinoClient.getUser(username);
     Assertions.assertNotNull(loadedUser);
     assertUser(mockUser, loadedUser);
 
@@ -114,8 +136,7 @@ public class TestUserGroup extends TestBase {
         ErrorResponse.notFound(NoSuchUserException.class.getSimpleName(), 
"user not found");
     buildMockResource(Method.GET, userPath, null, errResp1, SC_NOT_FOUND);
     Exception ex =
-        Assertions.assertThrows(
-            NoSuchUserException.class, () -> client.getUser(metalakeName, 
username));
+        Assertions.assertThrows(NoSuchUserException.class, () -> 
gravitinoClient.getUser(username));
     Assertions.assertEquals("user not found", ex.getMessage());
 
     // test NoSuchMetalakeException
@@ -124,14 +145,14 @@ public class TestUserGroup extends TestBase {
     buildMockResource(Method.GET, userPath, null, errResp2, SC_NOT_FOUND);
     ex =
         Assertions.assertThrows(
-            NoSuchMetalakeException.class, () -> client.getUser(metalakeName, 
username));
+            NoSuchMetalakeException.class, () -> 
gravitinoClient.getUser(username));
     Assertions.assertEquals("metalake not found", ex.getMessage());
 
     // test RuntimeException
     ErrorResponse errResp3 = ErrorResponse.internalError("internal error");
     buildMockResource(Method.GET, userPath, null, errResp3, SC_SERVER_ERROR);
     Assertions.assertThrows(
-        RuntimeException.class, () -> client.getUser(metalakeName, username), 
"internal error");
+        RuntimeException.class, () -> gravitinoClient.getUser(username), 
"internal error");
   }
 
   @Test
@@ -142,17 +163,16 @@ public class TestUserGroup extends TestBase {
     RemoveResponse removeResponse = new RemoveResponse(true);
     buildMockResource(Method.DELETE, userPath, null, removeResponse, SC_OK);
 
-    Assertions.assertTrue(client.removeUser(metalakeName, username));
+    Assertions.assertTrue(gravitinoClient.removeUser(username));
 
     removeResponse = new RemoveResponse(false);
     buildMockResource(Method.DELETE, userPath, null, removeResponse, SC_OK);
-    Assertions.assertFalse(client.removeUser(metalakeName, username));
+    Assertions.assertFalse(gravitinoClient.removeUser(username));
 
     // test RuntimeException
     ErrorResponse errResp = ErrorResponse.internalError("internal error");
     buildMockResource(Method.DELETE, userPath, null, errResp, SC_SERVER_ERROR);
-    Assertions.assertThrows(
-        RuntimeException.class, () -> client.removeUser(metalakeName, 
username));
+    Assertions.assertThrows(RuntimeException.class, () -> 
gravitinoClient.removeUser(username));
   }
 
   @Test
@@ -165,7 +185,7 @@ public class TestUserGroup extends TestBase {
     GroupResponse groupResponse = new GroupResponse(mockGroup);
     buildMockResource(Method.POST, groupPath, request, groupResponse, SC_OK);
 
-    Group addedGroup = client.addGroup(metalakeName, groupName);
+    Group addedGroup = gravitinoClient.addGroup(groupName);
     Assertions.assertNotNull(addedGroup);
     assertGroup(addedGroup, mockGroup);
 
@@ -176,7 +196,7 @@ public class TestUserGroup extends TestBase {
     buildMockResource(Method.POST, groupPath, request, errResp1, SC_CONFLICT);
     Exception ex =
         Assertions.assertThrows(
-            GroupAlreadyExistsException.class, () -> 
client.addGroup(metalakeName, groupName));
+            GroupAlreadyExistsException.class, () -> 
gravitinoClient.addGroup(groupName));
     Assertions.assertEquals("group already exists", ex.getMessage());
 
     // test NoSuchMetalakeException
@@ -185,14 +205,14 @@ public class TestUserGroup extends TestBase {
     buildMockResource(Method.POST, groupPath, request, errResp2, SC_NOT_FOUND);
     ex =
         Assertions.assertThrows(
-            NoSuchMetalakeException.class, () -> client.addGroup(metalakeName, 
groupName));
+            NoSuchMetalakeException.class, () -> 
gravitinoClient.addGroup(groupName));
     Assertions.assertEquals("metalake not found", ex.getMessage());
 
     // test RuntimeException
     ErrorResponse errResp3 = ErrorResponse.internalError("internal error");
     buildMockResource(Method.POST, groupPath, request, errResp3, 
SC_SERVER_ERROR);
     Assertions.assertThrows(
-        RuntimeException.class, () -> client.addGroup(metalakeName, 
groupName), "internal error");
+        RuntimeException.class, () -> gravitinoClient.addGroup(groupName), 
"internal error");
   }
 
   @Test
@@ -204,7 +224,7 @@ public class TestUserGroup extends TestBase {
     GroupResponse groupResponse = new GroupResponse(mockGroup);
     buildMockResource(Method.GET, groupPath, null, groupResponse, SC_OK);
 
-    Group loadedGroup = client.getGroup(metalakeName, groupName);
+    Group loadedGroup = gravitinoClient.getGroup(groupName);
     Assertions.assertNotNull(loadedGroup);
     assertGroup(mockGroup, loadedGroup);
 
@@ -214,7 +234,7 @@ public class TestUserGroup extends TestBase {
     buildMockResource(Method.GET, groupPath, null, errResp1, SC_NOT_FOUND);
     Exception ex =
         Assertions.assertThrows(
-            NoSuchGroupException.class, () -> client.getGroup(metalakeName, 
groupName));
+            NoSuchGroupException.class, () -> 
gravitinoClient.getGroup(groupName));
     Assertions.assertEquals("group not found", ex.getMessage());
 
     // test NoSuchMetalakeException
@@ -223,14 +243,14 @@ public class TestUserGroup extends TestBase {
     buildMockResource(Method.GET, groupPath, null, errResp2, SC_NOT_FOUND);
     ex =
         Assertions.assertThrows(
-            NoSuchMetalakeException.class, () -> client.getGroup(metalakeName, 
groupName));
+            NoSuchMetalakeException.class, () -> 
gravitinoClient.getGroup(groupName));
     Assertions.assertEquals("metalake not found", ex.getMessage());
 
     // test RuntimeException
     ErrorResponse errResp3 = ErrorResponse.internalError("internal error");
     buildMockResource(Method.GET, groupPath, null, errResp3, SC_SERVER_ERROR);
     Assertions.assertThrows(
-        RuntimeException.class, () -> client.getGroup(metalakeName, 
groupName), "internal error");
+        RuntimeException.class, () -> gravitinoClient.getGroup(groupName), 
"internal error");
   }
 
   @Test
@@ -241,17 +261,16 @@ public class TestUserGroup extends TestBase {
     RemoveResponse removeResponse = new RemoveResponse(true);
     buildMockResource(Method.DELETE, groupPath, null, removeResponse, SC_OK);
 
-    Assertions.assertTrue(client.removeGroup(metalakeName, groupName));
+    Assertions.assertTrue(gravitinoClient.removeGroup(groupName));
 
     removeResponse = new RemoveResponse(false);
     buildMockResource(Method.DELETE, groupPath, null, removeResponse, SC_OK);
-    Assertions.assertFalse(client.removeGroup(metalakeName, groupName));
+    Assertions.assertFalse(gravitinoClient.removeGroup(groupName));
 
     // test RuntimeException
     ErrorResponse errResp = ErrorResponse.internalError("internal error");
     buildMockResource(Method.DELETE, groupPath, null, errResp, 
SC_SERVER_ERROR);
-    Assertions.assertThrows(
-        RuntimeException.class, () -> client.removeGroup(metalakeName, 
groupName));
+    Assertions.assertThrows(RuntimeException.class, () -> 
gravitinoClient.removeGroup(groupName));
   }
 
   private UserDTO mockUserDTO(String name) {

Reply via email to