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

fanng pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/gravitino.git


The following commit(s) were added to refs/heads/main by this push:
     new b382cba719 [#6712] feat(core): Support user event to Gravitino server 
(#6746)
b382cba719 is described below

commit b382cba719656bd55aab4d9b7b814566592ed6ab
Author: Lord of Abyss <[email protected]>
AuthorDate: Mon Mar 31 20:20:25 2025 +0800

    [#6712] feat(core): Support user event to Gravitino server (#6746)
    
    ### What changes were proposed in this pull request?
    
    Support user event to Gravitino server
    
    
    
![image](https://github.com/user-attachments/assets/1ad67c05-ebed-441b-a02f-d4257195c8cb)
    
    
    ### Why are the changes needed?
    
    Fix: #6712
    
    ### Does this PR introduce _any_ user-facing change?
    
    No
    
    ### How was this patch tested?
    
    local test.
---
 .../api/event/AccessControlEventDispatcher.java    |  60 ++++--
 .../{GetUserPreEvent.java => AddUserEvent.java}    |  36 ++--
 .../listener/api/event/AddUserPreEvent.java        |  24 +--
 .../{GetUserPreEvent.java => GetUserEvent.java}    |  34 ++--
 .../listener/api/event/GetUserPreEvent.java        |  20 +-
 .../listener/api/event/GrantUserRolesEvent.java    |  78 ++++++++
 .../listener/api/event/GrantUserRolesPreEvent.java |  76 ++++++++
 ...rNamesPreEvent.java => ListUserNamesEvent.java} |  16 +-
 .../listener/api/event/ListUserNamesPreEvent.java  |  13 +-
 ...{ListUsersPreEvent.java => ListUsersEvent.java} |  15 +-
 .../listener/api/event/ListUsersPreEvent.java      |   6 +-
 .../listener/api/event/OperationType.java          |   2 +
 .../listener/api/event/RemoveUserEvent.java        |  77 ++++++++
 .../listener/api/event/RemoveUserPreEvent.java     |   8 +-
 .../listener/api/event/RevokeUserRolesEvent.java   |  78 ++++++++
 ...rPreEvent.java => RevokeUserRolesPreEvent.java} |  39 ++--
 .../{ListUsersPreEvent.java => UserEvent.java}     |  30 +--
 .../listener/api/info/ModelVersionInfo.java        |   2 +
 .../ListUsersPreEvent.java => info/UserInfo.java}  |  39 ++--
 .../apache/gravitino/utils/NameIdentifierUtil.java |  12 ++
 .../org/apache/gravitino/utils/NamespaceUtil.java  |  10 +
 .../listener/api/event/TestUserEvent.java          | 209 ++++++++++++++++++++-
 .../gravitino/utils/TestNameIdentifierUtil.java    |  20 ++
 docs/gravitino-server-config.md                    |  22 ++-
 24 files changed, 772 insertions(+), 154 deletions(-)

diff --git 
a/core/src/main/java/org/apache/gravitino/listener/api/event/AccessControlEventDispatcher.java
 
b/core/src/main/java/org/apache/gravitino/listener/api/event/AccessControlEventDispatcher.java
index e5614d1845..9004f7fa70 100644
--- 
a/core/src/main/java/org/apache/gravitino/listener/api/event/AccessControlEventDispatcher.java
+++ 
b/core/src/main/java/org/apache/gravitino/listener/api/event/AccessControlEventDispatcher.java
@@ -40,6 +40,7 @@ import org.apache.gravitino.exceptions.NoSuchUserException;
 import org.apache.gravitino.exceptions.RoleAlreadyExistsException;
 import org.apache.gravitino.exceptions.UserAlreadyExistsException;
 import org.apache.gravitino.listener.EventBus;
+import org.apache.gravitino.listener.api.info.UserInfo;
 import org.apache.gravitino.utils.PrincipalUtils;
 
 /**
@@ -69,10 +70,12 @@ public class AccessControlEventDispatcher implements 
AccessControlDispatcher {
       throws UserAlreadyExistsException, NoSuchMetalakeException {
     String initiator = PrincipalUtils.getCurrentUserName();
 
-    eventBus.dispatchEvent(new AddUserPreEvent(initiator, 
NameIdentifier.of(metalake), user));
+    eventBus.dispatchEvent(new AddUserPreEvent(initiator, metalake, user));
     try {
-      // TODO add Event
-      return dispatcher.addUser(metalake, user);
+      User userObject = dispatcher.addUser(metalake, user);
+      eventBus.dispatchEvent(new AddUserEvent(initiator, metalake, new 
UserInfo(userObject)));
+
+      return userObject;
     } catch (Exception e) {
       // TODO: add failure event
       throw e;
@@ -84,10 +87,12 @@ public class AccessControlEventDispatcher implements 
AccessControlDispatcher {
   public boolean removeUser(String metalake, String user) throws 
NoSuchMetalakeException {
     String initiator = PrincipalUtils.getCurrentUserName();
 
-    eventBus.dispatchEvent(new RemoveUserPreEvent(initiator, 
NameIdentifier.of(metalake), user));
+    eventBus.dispatchEvent(new RemoveUserPreEvent(initiator, metalake, user));
     try {
-      // TODO: add Event
-      return dispatcher.removeUser(metalake, user);
+      boolean isExists = dispatcher.removeUser(metalake, user);
+      eventBus.dispatchEvent(new RemoveUserEvent(initiator, metalake, user, 
isExists));
+
+      return isExists;
     } catch (Exception e) {
       // TODO: add failure event
       throw e;
@@ -100,9 +105,12 @@ public class AccessControlEventDispatcher implements 
AccessControlDispatcher {
       throws NoSuchUserException, NoSuchMetalakeException {
     String initiator = PrincipalUtils.getCurrentUserName();
 
-    eventBus.dispatchEvent(new GetUserPreEvent(initiator, 
NameIdentifier.of(metalake), user));
+    eventBus.dispatchEvent(new GetUserPreEvent(initiator, metalake, user));
     try {
-      return dispatcher.getUser(metalake, user);
+      User userObject = dispatcher.getUser(metalake, user);
+      eventBus.dispatchEvent(new GetUserEvent(initiator, metalake, new 
UserInfo(userObject)));
+
+      return userObject;
     } catch (Exception e) {
       // TODO: add failure event
       throw e;
@@ -114,10 +122,12 @@ public class AccessControlEventDispatcher implements 
AccessControlDispatcher {
   public User[] listUsers(String metalake) throws NoSuchMetalakeException {
     String initiator = PrincipalUtils.getCurrentUserName();
 
-    eventBus.dispatchEvent(new ListUsersPreEvent(initiator, 
NameIdentifier.of(metalake)));
+    eventBus.dispatchEvent(new ListUsersPreEvent(initiator, metalake));
     try {
-      // TODO: add Event
-      return dispatcher.listUsers(metalake);
+      User[] users = dispatcher.listUsers(metalake);
+      eventBus.dispatchEvent(new ListUsersEvent(initiator, metalake));
+
+      return users;
     } catch (Exception e) {
       // TODO: add failure event
       throw e;
@@ -129,10 +139,12 @@ public class AccessControlEventDispatcher implements 
AccessControlDispatcher {
   public String[] listUserNames(String metalake) throws 
NoSuchMetalakeException {
     String initiator = PrincipalUtils.getCurrentUserName();
 
-    eventBus.dispatchEvent(new ListUserNamesPreEvent(initiator, 
NameIdentifier.of(metalake)));
+    eventBus.dispatchEvent(new ListUserNamesPreEvent(initiator, metalake));
     try {
-      // TODO: add Event
-      return dispatcher.listUserNames(metalake);
+      String[] userNames = dispatcher.listUserNames(metalake);
+      eventBus.dispatchEvent(new ListUserNamesEvent(initiator, metalake));
+
+      return userNames;
     } catch (Exception e) {
       // TODO: add failure event
       throw e;
@@ -218,9 +230,15 @@ public class AccessControlEventDispatcher implements 
AccessControlDispatcher {
   @Override
   public User grantRolesToUser(String metalake, List<String> roles, String 
user)
       throws NoSuchUserException, IllegalRoleException, 
NoSuchMetalakeException {
+    String initiator = PrincipalUtils.getCurrentUserName();
+
+    eventBus.dispatchEvent(new GrantUserRolesPreEvent(initiator, metalake, 
user, roles));
     try {
-      // TODO: add Event
-      return dispatcher.grantRolesToUser(metalake, roles, user);
+      User userObject = dispatcher.grantRolesToUser(metalake, roles, user);
+      eventBus.dispatchEvent(
+          new GrantUserRolesEvent(initiator, metalake, new 
UserInfo(userObject), roles));
+
+      return userObject;
     } catch (Exception e) {
       // TODO: add failure event
       throw e;
@@ -257,9 +275,15 @@ public class AccessControlEventDispatcher implements 
AccessControlDispatcher {
   @Override
   public User revokeRolesFromUser(String metalake, List<String> roles, String 
user)
       throws NoSuchUserException, IllegalRoleException, 
NoSuchMetalakeException {
+    String initiator = PrincipalUtils.getCurrentUserName();
+
+    eventBus.dispatchEvent(new RevokeUserRolesPreEvent(initiator, metalake, 
user, roles));
     try {
-      // TODO: add Event
-      return dispatcher.revokeRolesFromUser(metalake, roles, user);
+      User userObject = dispatcher.revokeRolesFromUser(metalake, roles, user);
+      eventBus.dispatchEvent(
+          new RevokeUserRolesEvent(initiator, metalake, new 
UserInfo(userObject), roles));
+
+      return userObject;
     } catch (Exception e) {
       // TODO: add failure event
       throw e;
diff --git 
a/core/src/main/java/org/apache/gravitino/listener/api/event/GetUserPreEvent.java
 b/core/src/main/java/org/apache/gravitino/listener/api/event/AddUserEvent.java
similarity index 51%
copy from 
core/src/main/java/org/apache/gravitino/listener/api/event/GetUserPreEvent.java
copy to 
core/src/main/java/org/apache/gravitino/listener/api/event/AddUserEvent.java
index 42562ff514..027a04a87c 100644
--- 
a/core/src/main/java/org/apache/gravitino/listener/api/event/GetUserPreEvent.java
+++ 
b/core/src/main/java/org/apache/gravitino/listener/api/event/AddUserEvent.java
@@ -19,34 +19,36 @@
 
 package org.apache.gravitino.listener.api.event;
 
-import org.apache.gravitino.NameIdentifier;
 import org.apache.gravitino.annotation.DeveloperApi;
+import org.apache.gravitino.listener.api.info.UserInfo;
+import org.apache.gravitino.utils.NameIdentifierUtil;
 
-/** Represents an event triggered before get a user from specific metalake */
+/** Represents an event generated after a user is successfully added to a 
metalake. */
 @DeveloperApi
-public class GetUserPreEvent extends UserPreEvent {
-  private final String userName;
+public class AddUserEvent extends UserEvent {
+  private UserInfo addedUserInfo;
 
   /**
-   * Construct a new {@link GetUserPreEvent} instance with the specified user, 
identifier and user
-   * info.
+   * Constructs a new {@link AddUserEvent} instance with the specified 
initiator, metalake name, and
+   * user information.
    *
-   * @param initiator the user who initiated the add-user request.
-   * @param identifier the identifier of the metalake which the user is 
getting retrieved from.
-   * @param userName the username which is requested to be retrieved.
+   * @param initiator the user who initiated the request to add a user.
+   * @param metalake the name of the metalake where the user was added.
+   * @param addedUserInfo the user information of the newly added user.
    */
-  public GetUserPreEvent(String initiator, NameIdentifier identifier, String 
userName) {
-    super(initiator, identifier);
-    this.userName = userName;
+  protected AddUserEvent(String initiator, String metalake, UserInfo 
addedUserInfo) {
+    super(initiator, NameIdentifierUtil.ofUser(metalake, 
addedUserInfo.name()));
+
+    this.addedUserInfo = addedUserInfo;
   }
 
   /**
-   * Returns the user info for the user which is getting retrieved.
+   * Returns the user information of the user added to the metalake.
    *
-   * @return the username which is requested to be retrieved.
+   * @return the {@link UserInfo} instance containing the details of the added 
user.
    */
-  public String userName() {
-    return userName;
+  public UserInfo addedUserInfo() {
+    return addedUserInfo;
   }
 
   /**
@@ -56,6 +58,6 @@ public class GetUserPreEvent extends UserPreEvent {
    */
   @Override
   public OperationType operationType() {
-    return OperationType.GET_USER;
+    return OperationType.ADD_USER;
   }
 }
diff --git 
a/core/src/main/java/org/apache/gravitino/listener/api/event/AddUserPreEvent.java
 
b/core/src/main/java/org/apache/gravitino/listener/api/event/AddUserPreEvent.java
index 611ec97b6d..33d2a70a52 100644
--- 
a/core/src/main/java/org/apache/gravitino/listener/api/event/AddUserPreEvent.java
+++ 
b/core/src/main/java/org/apache/gravitino/listener/api/event/AddUserPreEvent.java
@@ -19,40 +19,40 @@
 
 package org.apache.gravitino.listener.api.event;
 
-import org.apache.gravitino.NameIdentifier;
 import org.apache.gravitino.annotation.DeveloperApi;
+import org.apache.gravitino.utils.NameIdentifierUtil;
 
-/** Represents an event triggered before add a user to a metalake. */
+/** Represents an event triggered before adding a user to a metalake. */
 @DeveloperApi
 public class AddUserPreEvent extends UserPreEvent {
   private final String userName;
 
   /**
-   * Construct a new {@link AddUserPreEvent} instance with initiator, 
identifier and username.
+   * Constructs a new {@link AddUserPreEvent} instance with initiator, 
identifier, and username.
    *
-   * @param initiator the user who initiated the add-user request.
-   * @param identifier the identifier of the metalake which the user is being 
added to.
-   * @param userName the username which is requested to be added to the 
metalake.
+   * @param initiator The name of the user who initiated the add-user request.
+   * @param metalake The name of the metalake to which the user is being added.
+   * @param userName The username that is requested to be added to the 
metalake.
    */
-  public AddUserPreEvent(String initiator, NameIdentifier identifier, String 
userName) {
-    super(initiator, identifier);
+  public AddUserPreEvent(String initiator, String metalake, String userName) {
+    super(initiator, NameIdentifierUtil.ofUser(metalake, userName));
 
     this.userName = userName;
   }
 
   /**
-   * Returns the user information which is being added to the metalake.
+   * Returns the username to be added to the metalake.
    *
-   * @return the username which is requested to be added to the metalake.
+   * @return The username to be added.
    */
   public String userName() {
     return userName;
   }
 
   /**
-   * Returns the operation type of this event.
+   * Returns the operation type associated with this event.
    *
-   * @return the operation type.
+   * @return The operation type, specifically {@code OperationType.ADD_USER} 
for this event.
    */
   @Override
   public OperationType operationType() {
diff --git 
a/core/src/main/java/org/apache/gravitino/listener/api/event/GetUserPreEvent.java
 b/core/src/main/java/org/apache/gravitino/listener/api/event/GetUserEvent.java
similarity index 51%
copy from 
core/src/main/java/org/apache/gravitino/listener/api/event/GetUserPreEvent.java
copy to 
core/src/main/java/org/apache/gravitino/listener/api/event/GetUserEvent.java
index 42562ff514..15957695ae 100644
--- 
a/core/src/main/java/org/apache/gravitino/listener/api/event/GetUserPreEvent.java
+++ 
b/core/src/main/java/org/apache/gravitino/listener/api/event/GetUserEvent.java
@@ -19,34 +19,36 @@
 
 package org.apache.gravitino.listener.api.event;
 
-import org.apache.gravitino.NameIdentifier;
 import org.apache.gravitino.annotation.DeveloperApi;
+import org.apache.gravitino.listener.api.info.UserInfo;
+import org.apache.gravitino.utils.NameIdentifierUtil;
 
-/** Represents an event triggered before get a user from specific metalake */
+/** Represents an event triggered after successfully retrieving a user from a 
specific metalake. */
 @DeveloperApi
-public class GetUserPreEvent extends UserPreEvent {
-  private final String userName;
+public class GetUserEvent extends UserEvent {
+  private final UserInfo loadedUserInfo;
 
   /**
-   * Construct a new {@link GetUserPreEvent} instance with the specified user, 
identifier and user
-   * info.
+   * Constructs a new {@link GetUserEvent} instance with the specified 
initiator, metalake name, and
+   * user information.
    *
-   * @param initiator the user who initiated the add-user request.
-   * @param identifier the identifier of the metalake which the user is 
getting retrieved from.
-   * @param userName the username which is requested to be retrieved.
+   * @param initiator the user who initiated the request to get the user.
+   * @param metalake the name of the metalake from which the user is retrieved.
+   * @param loadedUserInfo the user information of the retrieved user.
    */
-  public GetUserPreEvent(String initiator, NameIdentifier identifier, String 
userName) {
-    super(initiator, identifier);
-    this.userName = userName;
+  protected GetUserEvent(String initiator, String metalake, UserInfo 
loadedUserInfo) {
+    super(initiator, NameIdentifierUtil.ofUser(metalake, 
loadedUserInfo.name()));
+
+    this.loadedUserInfo = loadedUserInfo;
   }
 
   /**
-   * Returns the user info for the user which is getting retrieved.
+   * Returns the user information of the user successfully retrieved from the 
metalake.
    *
-   * @return the username which is requested to be retrieved.
+   * @return the {@link UserInfo} instance containing the details of the 
retrieved user.
    */
-  public String userName() {
-    return userName;
+  public UserInfo loadedUserInfo() {
+    return loadedUserInfo;
   }
 
   /**
diff --git 
a/core/src/main/java/org/apache/gravitino/listener/api/event/GetUserPreEvent.java
 
b/core/src/main/java/org/apache/gravitino/listener/api/event/GetUserPreEvent.java
index 42562ff514..12672b2712 100644
--- 
a/core/src/main/java/org/apache/gravitino/listener/api/event/GetUserPreEvent.java
+++ 
b/core/src/main/java/org/apache/gravitino/listener/api/event/GetUserPreEvent.java
@@ -19,31 +19,31 @@
 
 package org.apache.gravitino.listener.api.event;
 
-import org.apache.gravitino.NameIdentifier;
 import org.apache.gravitino.annotation.DeveloperApi;
+import org.apache.gravitino.utils.NameIdentifierUtil;
 
-/** Represents an event triggered before get a user from specific metalake */
+/** Represents an event triggered before retrieving a user from a specific 
metalake. */
 @DeveloperApi
 public class GetUserPreEvent extends UserPreEvent {
   private final String userName;
 
   /**
-   * Construct a new {@link GetUserPreEvent} instance with the specified user, 
identifier and user
+   * Constructs a new {@link GetUserPreEvent} instance with the specified 
user, identifier, and user
    * info.
    *
-   * @param initiator the user who initiated the add-user request.
-   * @param identifier the identifier of the metalake which the user is 
getting retrieved from.
-   * @param userName the username which is requested to be retrieved.
+   * @param initiator The name of the user who initiated the get-user request.
+   * @param metalake The name of the metalake where the user is being 
retrieved from.
+   * @param userName The username that is requested to be retrieved.
    */
-  public GetUserPreEvent(String initiator, NameIdentifier identifier, String 
userName) {
-    super(initiator, identifier);
+  public GetUserPreEvent(String initiator, String metalake, String userName) {
+    super(initiator, NameIdentifierUtil.ofUser(metalake, userName));
     this.userName = userName;
   }
 
   /**
-   * Returns the user info for the user which is getting retrieved.
+   * Returns the username for the user being retrieved.
    *
-   * @return the username which is requested to be retrieved.
+   * @return The username that is requested to be retrieved.
    */
   public String userName() {
     return userName;
diff --git 
a/core/src/main/java/org/apache/gravitino/listener/api/event/GrantUserRolesEvent.java
 
b/core/src/main/java/org/apache/gravitino/listener/api/event/GrantUserRolesEvent.java
new file mode 100644
index 0000000000..160c0e106b
--- /dev/null
+++ 
b/core/src/main/java/org/apache/gravitino/listener/api/event/GrantUserRolesEvent.java
@@ -0,0 +1,78 @@
+/*
+ * 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.gravitino.listener.api.event;
+
+import com.google.common.collect.ImmutableList;
+import java.util.List;
+import org.apache.gravitino.annotation.DeveloperApi;
+import org.apache.gravitino.listener.api.info.UserInfo;
+import org.apache.gravitino.utils.NameIdentifierUtil;
+
+/** Represents an event triggered after the operation of granting roles to a 
user. */
+@DeveloperApi
+public class GrantUserRolesEvent extends UserEvent {
+  private final UserInfo grantUserInfo;
+  private final List<String> roles;
+
+  /**
+   * Constructs a new {@link GrantUserRolesEvent} instance with the specified 
initiator, metalake
+   * name, user information, and roles granted.
+   *
+   * @param initiator the user who initiated the role-granting operation.
+   * @param metalake the name of the metalake that the operation affects.
+   * @param grantUserInfo the user information of the user whose roles are 
being granted.
+   * @param roles the list of roles that are granted to the user.
+   */
+  public GrantUserRolesEvent(
+      String initiator, String metalake, UserInfo grantUserInfo, List<String> 
roles) {
+    super(initiator, NameIdentifierUtil.ofUser(metalake, 
grantUserInfo.name()));
+
+    this.grantUserInfo = grantUserInfo;
+    this.roles = roles == null ? ImmutableList.of() : 
ImmutableList.copyOf(roles);
+  }
+
+  /**
+   * Returns the user information of the user to whom the roles are granted.
+   *
+   * @return the {@link UserInfo} instance containing the details of the user.
+   */
+  public UserInfo grantUserInfo() {
+    return grantUserInfo;
+  }
+
+  /**
+   * Returns the list of roles that have been granted to the user.
+   *
+   * @return the list of roles granted to the user.
+   */
+  public List<String> roles() {
+    return roles;
+  }
+
+  /**
+   * Returns the operation type of this event.
+   *
+   * @return the operation type.
+   */
+  @Override
+  public OperationType operationType() {
+    return OperationType.GRANT_USER_ROLES;
+  }
+}
diff --git 
a/core/src/main/java/org/apache/gravitino/listener/api/event/GrantUserRolesPreEvent.java
 
b/core/src/main/java/org/apache/gravitino/listener/api/event/GrantUserRolesPreEvent.java
new file mode 100644
index 0000000000..43febc7f9e
--- /dev/null
+++ 
b/core/src/main/java/org/apache/gravitino/listener/api/event/GrantUserRolesPreEvent.java
@@ -0,0 +1,76 @@
+/*
+ * 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.gravitino.listener.api.event;
+
+import java.util.List;
+import org.apache.gravitino.annotation.DeveloperApi;
+import org.apache.gravitino.utils.NameIdentifierUtil;
+
+/** Represents an event triggered before granting roles to a user. */
+@DeveloperApi
+public class GrantUserRolesPreEvent extends UserPreEvent {
+  private final String userName;
+  private final List<String> roles;
+
+  /**
+   * Constructs a new {@link GrantUserRolesPreEvent} instance with the 
specified initiator, metalake
+   * name, username, and roles to be granted.
+   *
+   * @param initiator the user who initiated the role-granting event.
+   * @param metalake the name of the metalake on which the operation is being 
performed.
+   * @param userName the username of the user to whom the roles will be 
granted.
+   * @param roles the list of roles that will be granted to the user.
+   */
+  protected GrantUserRolesPreEvent(
+      String initiator, String metalake, String userName, List<String> roles) {
+    super(initiator, NameIdentifierUtil.ofUser(metalake, userName));
+
+    this.userName = userName;
+    this.roles = roles;
+  }
+
+  /**
+   * Returns the username of the user to whom the roles will be granted.
+   *
+   * @return the username of the user.
+   */
+  public String userName() {
+    return userName;
+  }
+
+  /**
+   * Returns the list of roles that are being granted to the user.
+   *
+   * @return the list of roles to be granted.
+   */
+  public List<String> roles() {
+    return roles;
+  }
+
+  /**
+   * Returns the operation type of this event.
+   *
+   * @return the operation type.
+   */
+  @Override
+  public OperationType operationType() {
+    return OperationType.GRANT_USER_ROLES;
+  }
+}
diff --git 
a/core/src/main/java/org/apache/gravitino/listener/api/event/ListUserNamesPreEvent.java
 
b/core/src/main/java/org/apache/gravitino/listener/api/event/ListUserNamesEvent.java
similarity index 69%
copy from 
core/src/main/java/org/apache/gravitino/listener/api/event/ListUserNamesPreEvent.java
copy to 
core/src/main/java/org/apache/gravitino/listener/api/event/ListUserNamesEvent.java
index d5596d06d7..6c2bca1368 100644
--- 
a/core/src/main/java/org/apache/gravitino/listener/api/event/ListUserNamesPreEvent.java
+++ 
b/core/src/main/java/org/apache/gravitino/listener/api/event/ListUserNamesEvent.java
@@ -22,18 +22,18 @@ package org.apache.gravitino.listener.api.event;
 import org.apache.gravitino.NameIdentifier;
 import org.apache.gravitino.annotation.DeveloperApi;
 
-/** Represents an event triggered before list users name from specific 
metalake */
+/** Represents an event triggered after successfully listing usernames from a 
specific metalake. */
 @DeveloperApi
-public class ListUserNamesPreEvent extends UserPreEvent {
-
+public class ListUserNamesEvent extends UserEvent {
   /**
-   * Construct a new {@link ListUserNamesPreEvent} instance with the specified 
user and identifier.
+   * Constructs a new {@link ListUserNamesEvent} instance with the specified 
initiator and metalake
+   * name.
    *
-   * @param initiator the user who initiated the list-user request.
-   * @param identifier the identifier of the metalake which is being listed.
+   * @param initiator the user who initiated the request to list usernames.
+   * @param metalake the name of the metalake from which the usernames are 
listed.
    */
-  protected ListUserNamesPreEvent(String initiator, NameIdentifier identifier) 
{
-    super(initiator, identifier);
+  protected ListUserNamesEvent(String initiator, String metalake) {
+    super(initiator, NameIdentifier.of(metalake));
   }
 
   /**
diff --git 
a/core/src/main/java/org/apache/gravitino/listener/api/event/ListUserNamesPreEvent.java
 
b/core/src/main/java/org/apache/gravitino/listener/api/event/ListUserNamesPreEvent.java
index d5596d06d7..e34d10cb74 100644
--- 
a/core/src/main/java/org/apache/gravitino/listener/api/event/ListUserNamesPreEvent.java
+++ 
b/core/src/main/java/org/apache/gravitino/listener/api/event/ListUserNamesPreEvent.java
@@ -22,18 +22,19 @@ package org.apache.gravitino.listener.api.event;
 import org.apache.gravitino.NameIdentifier;
 import org.apache.gravitino.annotation.DeveloperApi;
 
-/** Represents an event triggered before list users name from specific 
metalake */
+/** Represents an event triggered before listing usernames from a specific 
metalake. */
 @DeveloperApi
 public class ListUserNamesPreEvent extends UserPreEvent {
 
   /**
-   * Construct a new {@link ListUserNamesPreEvent} instance with the specified 
user and identifier.
+   * Constructs a new {@link ListUserNamesPreEvent} instance with the 
specified user and metalake
+   * name.
    *
-   * @param initiator the user who initiated the list-user request.
-   * @param identifier the identifier of the metalake which is being listed.
+   * @param initiator the user who initiated the request to list usernames.
+   * @param metalake the name of the metalake from which to list usernames.
    */
-  protected ListUserNamesPreEvent(String initiator, NameIdentifier identifier) 
{
-    super(initiator, identifier);
+  protected ListUserNamesPreEvent(String initiator, String metalake) {
+    super(initiator, NameIdentifier.of(metalake));
   }
 
   /**
diff --git 
a/core/src/main/java/org/apache/gravitino/listener/api/event/ListUsersPreEvent.java
 
b/core/src/main/java/org/apache/gravitino/listener/api/event/ListUsersEvent.java
similarity index 69%
copy from 
core/src/main/java/org/apache/gravitino/listener/api/event/ListUsersPreEvent.java
copy to 
core/src/main/java/org/apache/gravitino/listener/api/event/ListUsersEvent.java
index 975d37d77b..5188e22a9a 100644
--- 
a/core/src/main/java/org/apache/gravitino/listener/api/event/ListUsersPreEvent.java
+++ 
b/core/src/main/java/org/apache/gravitino/listener/api/event/ListUsersEvent.java
@@ -22,18 +22,19 @@ package org.apache.gravitino.listener.api.event;
 import org.apache.gravitino.NameIdentifier;
 import org.apache.gravitino.annotation.DeveloperApi;
 
-/** Represents an event triggered before list user from specific metalake */
+/** Represents an event triggered after successfully listing users from a 
specific metalake. */
 @DeveloperApi
-public class ListUsersPreEvent extends UserPreEvent {
+public class ListUsersEvent extends UserEvent {
 
   /**
-   * Construct a new {@link ListUsersPreEvent} instance with the specified 
user and identifier.
+   * Constructs a new {@link ListUsersEvent} instance with the specified 
initiator and metalake
+   * name.
    *
-   * @param initiator the user who initiated the list-user request.
-   * @param identifier the identifier of the metalake which is being listed.
+   * @param initiator the user who initiated the request to list users.
+   * @param metalake the name of the metalake from which the users are listed.
    */
-  protected ListUsersPreEvent(String initiator, NameIdentifier identifier) {
-    super(initiator, identifier);
+  protected ListUsersEvent(String initiator, String metalake) {
+    super(initiator, NameIdentifier.of(metalake));
   }
 
   /**
diff --git 
a/core/src/main/java/org/apache/gravitino/listener/api/event/ListUsersPreEvent.java
 
b/core/src/main/java/org/apache/gravitino/listener/api/event/ListUsersPreEvent.java
index 975d37d77b..1c3d21c67a 100644
--- 
a/core/src/main/java/org/apache/gravitino/listener/api/event/ListUsersPreEvent.java
+++ 
b/core/src/main/java/org/apache/gravitino/listener/api/event/ListUsersPreEvent.java
@@ -30,10 +30,10 @@ public class ListUsersPreEvent extends UserPreEvent {
    * Construct a new {@link ListUsersPreEvent} instance with the specified 
user and identifier.
    *
    * @param initiator the user who initiated the list-user request.
-   * @param identifier the identifier of the metalake which is being listed.
+   * @param metalake the metalake name to list users from.
    */
-  protected ListUsersPreEvent(String initiator, NameIdentifier identifier) {
-    super(initiator, identifier);
+  protected ListUsersPreEvent(String initiator, String metalake) {
+    super(initiator, NameIdentifier.of(metalake));
   }
 
   /**
diff --git 
a/core/src/main/java/org/apache/gravitino/listener/api/event/OperationType.java 
b/core/src/main/java/org/apache/gravitino/listener/api/event/OperationType.java
index 0f7a0d2098..a61d68dd6f 100644
--- 
a/core/src/main/java/org/apache/gravitino/listener/api/event/OperationType.java
+++ 
b/core/src/main/java/org/apache/gravitino/listener/api/event/OperationType.java
@@ -119,6 +119,8 @@ public enum OperationType {
   GET_USER,
   LIST_USERS,
   LIST_USER_NAMES,
+  GRANT_USER_ROLES,
+  REVOKE_USER_ROLES,
 
   // Group
   ADD_GROUP,
diff --git 
a/core/src/main/java/org/apache/gravitino/listener/api/event/RemoveUserEvent.java
 
b/core/src/main/java/org/apache/gravitino/listener/api/event/RemoveUserEvent.java
new file mode 100644
index 0000000000..5b48dd7743
--- /dev/null
+++ 
b/core/src/main/java/org/apache/gravitino/listener/api/event/RemoveUserEvent.java
@@ -0,0 +1,77 @@
+/*
+ * 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.gravitino.listener.api.event;
+
+import org.apache.gravitino.annotation.DeveloperApi;
+import org.apache.gravitino.utils.NameIdentifierUtil;
+
+/** Represents an event triggered after a user is successfully removed from a 
metalake. */
+@DeveloperApi
+public class RemoveUserEvent extends UserEvent {
+  private final String removedUserName;
+  private final boolean isExists;
+
+  /**
+   * Constructs a new {@link RemoveUserEvent} instance with the specified 
initiator, metalake name,
+   * removed username, and removal status.
+   *
+   * @param initiator the user who initiated the remove user operation.
+   * @param metalake the name of the metalake from which the user was removed.
+   * @param removedUserName the username of the user that was removed.
+   * @param isExists {@code true} if the user was successfully removed, {@code 
false} if no such
+   *     user exists in the metalake.
+   */
+  protected RemoveUserEvent(
+      String initiator, String metalake, String removedUserName, boolean 
isExists) {
+    super(initiator, NameIdentifierUtil.ofUser(metalake, removedUserName));
+
+    this.removedUserName = removedUserName;
+    this.isExists = isExists;
+  }
+
+  /**
+   * Returns the username of the user that was removed from the metalake.
+   *
+   * @return the username of the removed user.
+   */
+  public String removedUserName() {
+    return removedUserName;
+  }
+
+  /**
+   * Returns whether the user was removed from the metalake.
+   *
+   * @return {@code true} if the user was removed, {@code false} if no such 
user exists in the
+   *     metalake.
+   */
+  public boolean isExists() {
+    return isExists;
+  }
+
+  /**
+   * Returns the operation type of this event.
+   *
+   * @return the operation type of this event.
+   */
+  @Override
+  public OperationType operationType() {
+    return OperationType.REMOVE_USER;
+  }
+}
diff --git 
a/core/src/main/java/org/apache/gravitino/listener/api/event/RemoveUserPreEvent.java
 
b/core/src/main/java/org/apache/gravitino/listener/api/event/RemoveUserPreEvent.java
index 3c39c5a9aa..a6b66ec883 100644
--- 
a/core/src/main/java/org/apache/gravitino/listener/api/event/RemoveUserPreEvent.java
+++ 
b/core/src/main/java/org/apache/gravitino/listener/api/event/RemoveUserPreEvent.java
@@ -19,8 +19,8 @@
 
 package org.apache.gravitino.listener.api.event;
 
-import org.apache.gravitino.NameIdentifier;
 import org.apache.gravitino.annotation.DeveloperApi;
+import org.apache.gravitino.utils.NameIdentifierUtil;
 
 /** Represents an event triggered before remove a user from specific metalake. 
*/
 @DeveloperApi
@@ -31,11 +31,11 @@ public class RemoveUserPreEvent extends UserPreEvent {
    * Construct a new {@link RemoveUserPreEvent} instance with the specified 
user and identifier.
    *
    * @param initiator the user who initiated the remove user operation.
-   * @param identifier the identifier of the metalake where the user is 
removed.
+   * @param metalake the metalake name of the metalake from which the user is 
to be removed.
    * @param userName the username which is requested to be removed from the 
metalake.
    */
-  protected RemoveUserPreEvent(String initiator, NameIdentifier identifier, 
String userName) {
-    super(initiator, identifier);
+  protected RemoveUserPreEvent(String initiator, String metalake, String 
userName) {
+    super(initiator, NameIdentifierUtil.ofUser(metalake, userName));
 
     this.userName = userName;
   }
diff --git 
a/core/src/main/java/org/apache/gravitino/listener/api/event/RevokeUserRolesEvent.java
 
b/core/src/main/java/org/apache/gravitino/listener/api/event/RevokeUserRolesEvent.java
new file mode 100644
index 0000000000..94d0450f05
--- /dev/null
+++ 
b/core/src/main/java/org/apache/gravitino/listener/api/event/RevokeUserRolesEvent.java
@@ -0,0 +1,78 @@
+/*
+ * 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.gravitino.listener.api.event;
+
+import com.google.common.collect.ImmutableList;
+import java.util.List;
+import org.apache.gravitino.annotation.DeveloperApi;
+import org.apache.gravitino.listener.api.info.UserInfo;
+import org.apache.gravitino.utils.NameIdentifierUtil;
+
+/** Represents an event triggered after the operation of revoking roles from a 
user. */
+@DeveloperApi
+public class RevokeUserRolesEvent extends UserEvent {
+  private final UserInfo revokedUserInfo;
+  private final List<String> roles;
+
+  /**
+   * Constructs a new {@link RevokeUserRolesEvent} instance with the specified 
initiator, metalake
+   * name, user information, and revoked roles.
+   *
+   * @param initiator the user who initiated the role-revocation operation.
+   * @param metalake the name of the metalake that the operation affects.
+   * @param revokedUserInfo the user information of the user whose roles are 
being revoked.
+   * @param roles the list of roles that have been revoked from the user.
+   */
+  public RevokeUserRolesEvent(
+      String initiator, String metalake, UserInfo revokedUserInfo, 
List<String> roles) {
+    super(initiator, NameIdentifierUtil.ofUser(metalake, 
revokedUserInfo.name()));
+
+    this.revokedUserInfo = revokedUserInfo;
+    this.roles = roles == null ? ImmutableList.of() : 
ImmutableList.copyOf(roles);
+  }
+
+  /**
+   * Returns the user information of the user whose roles have been revoked.
+   *
+   * @return the {@link UserInfo} instance containing the details of the user.
+   */
+  public UserInfo revokedUserInfo() {
+    return revokedUserInfo;
+  }
+
+  /**
+   * Returns the list of roles that have been revoked from the user.
+   *
+   * @return the list of revoked roles.
+   */
+  public List<String> roles() {
+    return roles;
+  }
+
+  /**
+   * Returns the operation type of this event.
+   *
+   * @return the operation type.
+   */
+  @Override
+  public OperationType operationType() {
+    return OperationType.REVOKE_USER_ROLES;
+  }
+}
diff --git 
a/core/src/main/java/org/apache/gravitino/listener/api/event/AddUserPreEvent.java
 
b/core/src/main/java/org/apache/gravitino/listener/api/event/RevokeUserRolesPreEvent.java
similarity index 50%
copy from 
core/src/main/java/org/apache/gravitino/listener/api/event/AddUserPreEvent.java
copy to 
core/src/main/java/org/apache/gravitino/listener/api/event/RevokeUserRolesPreEvent.java
index 611ec97b6d..abb836ca4c 100644
--- 
a/core/src/main/java/org/apache/gravitino/listener/api/event/AddUserPreEvent.java
+++ 
b/core/src/main/java/org/apache/gravitino/listener/api/event/RevokeUserRolesPreEvent.java
@@ -19,36 +19,51 @@
 
 package org.apache.gravitino.listener.api.event;
 
-import org.apache.gravitino.NameIdentifier;
+import java.util.List;
 import org.apache.gravitino.annotation.DeveloperApi;
+import org.apache.gravitino.utils.NameIdentifierUtil;
 
-/** Represents an event triggered before add a user to a metalake. */
+/** Represents an event triggered before revoking roles from a user. */
 @DeveloperApi
-public class AddUserPreEvent extends UserPreEvent {
+public class RevokeUserRolesPreEvent extends UserPreEvent {
   private final String userName;
+  private final List<String> roles;
 
   /**
-   * Construct a new {@link AddUserPreEvent} instance with initiator, 
identifier and username.
+   * Constructs a new {@link RevokeUserRolesPreEvent} instance with the 
specified initiator,
+   * metalake name, username, and roles to be revoked.
    *
-   * @param initiator the user who initiated the add-user request.
-   * @param identifier the identifier of the metalake which the user is being 
added to.
-   * @param userName the username which is requested to be added to the 
metalake.
+   * @param initiator the user who initiated the event to revoke roles.
+   * @param metalake the name of the metalake on which the operation is being 
performed.
+   * @param userName the username of the user whose roles are being revoked.
+   * @param roles the list of roles to be revoked from the user.
    */
-  public AddUserPreEvent(String initiator, NameIdentifier identifier, String 
userName) {
-    super(initiator, identifier);
+  public RevokeUserRolesPreEvent(
+      String initiator, String metalake, String userName, List<String> roles) {
+    super(initiator, NameIdentifierUtil.ofUser(metalake, userName));
 
     this.userName = userName;
+    this.roles = roles;
   }
 
   /**
-   * Returns the user information which is being added to the metalake.
+   * Returns the username of the user whose roles are being revoked.
    *
-   * @return the username which is requested to be added to the metalake.
+   * @return the username of the user.
    */
   public String userName() {
     return userName;
   }
 
+  /**
+   * Returns the list of roles that are being revoked from the user.
+   *
+   * @return the list of revoked roles.
+   */
+  public List<String> roles() {
+    return roles;
+  }
+
   /**
    * Returns the operation type of this event.
    *
@@ -56,6 +71,6 @@ public class AddUserPreEvent extends UserPreEvent {
    */
   @Override
   public OperationType operationType() {
-    return OperationType.ADD_USER;
+    return OperationType.REVOKE_USER_ROLES;
   }
 }
diff --git 
a/core/src/main/java/org/apache/gravitino/listener/api/event/ListUsersPreEvent.java
 b/core/src/main/java/org/apache/gravitino/listener/api/event/UserEvent.java
similarity index 53%
copy from 
core/src/main/java/org/apache/gravitino/listener/api/event/ListUsersPreEvent.java
copy to 
core/src/main/java/org/apache/gravitino/listener/api/event/UserEvent.java
index 975d37d77b..e8c0d36da5 100644
--- 
a/core/src/main/java/org/apache/gravitino/listener/api/event/ListUsersPreEvent.java
+++ b/core/src/main/java/org/apache/gravitino/listener/api/event/UserEvent.java
@@ -22,27 +22,31 @@ package org.apache.gravitino.listener.api.event;
 import org.apache.gravitino.NameIdentifier;
 import org.apache.gravitino.annotation.DeveloperApi;
 
-/** Represents an event triggered before list user from specific metalake */
+/**
+ * Represents an abstract base class for events related to user operations. 
This class extends
+ * {@link Event} to provide a more specific context involving operations 
performed by users. It
+ * captures essential information including the user performing the operation 
and the identifier of
+ * the metalake being operated on.
+ *
+ * <p>Concrete implementations of this class should provide additional details 
pertinent to the
+ * specific type of user operation being represented.
+ */
 @DeveloperApi
-public class ListUsersPreEvent extends UserPreEvent {
+public abstract class UserEvent extends Event {
 
   /**
-   * Construct a new {@link ListUsersPreEvent} instance with the specified 
user and identifier.
+   * Construct a new {@link UserEvent} instance with the given initiator and 
identifier.
    *
-   * @param initiator the user who initiated the list-user request.
-   * @param identifier the identifier of the metalake which is being listed.
+   * @param initiator the user who triggered the event.
+   * @param identifier the identifier of the metalake being operated on.
    */
-  protected ListUsersPreEvent(String initiator, NameIdentifier identifier) {
+  protected UserEvent(String initiator, NameIdentifier identifier) {
     super(initiator, identifier);
   }
 
-  /**
-   * Returns the operation type for this event.
-   *
-   * @return the operation type for this event.
-   */
+  /** {@inheritDoc} */
   @Override
-  public OperationType operationType() {
-    return OperationType.LIST_USERS;
+  public OperationStatus operationStatus() {
+    return OperationStatus.SUCCESS;
   }
 }
diff --git 
a/core/src/main/java/org/apache/gravitino/listener/api/info/ModelVersionInfo.java
 
b/core/src/main/java/org/apache/gravitino/listener/api/info/ModelVersionInfo.java
index 6f4c956433..0b690bd160 100644
--- 
a/core/src/main/java/org/apache/gravitino/listener/api/info/ModelVersionInfo.java
+++ 
b/core/src/main/java/org/apache/gravitino/listener/api/info/ModelVersionInfo.java
@@ -23,12 +23,14 @@ import com.google.common.collect.ImmutableMap;
 import java.util.Map;
 import java.util.Optional;
 import org.apache.gravitino.Audit;
+import org.apache.gravitino.annotation.DeveloperApi;
 import org.apache.gravitino.model.ModelVersion;
 
 /**
  * {@link ModelVersionInfo} exposes model version information for event 
listener, it's supposed to
  * be read only. Most of the fields are shallow copied internally not deep 
copies for performance.
  */
+@DeveloperApi
 public class ModelVersionInfo {
   private final String uri;
   private final Map<String, String> properties;
diff --git 
a/core/src/main/java/org/apache/gravitino/listener/api/event/ListUsersPreEvent.java
 b/core/src/main/java/org/apache/gravitino/listener/api/info/UserInfo.java
similarity index 54%
copy from 
core/src/main/java/org/apache/gravitino/listener/api/event/ListUsersPreEvent.java
copy to core/src/main/java/org/apache/gravitino/listener/api/info/UserInfo.java
index 975d37d77b..e881df3a64 100644
--- 
a/core/src/main/java/org/apache/gravitino/listener/api/event/ListUsersPreEvent.java
+++ b/core/src/main/java/org/apache/gravitino/listener/api/info/UserInfo.java
@@ -17,32 +17,43 @@
  * under the License.
  */
 
-package org.apache.gravitino.listener.api.event;
+package org.apache.gravitino.listener.api.info;
 
-import org.apache.gravitino.NameIdentifier;
+import java.util.List;
 import org.apache.gravitino.annotation.DeveloperApi;
+import org.apache.gravitino.authorization.User;
 
-/** Represents an event triggered before list user from specific metalake */
+/** Provides read-only access to user information for event listeners. */
 @DeveloperApi
-public class ListUsersPreEvent extends UserPreEvent {
+public class UserInfo {
+  private final String name;
+  private List<String> roles;
 
   /**
-   * Construct a new {@link ListUsersPreEvent} instance with the specified 
user and identifier.
+   * Construct a new {@link UserInfo} instance with the given {@link User} 
information.
    *
-   * @param initiator the user who initiated the list-user request.
-   * @param identifier the identifier of the metalake which is being listed.
+   * @param user the {@link User} instance.
    */
-  protected ListUsersPreEvent(String initiator, NameIdentifier identifier) {
-    super(initiator, identifier);
+  public UserInfo(User user) {
+    this.name = user.name();
+    this.roles = user.roles();
   }
 
   /**
-   * Returns the operation type for this event.
+   * Returns the name of the user.
    *
-   * @return the operation type for this event.
+   * @return the name of the user
    */
-  @Override
-  public OperationType operationType() {
-    return OperationType.LIST_USERS;
+  public String name() {
+    return name;
+  }
+
+  /**
+   * Returns the roles of the user.
+   *
+   * @return the roles of the user.
+   */
+  public List<String> roles() {
+    return roles;
   }
 }
diff --git 
a/core/src/main/java/org/apache/gravitino/utils/NameIdentifierUtil.java 
b/core/src/main/java/org/apache/gravitino/utils/NameIdentifierUtil.java
index 47b203ed4d..ba2aa6fa89 100644
--- a/core/src/main/java/org/apache/gravitino/utils/NameIdentifierUtil.java
+++ b/core/src/main/java/org/apache/gravitino/utils/NameIdentifierUtil.java
@@ -103,6 +103,18 @@ public class NameIdentifierUtil {
   public static NameIdentifier ofTag(String metalake, String tagName) {
     return NameIdentifier.of(NamespaceUtil.ofTag(metalake), tagName);
   }
+
+  /**
+   * Create the user {@link NameIdentifier} with the given metalake and 
username.
+   *
+   * @param metalake The metalake name
+   * @param userName The username
+   * @return the created user {@link NameIdentifier}
+   */
+  public static NameIdentifier ofUser(String metalake, String userName) {
+    return NameIdentifier.of(NamespaceUtil.ofUser(metalake), userName);
+  }
+
   /**
    * Create the column {@link NameIdentifier} with the given metalake, 
catalog, schema, table and
    * column name.
diff --git a/core/src/main/java/org/apache/gravitino/utils/NamespaceUtil.java 
b/core/src/main/java/org/apache/gravitino/utils/NamespaceUtil.java
index eebab09346..3b9d56087d 100644
--- a/core/src/main/java/org/apache/gravitino/utils/NamespaceUtil.java
+++ b/core/src/main/java/org/apache/gravitino/utils/NamespaceUtil.java
@@ -82,6 +82,16 @@ public class NamespaceUtil {
     return Namespace.of(metalake, Entity.SYSTEM_CATALOG_RESERVED_NAME, 
Entity.TAG_SCHEMA_NAME);
   }
 
+  /**
+   * Create a namespace for user.
+   *
+   * @param metalake The metalake name
+   * @return A namespace for user
+   */
+  public static Namespace ofUser(String metalake) {
+    return Namespace.of(metalake, Entity.SYSTEM_CATALOG_RESERVED_NAME, 
Entity.USER_SCHEMA_NAME);
+  }
+
   /**
    * Create a namespace for column.
    *
diff --git 
a/core/src/test/java/org/apache/gravitino/listener/api/event/TestUserEvent.java 
b/core/src/test/java/org/apache/gravitino/listener/api/event/TestUserEvent.java
index 9fcff6f86a..1d822367cf 100644
--- 
a/core/src/test/java/org/apache/gravitino/listener/api/event/TestUserEvent.java
+++ 
b/core/src/test/java/org/apache/gravitino/listener/api/event/TestUserEvent.java
@@ -32,6 +32,8 @@ import 
org.apache.gravitino.exceptions.NoSuchMetalakeException;
 import org.apache.gravitino.exceptions.NoSuchUserException;
 import org.apache.gravitino.listener.DummyEventListener;
 import org.apache.gravitino.listener.EventBus;
+import org.apache.gravitino.listener.api.info.UserInfo;
+import org.apache.gravitino.utils.NameIdentifierUtil;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Test;
@@ -50,6 +52,10 @@ public class TestUserEvent {
   private User user;
   private User otherUser;
   private NameIdentifier identifier;
+  private NameIdentifier otherIdentifier;
+  private NameIdentifier inExistIdentifier;
+  private List<String> grantedRoles;
+  private List<String> revokedRoles;
 
   @BeforeAll
   void init() {
@@ -58,7 +64,11 @@ public class TestUserEvent {
     this.inExistUserName = "user_not_exist";
     this.user = getMockUser(userName, ImmutableList.of("test", "engineer"));
     this.otherUser = getMockUser(otherUserName, null);
-    this.identifier = NameIdentifier.of(METALAKE);
+    this.identifier = NameIdentifierUtil.ofUser(METALAKE, userName);
+    this.otherIdentifier = NameIdentifierUtil.ofUser(METALAKE, otherUserName);
+    this.inExistIdentifier = NameIdentifierUtil.ofUser(METALAKE, 
inExistUserName);
+    this.grantedRoles = ImmutableList.of("test", "engineer");
+    this.revokedRoles = ImmutableList.of("admin", "scientist");
 
     this.dummyEventListener = new DummyEventListener();
     EventBus eventBus = new 
EventBus(Collections.singletonList(dummyEventListener));
@@ -69,6 +79,15 @@ public class TestUserEvent {
     System.out.println(failureDispatcher);
   }
 
+  @Test
+  void testUserInfo() {
+    User mockUser = getMockUser("mock_user", ImmutableList.of("admin"));
+    UserInfo info = new UserInfo(mockUser);
+
+    Assertions.assertEquals("mock_user", info.name());
+    Assertions.assertEquals(ImmutableList.of("admin"), info.roles());
+  }
+
   @Test
   void testAddUserPreEvent() {
     dispatcher.addUser(METALAKE, otherUserName);
@@ -80,11 +99,28 @@ public class TestUserEvent {
     Assertions.assertEquals(OperationType.ADD_USER, preEvent.operationType());
 
     AddUserPreEvent addUserPreEvent = (AddUserPreEvent) preEvent;
-    Assertions.assertEquals(identifier, addUserPreEvent.identifier());
+    Assertions.assertEquals(otherIdentifier, addUserPreEvent.identifier());
     String userName = addUserPreEvent.userName();
     Assertions.assertEquals(otherUserName, userName);
   }
 
+  @Test
+  void testAddUserEvent() {
+    dispatcher.addUser(METALAKE, userName);
+
+    // validate post-event
+    Event event = dummyEventListener.popPostEvent();
+    Assertions.assertEquals(AddUserEvent.class, event.getClass());
+    Assertions.assertEquals(OperationStatus.SUCCESS, event.operationStatus());
+    Assertions.assertEquals(OperationType.ADD_USER, event.operationType());
+
+    AddUserEvent addUserEvent = (AddUserEvent) event;
+    Assertions.assertEquals(identifier, addUserEvent.identifier());
+    UserInfo userInfo = addUserEvent.addedUserInfo();
+
+    validateUserInfo(userInfo, user);
+  }
+
   @Test
   void testGetUserPreEventWithExistingUser() {
     dispatcher.getUser(METALAKE, userName);
@@ -113,6 +149,35 @@ public class TestUserEvent {
         NoSuchMetalakeException.class, () -> 
dispatcher.getUser(INEXIST_METALAKE, userName));
   }
 
+  @Test
+  void testGetUserEventWithExistingUser() {
+    dispatcher.getUser(METALAKE, userName);
+
+    // validate post-event
+    Event event = dummyEventListener.popPostEvent();
+    Assertions.assertEquals(GetUserEvent.class, event.getClass());
+    Assertions.assertEquals(OperationStatus.SUCCESS, event.operationStatus());
+    Assertions.assertEquals(OperationType.GET_USER, event.operationType());
+
+    GetUserEvent getUserEvent = (GetUserEvent) event;
+    Assertions.assertEquals(identifier, getUserEvent.identifier());
+    UserInfo userInfo = getUserEvent.loadedUserInfo();
+
+    validateUserInfo(userInfo, user);
+  }
+
+  @Test
+  void testGetUserEventWithNonExistingUser() {
+    Assertions.assertThrows(
+        NoSuchUserException.class, () -> dispatcher.getUser(METALAKE, 
inExistUserName));
+  }
+
+  @Test
+  void testGetUserEventWithNonExistingMetalake() {
+    Assertions.assertThrows(
+        NoSuchMetalakeException.class, () -> 
dispatcher.getUser(INEXIST_METALAKE, userName));
+  }
+
   @Test
   void testListUserPreEvent() {
     dispatcher.listUsers(METALAKE);
@@ -123,7 +188,21 @@ public class TestUserEvent {
     Assertions.assertEquals(OperationStatus.UNPROCESSED, 
preEvent.operationStatus());
 
     ListUsersPreEvent listUsersPreEvent = (ListUsersPreEvent) preEvent;
-    Assertions.assertEquals(identifier, listUsersPreEvent.identifier());
+    Assertions.assertEquals(NameIdentifier.of(METALAKE), 
listUsersPreEvent.identifier());
+  }
+
+  @Test
+  void testListUserEvent() {
+    dispatcher.listUsers(METALAKE);
+
+    // validate post-event
+    Event event = dummyEventListener.popPostEvent();
+    Assertions.assertEquals(ListUsersEvent.class, event.getClass());
+    Assertions.assertEquals(OperationStatus.SUCCESS, event.operationStatus());
+    Assertions.assertEquals(OperationType.LIST_USERS, event.operationType());
+
+    ListUsersEvent listUsersEvent = (ListUsersEvent) event;
+    Assertions.assertEquals(NameIdentifier.of(METALAKE), 
listUsersEvent.identifier());
   }
 
   @Test
@@ -136,7 +215,21 @@ public class TestUserEvent {
     Assertions.assertEquals(OperationStatus.UNPROCESSED, 
preEvent.operationStatus());
 
     ListUserNamesPreEvent listUserNamesPreEvent = (ListUserNamesPreEvent) 
preEvent;
-    Assertions.assertEquals(identifier, listUserNamesPreEvent.identifier());
+    Assertions.assertEquals(NameIdentifier.of(METALAKE), 
listUserNamesPreEvent.identifier());
+  }
+
+  @Test
+  void testListUserNamesEvent() {
+    dispatcher.listUserNames(METALAKE);
+
+    // validate post-event
+    Event event = dummyEventListener.popPostEvent();
+    Assertions.assertEquals(ListUserNamesEvent.class, event.getClass());
+    Assertions.assertEquals(OperationStatus.SUCCESS, event.operationStatus());
+    Assertions.assertEquals(OperationType.LIST_USER_NAMES, 
event.operationType());
+
+    ListUserNamesEvent listUserNamesEvent = (ListUserNamesEvent) event;
+    Assertions.assertEquals(NameIdentifier.of(METALAKE), 
listUserNamesEvent.identifier());
   }
 
   @Test
@@ -155,6 +248,106 @@ public class TestUserEvent {
     Assertions.assertEquals(userName, removedUserName);
   }
 
+  @Test
+  void testRemoveUserEventWithExistingUser() {
+    dispatcher.removeUser(METALAKE, userName);
+
+    // validate post-event
+    Event event = dummyEventListener.popPostEvent();
+    Assertions.assertEquals(RemoveUserEvent.class, event.getClass());
+    Assertions.assertEquals(OperationStatus.SUCCESS, event.operationStatus());
+    Assertions.assertEquals(OperationType.REMOVE_USER, event.operationType());
+
+    RemoveUserEvent removeUserEvent = (RemoveUserEvent) event;
+    Assertions.assertEquals(identifier, removeUserEvent.identifier());
+    Assertions.assertTrue(removeUserEvent.isExists());
+    Assertions.assertEquals(userName, removeUserEvent.removedUserName());
+  }
+
+  @Test
+  void testRemoveUserPreEventWithNonExistingUser() {
+    dispatcher.removeUser(METALAKE, inExistUserName);
+
+    // validate post-event
+    Event event = dummyEventListener.popPostEvent();
+    Assertions.assertEquals(RemoveUserEvent.class, event.getClass());
+    Assertions.assertEquals(OperationStatus.SUCCESS, event.operationStatus());
+    Assertions.assertEquals(OperationType.REMOVE_USER, event.operationType());
+
+    RemoveUserEvent removeUserEvent = (RemoveUserEvent) event;
+    Assertions.assertEquals(inExistIdentifier, removeUserEvent.identifier());
+    Assertions.assertFalse(removeUserEvent.isExists());
+    Assertions.assertEquals(inExistUserName, 
removeUserEvent.removedUserName());
+  }
+
+  @Test
+  void testGrantRolesToUserPreEvent() {
+    dispatcher.grantRolesToUser(METALAKE, grantedRoles, userName);
+
+    // validate pre-event
+    PreEvent preEvent = dummyEventListener.popPreEvent();
+    Assertions.assertEquals(GrantUserRolesPreEvent.class, preEvent.getClass());
+    Assertions.assertEquals(OperationStatus.UNPROCESSED, 
preEvent.operationStatus());
+    Assertions.assertEquals(OperationType.GRANT_USER_ROLES, 
preEvent.operationType());
+
+    GrantUserRolesPreEvent grantUserRolesEvent = (GrantUserRolesPreEvent) 
preEvent;
+    Assertions.assertEquals(identifier, grantUserRolesEvent.identifier());
+    String grantedUserName = grantUserRolesEvent.userName();
+    Assertions.assertEquals(userName, grantedUserName);
+    Assertions.assertEquals(grantedRoles, grantUserRolesEvent.roles());
+  }
+
+  @Test
+  void testGrantRolesToUserEvent() {
+    dispatcher.grantRolesToUser(METALAKE, grantedRoles, userName);
+
+    // validate post-event
+    Event event = dummyEventListener.popPostEvent();
+    Assertions.assertEquals(GrantUserRolesEvent.class, event.getClass());
+    Assertions.assertEquals(OperationStatus.SUCCESS, event.operationStatus());
+    Assertions.assertEquals(OperationType.GRANT_USER_ROLES, 
event.operationType());
+
+    GrantUserRolesEvent grantUserRolesEvent = (GrantUserRolesEvent) event;
+    Assertions.assertEquals(identifier, grantUserRolesEvent.identifier());
+    UserInfo userInfo = grantUserRolesEvent.grantUserInfo();
+
+    validateUserInfo(userInfo, user);
+  }
+
+  @Test
+  void testRevokeRolesUserPreEvent() {
+    dispatcher.revokeRolesFromUser(METALAKE, revokedRoles, otherUserName);
+
+    // validate pre-event
+    PreEvent preEvent = dummyEventListener.popPreEvent();
+    Assertions.assertEquals(RevokeUserRolesPreEvent.class, 
preEvent.getClass());
+    Assertions.assertEquals(OperationStatus.UNPROCESSED, 
preEvent.operationStatus());
+    Assertions.assertEquals(OperationType.REVOKE_USER_ROLES, 
preEvent.operationType());
+
+    RevokeUserRolesPreEvent revokeUserRolesEvent = (RevokeUserRolesPreEvent) 
preEvent;
+    Assertions.assertEquals(otherIdentifier, 
revokeUserRolesEvent.identifier());
+    String revokedUserName = revokeUserRolesEvent.userName();
+    Assertions.assertEquals(otherUserName, revokedUserName);
+    Assertions.assertEquals(revokedRoles, revokeUserRolesEvent.roles());
+  }
+
+  @Test
+  void testRevokeRolesUserEvent() {
+    dispatcher.revokeRolesFromUser(METALAKE, revokedRoles, otherUserName);
+
+    // validate post-event
+    Event event = dummyEventListener.popPostEvent();
+    Assertions.assertEquals(RevokeUserRolesEvent.class, event.getClass());
+    Assertions.assertEquals(OperationStatus.SUCCESS, event.operationStatus());
+    Assertions.assertEquals(OperationType.REVOKE_USER_ROLES, 
event.operationType());
+
+    RevokeUserRolesEvent revokeUserRolesEvent = (RevokeUserRolesEvent) event;
+    Assertions.assertEquals(otherIdentifier, 
revokeUserRolesEvent.identifier());
+    UserInfo userInfo = revokeUserRolesEvent.revokedUserInfo();
+
+    validateUserInfo(userInfo, otherUser);
+  }
+
   private AccessControlEventDispatcher mockUserDispatcher() {
     AccessControlEventDispatcher dispatcher = 
mock(AccessControlEventDispatcher.class);
     when(dispatcher.addUser(METALAKE, userName)).thenReturn(user);
@@ -171,6 +364,9 @@ public class TestUserEvent {
         .thenThrow(new NoSuchUserException("user not found"));
     when(dispatcher.getUser(INEXIST_METALAKE, userName))
         .thenThrow(new NoSuchMetalakeException("user not found"));
+    when(dispatcher.grantRolesToUser(METALAKE, grantedRoles, 
userName)).thenReturn(user);
+    when(dispatcher.revokeRolesFromUser(METALAKE, revokedRoles, otherUserName))
+        .thenReturn(otherUser);
 
     return dispatcher;
   }
@@ -190,4 +386,9 @@ public class TestUserEvent {
 
     return user;
   }
+
+  private void validateUserInfo(UserInfo userInfo, User expectedUser) {
+    Assertions.assertEquals(userInfo.name(), expectedUser.name());
+    Assertions.assertEquals(userInfo.roles(), expectedUser.roles());
+  }
 }
diff --git 
a/core/src/test/java/org/apache/gravitino/utils/TestNameIdentifierUtil.java 
b/core/src/test/java/org/apache/gravitino/utils/TestNameIdentifierUtil.java
index e5db1eb107..8dc9170b9f 100644
--- a/core/src/test/java/org/apache/gravitino/utils/TestNameIdentifierUtil.java
+++ b/core/src/test/java/org/apache/gravitino/utils/TestNameIdentifierUtil.java
@@ -22,12 +22,14 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
+import com.google.common.base.Joiner;
 import org.apache.gravitino.Entity;
 import org.apache.gravitino.MetadataObject;
 import org.apache.gravitino.MetadataObjects;
 import org.apache.gravitino.NameIdentifier;
 import org.apache.gravitino.exceptions.IllegalNameIdentifierException;
 import org.apache.gravitino.exceptions.IllegalNamespaceException;
+import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
 
 public class TestNameIdentifierUtil {
@@ -152,4 +154,22 @@ public class TestNameIdentifierUtil {
             () -> NameIdentifierUtil.toMetadataObject(model, 
Entity.EntityType.MODEL_VERSION));
     assertTrue(e3.getMessage().contains("Entity type MODEL_VERSION is not 
supported"));
   }
+
+  @Test
+  void testOfUser() {
+    String userName = "userA";
+    String metalake = "demo_metalake";
+
+    NameIdentifier nameIdentifier = NameIdentifierUtil.ofUser(metalake, 
userName);
+    Assertions.assertEquals(
+        Joiner.on(".")
+            .join(metalake, Entity.SYSTEM_CATALOG_RESERVED_NAME, 
Entity.USER_SCHEMA_NAME, userName),
+        nameIdentifier.toString());
+    Assertions.assertEquals(
+        Joiner.on(".").join(metalake, Entity.SYSTEM_CATALOG_RESERVED_NAME, 
Entity.USER_SCHEMA_NAME),
+        NamespaceUtil.ofUser(metalake).toString());
+    Assertions.assertThrows(
+        IllegalArgumentException.class, () -> NameIdentifierUtil.ofUser(null, 
userName));
+    Assertions.assertThrows(IllegalArgumentException.class, () -> 
NamespaceUtil.ofUser(null));
+  }
 }
diff --git a/docs/gravitino-server-config.md b/docs/gravitino-server-config.md
index 092735ee71..2a04ca2ce6 100644
--- a/docs/gravitino-server-config.md
+++ b/docs/gravitino-server-config.md
@@ -118,17 +118,19 @@ Gravitino triggers a pre-event before the operation, a 
post-event after the comp
 
 ##### Post-event
 
-| Operation type                      | Post-event                             
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
              [...]
-|-------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 [...]
-| table operation                     | `CreateTableEvent`, `AlterTableEvent`, 
`DropTableEvent`, `LoadTableEvent`, `ListTableEvent`, `PurgeTableFailureEvent`, 
`CreateTableFailureEvent`, `AlterTableFailureEvent`, `DropTableFailureEvent`, 
`LoadTableFailureEvent`, `ListTableFailureEvent`, `PurgeTableFailureEvent`      
                                                                                
                                                                                
                [...]
-| fileset operation                   | `CreateFileSetEvent`, 
`AlterFileSetEvent`, `DropFileSetEvent`, `LoadFileSetEvent`, 
`ListFileSetEvent`, `CreateFileSetFailureEvent`, `AlterFileSetFailureEvent`, 
`DropFileSetFailureEvent`, `LoadFileSetFailureEvent`, `ListFileSetFailureEvent` 
                                                                                
                                                                                
                                                     [...]
-| topic operation                     | `CreateTopicEvent`, `AlterTopicEvent`, 
`DropTopicEvent`, `LoadTopicEvent`, `ListTopicEvent`, 
`CreateTopicFailureEvent`, `AlterTopicFailureEvent`, `DropTopicFailureEvent`, 
`LoadTopicFailureEvent`, `ListTopicFailureEvent`                                
                                                                                
                                                                                
                                          [...]
-| schema operation                    | `CreateSchemaEvent`, 
`AlterSchemaEvent`, `DropSchemaEvent`, `LoadSchemaEvent`, `ListSchemaEvent`, 
`CreateSchemaFailureEvent`, `AlterSchemaFailureEvent`, 
`DropSchemaFailureEvent`, `LoadSchemaFailureEvent`, `ListSchemaFailureEvent`    
                                                                                
                                                                                
                                                            [...]
-| catalog operation                   | `CreateCatalogEvent`, 
`AlterCatalogEvent`, `DropCatalogEvent`, `LoadCatalogEvent`, 
`ListCatalogEvent`, `CreateCatalogFailureEvent`, `AlterCatalogFailureEvent`, 
`DropCatalogFailureEvent`, `LoadCatalogFailureEvent`, `ListCatalogFailureEvent` 
                                                                                
                                                                                
                                                     [...]
-| metalake operation                  | `CreateMetalakeEvent`, 
`AlterMetalakeEvent`, `DropMetalakeEvent`, `LoadMetalakeEvent`, 
`ListMetalakeEvent`, `CreateMetalakeFailureEvent`, `AlterMetalakeFailureEvent`, 
`DropMetalakeFailureEvent`, `LoadMetalakeFailureEvent`, 
`ListMetalakeFailureEvent`                                                      
                                                                                
                                                                      [...]
-| Iceberg REST server table operation | `IcebergCreateTableEvent`, 
`IcebergUpdateTableEvent`, `IcebergDropTableEvent`, `IcebergLoadTableEvent`, 
`IcebergListTableEvent`, `IcebergTableExistsEvent`, `IcebergRenameTableEvent`, 
`IcebergCreateTableFailureEvent`, `IcebergUpdateTableFailureEvent`, 
`IcebergDropTableFailureEvent`, `IcebergLoadTableFailureEvent`, 
`IcebergListTableFailureEvent`, `IcebergRenameTableFailureEvent`, 
`IcebergTableExistsFailureEvent`                                        [...]
+| Operation type                      | Post-event                             
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
              [...]
+|-------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 [...]
+| table operation                     | `CreateTableEvent`, `AlterTableEvent`, 
`DropTableEvent`, `LoadTableEvent`, `ListTableEvent`, `PurgeTableFailureEvent`, 
`CreateTableFailureEvent`, `AlterTableFailureEvent`, `DropTableFailureEvent`, 
`LoadTableFailureEvent`, `ListTableFailureEvent`, `PurgeTableFailureEvent`      
                                                                                
                                                                                
                [...]
+| fileset operation                   | `CreateFileSetEvent`, 
`AlterFileSetEvent`, `DropFileSetEvent`, `LoadFileSetEvent`, 
`ListFileSetEvent`, `CreateFileSetFailureEvent`, `AlterFileSetFailureEvent`, 
`DropFileSetFailureEvent`, `LoadFileSetFailureEvent`, `ListFileSetFailureEvent` 
                                                                                
                                                                                
                                                     [...]
+| topic operation                     | `CreateTopicEvent`, `AlterTopicEvent`, 
`DropTopicEvent`, `LoadTopicEvent`, `ListTopicEvent`, 
`CreateTopicFailureEvent`, `AlterTopicFailureEvent`, `DropTopicFailureEvent`, 
`LoadTopicFailureEvent`, `ListTopicFailureEvent`                                
                                                                                
                                                                                
                                          [...]
+| schema operation                    | `CreateSchemaEvent`, 
`AlterSchemaEvent`, `DropSchemaEvent`, `LoadSchemaEvent`, `ListSchemaEvent`, 
`CreateSchemaFailureEvent`, `AlterSchemaFailureEvent`, 
`DropSchemaFailureEvent`, `LoadSchemaFailureEvent`, `ListSchemaFailureEvent`    
                                                                                
                                                                                
                                                            [...]
+| catalog operation                   | `CreateCatalogEvent`, 
`AlterCatalogEvent`, `DropCatalogEvent`, `LoadCatalogEvent`, 
`ListCatalogEvent`, `CreateCatalogFailureEvent`, `AlterCatalogFailureEvent`, 
`DropCatalogFailureEvent`, `LoadCatalogFailureEvent`, `ListCatalogFailureEvent` 
                                                                                
                                                                                
                                                     [...]
+| metalake operation                  | `CreateMetalakeEvent`, 
`AlterMetalakeEvent`, `DropMetalakeEvent`, `LoadMetalakeEvent`, 
`ListMetalakeEvent`, `CreateMetalakeFailureEvent`, `AlterMetalakeFailureEvent`, 
`DropMetalakeFailureEvent`, `LoadMetalakeFailureEvent`, 
`ListMetalakeFailureEvent`                                                      
                                                                                
                                                                      [...]
+| Iceberg REST server table operation | `IcebergCreateTableEvent`, 
`IcebergUpdateTableEvent`, `IcebergDropTableEvent`, `IcebergLoadTableEvent`, 
`IcebergListTableEvent`, `IcebergTableExistsEvent`, `IcebergRenameTableEvent`, 
`IcebergCreateTableFailureEvent`, `IcebergUpdateTableFailureEvent`, 
`IcebergDropTableFailureEvent`, `IcebergLoadTableFailureEvent`, 
`IcebergListTableFailureEvent`, `IcebergRenameTableFailureEvent`, 
`IcebergTableExistsFailureEvent`                                        [...]
 | tag operation                       | `ListTagsEvent`, `ListTagsInfoEvent`, 
`CreateTagEvent`, `GetTagEvent`, `AlterTagEvent`, `DeleteTagEvent`, 
`ListMetadataObjectsForTagEvent`, `ListTagsForMetadataObjectEvent`, 
`ListTagsInfoForMetadataObjectEvent`, `AssociateTagsForMetadataObjectEvent`, 
`GetTagForMetadataObjectEvent`, `ListTagsFailureEvent`, 
`ListTagInfoFailureEvent`, `CreateTagFailureEvent`, `GetTagFailureEvent`, 
`AlterTagFailureEvent`, `DeleteTagFailureEvent`, `ListMetadataObjectsFo [...]
-| model operation                     | `DeleteModelEvent`,  
`DeleteModelVersionEvent`,  `GetModelEvent`, `GetModelVersionEvent`, 
`LinkModelVersionEvent`, `ListModelEvent`, `ListModelVersionsEvent`,  
`RegisterAndLinkModelEvent`, `RegisterModelEvent`,  `DeleteModelFailureEvent`, 
`DeleteModelVersionFailureEvent`, `GetModelFailureEvent`, 
`GetModelVersionFailureEvent`, `LinkModelVersionFailureEvent`, 
`ListModelFailureEvent`, `ListModelVersionFailureEvent`, 
`RegisterAndLinkModelFailureEvent`, [...]
+| model operation                     | `DeleteModelEvent`,  
`DeleteModelVersionEvent`,  `GetModelEvent`, `GetModelVersionEvent`, 
`LinkModelVersionEvent`, `ListModelEvent`, `ListModelVersionsEvent`,  
`RegisterAndLinkModelEvent`, `RegisterModelEvent`,  `DeleteModelFailureEvent`, 
`DeleteModelVersionFailureEvent`, `GetModelFailureEvent`, 
`GetModelVersionFailureEvent`, `LinkModelVersionFailureEvent`, 
`ListModelFailureEvent`, `ListModelVersionFailureEvent`, 
`RegisterAndLinkModelFailureEvent`, [...]
+| user operation                     | `AddUserEvent`, `GetUserEvent`, 
`ListUserNamesEvent`, `ListUsersEvent`, `RemoveUserEvent`                       
                                                                                
                                                                                
                                                                                
                                                                                
                      [...]
+
 
 ##### Pre-event
 

Reply via email to