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 c4618d9035 [#6713] feat(core): Support user failure event to Gravitino 
server (#6817)
c4618d9035 is described below

commit c4618d9035e78bad650b1cfc7922857dbc59b046
Author: Lord of Abyss <103809695+abyss-l...@users.noreply.github.com>
AuthorDate: Wed Apr 2 17:18:52 2025 +0800

    [#6713] feat(core): Support user failure event to Gravitino server (#6817)
    
    ### What changes were proposed in this pull request?
    
    Support user failure event to Gravitino server
    
    ### Why are the changes needed?
    
    Fix: #6713
    
    ### Does this PR introduce _any_ user-facing change?
    
    Users can now listen for the user failure Event.
    
    ### How was this patch tested?
    
    local test.
---
 .../api/event/AccessControlEventDispatcher.java    |  14 +--
 .../listener/api/event/AddUserFailureEvent.java    |  65 +++++++++++
 .../listener/api/event/GetUserFailureEvent.java    |  65 +++++++++++
 .../api/event/GrantUserRolesFailureEvent.java      |  77 +++++++++++++
 .../api/event/ListUserNamesFailureEvent.java       |  51 +++++++++
 .../listener/api/event/ListUsersFailureEvent.java  |  51 +++++++++
 .../listener/api/event/RemoveUserFailureEvent.java |  65 +++++++++++
 .../api/event/RevokeUserRolesFailureEvent.java     |  78 +++++++++++++
 .../listener/api/event/UserFailureEvent.java       |  44 ++++++++
 .../listener/api/event/TestUserEvent.java          | 123 +++++++++++++++++++++
 docs/gravitino-server-config.md                    |  24 ++--
 11 files changed, 638 insertions(+), 19 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 2cb3bcd8fb..59d6cfb3bb 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
@@ -77,7 +77,7 @@ public class AccessControlEventDispatcher implements 
AccessControlDispatcher {
 
       return userObject;
     } catch (Exception e) {
-      // TODO: add failure event
+      eventBus.dispatchEvent(new AddUserFailureEvent(initiator, metalake, e, 
user));
       throw e;
     }
   }
@@ -94,7 +94,7 @@ public class AccessControlEventDispatcher implements 
AccessControlDispatcher {
 
       return isExists;
     } catch (Exception e) {
-      // TODO: add failure event
+      eventBus.dispatchEvent(new RemoveUserFailureEvent(initiator, metalake, 
e, user));
       throw e;
     }
   }
@@ -112,7 +112,7 @@ public class AccessControlEventDispatcher implements 
AccessControlDispatcher {
 
       return userObject;
     } catch (Exception e) {
-      // TODO: add failure event
+      eventBus.dispatchEvent(new GetUserFailureEvent(initiator, metalake, e, 
user));
       throw e;
     }
   }
@@ -129,7 +129,7 @@ public class AccessControlEventDispatcher implements 
AccessControlDispatcher {
 
       return users;
     } catch (Exception e) {
-      // TODO: add failure event
+      eventBus.dispatchEvent(new ListUsersFailureEvent(initiator, metalake, 
e));
       throw e;
     }
   }
@@ -146,7 +146,7 @@ public class AccessControlEventDispatcher implements 
AccessControlDispatcher {
 
       return userNames;
     } catch (Exception e) {
-      // TODO: add failure event
+      eventBus.dispatchEvent(new ListUserNamesFailureEvent(initiator, 
metalake, e));
       throw e;
     }
   }
@@ -252,7 +252,7 @@ public class AccessControlEventDispatcher implements 
AccessControlDispatcher {
 
       return userObject;
     } catch (Exception e) {
-      // TODO: add failure event
+      eventBus.dispatchEvent(new GrantUserRolesFailureEvent(initiator, 
metalake, e, user, roles));
       throw e;
     }
   }
@@ -309,7 +309,7 @@ public class AccessControlEventDispatcher implements 
AccessControlDispatcher {
 
       return userObject;
     } catch (Exception e) {
-      // TODO: add failure event
+      eventBus.dispatchEvent(new RevokeUserRolesFailureEvent(initiator, 
metalake, e, user, roles));
       throw e;
     }
   }
diff --git 
a/core/src/main/java/org/apache/gravitino/listener/api/event/AddUserFailureEvent.java
 
b/core/src/main/java/org/apache/gravitino/listener/api/event/AddUserFailureEvent.java
new file mode 100644
index 0000000000..79ec431cb6
--- /dev/null
+++ 
b/core/src/main/java/org/apache/gravitino/listener/api/event/AddUserFailureEvent.java
@@ -0,0 +1,65 @@
+/*
+ * 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 when an attempt to add a user to a metalake 
fails due to an
+ * exception.
+ */
+@DeveloperApi
+public class AddUserFailureEvent extends UserFailureEvent {
+  private final String userName;
+
+  /**
+   * Constructs a new {@code AddUserFailureEvent} instance.
+   *
+   * @param user the user who initiated the operation
+   * @param metalake the name of the metalake where the user was attempted to 
be added
+   * @param exception the exception encountered during the operation
+   * @param userName the name of the user that failed to be added
+   */
+  public AddUserFailureEvent(String user, String metalake, Exception 
exception, String userName) {
+    super(user, NameIdentifierUtil.ofUser(metalake, userName), exception);
+
+    this.userName = userName;
+  }
+
+  /**
+   * Returns the name of the user that failed to be added.
+   *
+   * @return the username involved in the failure event
+   */
+  public String userName() {
+    return userName;
+  }
+
+  /**
+   * Returns the operation type for this event.
+   *
+   * @return the operation type for this event.
+   */
+  @Override
+  public OperationType operationType() {
+    return OperationType.ADD_USER;
+  }
+}
diff --git 
a/core/src/main/java/org/apache/gravitino/listener/api/event/GetUserFailureEvent.java
 
b/core/src/main/java/org/apache/gravitino/listener/api/event/GetUserFailureEvent.java
new file mode 100644
index 0000000000..8329ff7ca3
--- /dev/null
+++ 
b/core/src/main/java/org/apache/gravitino/listener/api/event/GetUserFailureEvent.java
@@ -0,0 +1,65 @@
+/*
+ * 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 when an attempt to retrieve a user from the 
metalake fails due to
+ * an exception.
+ */
+@DeveloperApi
+public class GetUserFailureEvent extends UserFailureEvent {
+  private final String userName;
+
+  /**
+   * Constructs a new {@code GetUserFailureEvent} instance.
+   *
+   * @param user the user who initiated the operation
+   * @param metalake the name of the metalake from which the user was 
attempted to be retrieved
+   * @param exception the exception encountered during the operation
+   * @param userName the name of the user that failed to be retrieved
+   */
+  public GetUserFailureEvent(String user, String metalake, Exception 
exception, String userName) {
+    super(user, NameIdentifierUtil.ofUser(metalake, userName), exception);
+
+    this.userName = userName;
+  }
+
+  /**
+   * Returns the name of the user that failed to be retrieved.
+   *
+   * @return the username involved in the failure event
+   */
+  public String userName() {
+    return userName;
+  }
+
+  /**
+   * Returns the operation type for this event.
+   *
+   * @return the operation type for this event.
+   */
+  @Override
+  public OperationType operationType() {
+    return OperationType.GET_USER;
+  }
+}
diff --git 
a/core/src/main/java/org/apache/gravitino/listener/api/event/GrantUserRolesFailureEvent.java
 
b/core/src/main/java/org/apache/gravitino/listener/api/event/GrantUserRolesFailureEvent.java
new file mode 100644
index 0000000000..5db68065bc
--- /dev/null
+++ 
b/core/src/main/java/org/apache/gravitino/listener/api/event/GrantUserRolesFailureEvent.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 java.util.List;
+import org.apache.gravitino.annotation.DeveloperApi;
+import org.apache.gravitino.utils.NameIdentifierUtil;
+
+/**
+ * Represents an event triggered when an attempt to grant roles to a user 
fails due to an exception.
+ */
+@DeveloperApi
+public class GrantUserRolesFailureEvent extends UserFailureEvent {
+  private final String userName;
+  private final List<String> roles;
+
+  /**
+   * Constructs a new {@code GrantUserRolesFailureEvent} instance.
+   *
+   * @param initiator the user who initiated the operation
+   * @param metalake the name of the metalake where the operation was attempted
+   * @param exception the exception encountered during the operation
+   * @param userName the name of the user to whom the roles were attempted to 
be granted
+   * @param roles the list of roles that were attempted to be granted to the 
user
+   */
+  public GrantUserRolesFailureEvent(
+      String initiator, String metalake, Exception exception, String userName, 
List<String> roles) {
+    super(initiator, NameIdentifierUtil.ofUser(metalake, userName), exception);
+    this.userName = userName;
+    this.roles = roles;
+  }
+
+  /**
+   * Returns the name of the user to whom the roles were attempted to be 
granted.
+   *
+   * @return the username involved in the failure event
+   */
+  public String userName() {
+    return userName;
+  }
+
+  /**
+   * Returns the list of roles that were attempted to be granted to the user.
+   *
+   * @return the list of roles involved in the failure event
+   */
+  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/ListUserNamesFailureEvent.java
 
b/core/src/main/java/org/apache/gravitino/listener/api/event/ListUserNamesFailureEvent.java
new file mode 100644
index 0000000000..c692047726
--- /dev/null
+++ 
b/core/src/main/java/org/apache/gravitino/listener/api/event/ListUserNamesFailureEvent.java
@@ -0,0 +1,51 @@
+/*
+ * 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 when an attempt to list usernames from a 
metalake fails due to an
+ * exception.
+ */
+@DeveloperApi
+public class ListUserNamesFailureEvent extends UserFailureEvent {
+  /**
+   * Constructs a new {@code ListUserNamesFailureEvent} instance.
+   *
+   * @param user the user who initiated the operation
+   * @param metalake the name of the metalake where the operation was attempted
+   * @param exception the exception encountered during the operation
+   */
+  protected ListUserNamesFailureEvent(String user, String metalake, Exception 
exception) {
+    super(user, NameIdentifierUtil.ofMetalake(metalake), exception);
+  }
+
+  /**
+   * Returns the operation type for this event.
+   *
+   * @return the operation type for this event.
+   */
+  @Override
+  public OperationType operationType() {
+    return OperationType.LIST_USER_NAMES;
+  }
+}
diff --git 
a/core/src/main/java/org/apache/gravitino/listener/api/event/ListUsersFailureEvent.java
 
b/core/src/main/java/org/apache/gravitino/listener/api/event/ListUsersFailureEvent.java
new file mode 100644
index 0000000000..3cd52e0654
--- /dev/null
+++ 
b/core/src/main/java/org/apache/gravitino/listener/api/event/ListUsersFailureEvent.java
@@ -0,0 +1,51 @@
+/*
+ * 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 when an attempt to list users from a metalake 
fails due to an
+ * exception.
+ */
+@DeveloperApi
+public class ListUsersFailureEvent extends UserFailureEvent {
+  /**
+   * Constructs a new {@code ListUsersFailureEvent} instance.
+   *
+   * @param user the user who initiated the operation
+   * @param metalake the name of the metalake where the operation was attempted
+   * @param exception the exception encountered during the operation
+   */
+  protected ListUsersFailureEvent(String user, String metalake, Exception 
exception) {
+    super(user, NameIdentifierUtil.ofMetalake(metalake), exception);
+  }
+
+  /**
+   * Returns the operation type for this event.
+   *
+   * @return the operation type for this event.
+   */
+  @Override
+  public OperationType operationType() {
+    return OperationType.LIST_USERS;
+  }
+}
diff --git 
a/core/src/main/java/org/apache/gravitino/listener/api/event/RemoveUserFailureEvent.java
 
b/core/src/main/java/org/apache/gravitino/listener/api/event/RemoveUserFailureEvent.java
new file mode 100644
index 0000000000..7d991568b9
--- /dev/null
+++ 
b/core/src/main/java/org/apache/gravitino/listener/api/event/RemoveUserFailureEvent.java
@@ -0,0 +1,65 @@
+/*
+ * 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 when an attempt to remove a user from a 
metalake fails due to an
+ * exception.
+ */
+@DeveloperApi
+public class RemoveUserFailureEvent extends UserFailureEvent {
+  private final String userName;
+
+  /**
+   * Constructs a new {@code RemoveUserFailureEvent} instance.
+   *
+   * @param user the user who initiated the operation
+   * @param metalake the name of the metalake from which the user was 
attempted to be removed
+   * @param exception the exception encountered during the operation
+   * @param userName the name of the user that failed to be removed
+   */
+  public RemoveUserFailureEvent(
+      String user, String metalake, Exception exception, String userName) {
+    super(user, NameIdentifierUtil.ofUser(metalake, userName), exception);
+    this.userName = userName;
+  }
+
+  /**
+   * Returns the name of the user that failed to be removed.
+   *
+   * @return the username involved in the failure event
+   */
+  public String userName() {
+    return userName;
+  }
+
+  /**
+   * Returns the operation type for this event.
+   *
+   * @return the operation type for this event.
+   */
+  @Override
+  public OperationType operationType() {
+    return OperationType.REMOVE_USER;
+  }
+}
diff --git 
a/core/src/main/java/org/apache/gravitino/listener/api/event/RevokeUserRolesFailureEvent.java
 
b/core/src/main/java/org/apache/gravitino/listener/api/event/RevokeUserRolesFailureEvent.java
new file mode 100644
index 0000000000..d64d02e794
--- /dev/null
+++ 
b/core/src/main/java/org/apache/gravitino/listener/api/event/RevokeUserRolesFailureEvent.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 java.util.List;
+import org.apache.gravitino.annotation.DeveloperApi;
+import org.apache.gravitino.utils.NameIdentifierUtil;
+
+/**
+ * Represents an event triggered when an attempt to revoke roles from a user 
fails due to an
+ * exception.
+ */
+@DeveloperApi
+public class RevokeUserRolesFailureEvent extends UserFailureEvent {
+  private final String userName;
+  private final List<String> roles;
+
+  /**
+   * Constructs a new {@code RevokeUserRolesFailureEvent} instance.
+   *
+   * @param initiator the user who initiated the operation
+   * @param metalake the name of the metalake where the operation was attempted
+   * @param exception the exception encountered during the operation
+   * @param userName the name of the user from whom the roles were attempted 
to be revoked
+   * @param roles the list of roles that were attempted to be revoked from the 
user
+   */
+  public RevokeUserRolesFailureEvent(
+      String initiator, String metalake, Exception exception, String userName, 
List<String> roles) {
+    super(initiator, NameIdentifierUtil.ofUser(metalake, userName), exception);
+    this.userName = userName;
+    this.roles = roles;
+  }
+
+  /**
+   * Returns the name of the user from whom the roles were attempted to be 
revoked.
+   *
+   * @return the username involved in the failure event
+   */
+  public String userName() {
+    return userName;
+  }
+
+  /**
+   * Returns the list of roles that were attempted to be revoked from the user.
+   *
+   * @return the list of roles involved in the failure event
+   */
+  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/UserFailureEvent.java
 
b/core/src/main/java/org/apache/gravitino/listener/api/event/UserFailureEvent.java
new file mode 100644
index 0000000000..cd1489648b
--- /dev/null
+++ 
b/core/src/main/java/org/apache/gravitino/listener/api/event/UserFailureEvent.java
@@ -0,0 +1,44 @@
+/*
+ * 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.NameIdentifier;
+import org.apache.gravitino.annotation.DeveloperApi;
+
+/**
+ * Represents an event that is triggered when a user operation fails due to an 
exception. This event
+ * captures the user information, a unique identifier for the operation, and 
the exception that
+ * caused the failure.
+ */
+@DeveloperApi
+public abstract class UserFailureEvent extends FailureEvent {
+
+  /**
+   * Constructs a new {@code UserFailureEvent} instance.
+   *
+   * @param user the user who initiated the operation
+   * @param identifier the unique identifier associated with the user operation
+   * @param exception the exception encountered during the operation, 
providing details about the
+   *     failure
+   */
+  protected UserFailureEvent(String user, NameIdentifier identifier, Exception 
exception) {
+    super(user, identifier, exception);
+  }
+}
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 1d822367cf..d4fe9f00e8 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
@@ -121,6 +121,23 @@ public class TestUserEvent {
     validateUserInfo(userInfo, user);
   }
 
+  @Test
+  void testAddUserFailureEvent() {
+    Assertions.assertThrowsExactly(
+        GravitinoRuntimeException.class, () -> 
failureDispatcher.addUser(METALAKE, userName));
+
+    // validate post-event
+    Event event = dummyEventListener.popPostEvent();
+    Assertions.assertEquals(AddUserFailureEvent.class, event.getClass());
+    Assertions.assertEquals(OperationStatus.FAILURE, event.operationStatus());
+    Assertions.assertEquals(OperationType.ADD_USER, event.operationType());
+
+    AddUserFailureEvent addUserFailureEvent = (AddUserFailureEvent) event;
+    Assertions.assertEquals(
+        NameIdentifierUtil.ofUser(METALAKE, userName), 
addUserFailureEvent.identifier());
+    Assertions.assertEquals(userName, addUserFailureEvent.userName());
+  }
+
   @Test
   void testGetUserPreEventWithExistingUser() {
     dispatcher.getUser(METALAKE, userName);
@@ -178,6 +195,23 @@ public class TestUserEvent {
         NoSuchMetalakeException.class, () -> 
dispatcher.getUser(INEXIST_METALAKE, userName));
   }
 
+  @Test
+  void testGetUserFailureEvent() {
+    Assertions.assertThrowsExactly(
+        GravitinoRuntimeException.class,
+        () -> failureDispatcher.getUser(METALAKE, inExistUserName));
+
+    // validate post-event
+    Event event = dummyEventListener.popPostEvent();
+    Assertions.assertEquals(GetUserFailureEvent.class, event.getClass());
+    Assertions.assertEquals(OperationStatus.FAILURE, event.operationStatus());
+    Assertions.assertEquals(OperationType.GET_USER, event.operationType());
+
+    GetUserFailureEvent getUserFailureEvent = (GetUserFailureEvent) event;
+    Assertions.assertEquals(inExistIdentifier, 
getUserFailureEvent.identifier());
+    Assertions.assertEquals(inExistUserName, getUserFailureEvent.userName());
+  }
+
   @Test
   void testListUserPreEvent() {
     dispatcher.listUsers(METALAKE);
@@ -205,6 +239,22 @@ public class TestUserEvent {
     Assertions.assertEquals(NameIdentifier.of(METALAKE), 
listUsersEvent.identifier());
   }
 
+  @Test
+  void testListUserFailureEvent() {
+    Assertions.assertThrowsExactly(
+        GravitinoRuntimeException.class, () -> 
failureDispatcher.listUsers(INEXIST_METALAKE));
+
+    // validate post-event
+    Event event = dummyEventListener.popPostEvent();
+    Assertions.assertEquals(ListUsersFailureEvent.class, event.getClass());
+    Assertions.assertEquals(OperationStatus.FAILURE, event.operationStatus());
+    Assertions.assertEquals(OperationType.LIST_USERS, event.operationType());
+
+    ListUsersFailureEvent listUsersFailureEvent = (ListUsersFailureEvent) 
event;
+    Assertions.assertEquals(
+        NameIdentifier.of(INEXIST_METALAKE), 
listUsersFailureEvent.identifier());
+  }
+
   @Test
   void testListUserNamesPreEvent() {
     dispatcher.listUserNames(METALAKE);
@@ -232,6 +282,22 @@ public class TestUserEvent {
     Assertions.assertEquals(NameIdentifier.of(METALAKE), 
listUserNamesEvent.identifier());
   }
 
+  @Test
+  void testListUserNamesFailureEvent() {
+    Assertions.assertThrowsExactly(
+        GravitinoRuntimeException.class, () -> 
failureDispatcher.listUserNames(INEXIST_METALAKE));
+
+    // validate post-event
+    Event event = dummyEventListener.popPostEvent();
+    Assertions.assertEquals(ListUserNamesFailureEvent.class, event.getClass());
+    Assertions.assertEquals(OperationStatus.FAILURE, event.operationStatus());
+    Assertions.assertEquals(OperationType.LIST_USER_NAMES, 
event.operationType());
+
+    ListUserNamesFailureEvent listUserNamesFailureEvent = 
(ListUserNamesFailureEvent) event;
+    Assertions.assertEquals(
+        NameIdentifier.of(INEXIST_METALAKE), 
listUserNamesFailureEvent.identifier());
+  }
+
   @Test
   void testRemoveUserPreEventWithExistingUser() {
     dispatcher.removeUser(METALAKE, userName);
@@ -280,6 +346,23 @@ public class TestUserEvent {
     Assertions.assertEquals(inExistUserName, 
removeUserEvent.removedUserName());
   }
 
+  @Test
+  void testRemoveUserFailureEvent() {
+    Assertions.assertThrowsExactly(
+        GravitinoRuntimeException.class,
+        () -> failureDispatcher.removeUser(METALAKE, inExistUserName));
+
+    // validate post-event
+    Event event = dummyEventListener.popPostEvent();
+    Assertions.assertEquals(RemoveUserFailureEvent.class, event.getClass());
+    Assertions.assertEquals(OperationStatus.FAILURE, event.operationStatus());
+    Assertions.assertEquals(OperationType.REMOVE_USER, event.operationType());
+
+    RemoveUserFailureEvent removeUserFailureEvent = (RemoveUserFailureEvent) 
event;
+    Assertions.assertEquals(inExistIdentifier, 
removeUserFailureEvent.identifier());
+    Assertions.assertEquals(inExistUserName, 
removeUserFailureEvent.userName());
+  }
+
   @Test
   void testGrantRolesToUserPreEvent() {
     dispatcher.grantRolesToUser(METALAKE, grantedRoles, userName);
@@ -314,6 +397,26 @@ public class TestUserEvent {
     validateUserInfo(userInfo, user);
   }
 
+  @Test
+  void testGrantRolesToUserFailureEvent() {
+    Assertions.assertThrowsExactly(
+        GravitinoRuntimeException.class,
+        () -> failureDispatcher.grantRolesToUser(METALAKE, grantedRoles, 
inExistUserName));
+
+    // validate post-event
+    Event event = dummyEventListener.popPostEvent();
+    Assertions.assertEquals(GrantUserRolesFailureEvent.class, 
event.getClass());
+    Assertions.assertEquals(OperationStatus.FAILURE, event.operationStatus());
+    Assertions.assertEquals(OperationType.GRANT_USER_ROLES, 
event.operationType());
+
+    GrantUserRolesFailureEvent grantUserRolesFailureEvent = 
(GrantUserRolesFailureEvent) event;
+    Assertions.assertEquals(
+        NameIdentifierUtil.ofUser(METALAKE, inExistUserName),
+        grantUserRolesFailureEvent.identifier());
+    Assertions.assertEquals(inExistUserName, 
grantUserRolesFailureEvent.userName());
+    Assertions.assertEquals(grantedRoles, grantUserRolesFailureEvent.roles());
+  }
+
   @Test
   void testRevokeRolesUserPreEvent() {
     dispatcher.revokeRolesFromUser(METALAKE, revokedRoles, otherUserName);
@@ -348,6 +451,26 @@ public class TestUserEvent {
     validateUserInfo(userInfo, otherUser);
   }
 
+  @Test
+  void testRevokeRolesUserFailureEvent() {
+    Assertions.assertThrowsExactly(
+        GravitinoRuntimeException.class,
+        () -> failureDispatcher.revokeRolesFromUser(METALAKE, revokedRoles, 
inExistUserName));
+
+    // validate post-event
+    Event event = dummyEventListener.popPostEvent();
+    Assertions.assertEquals(RevokeUserRolesFailureEvent.class, 
event.getClass());
+    Assertions.assertEquals(OperationStatus.FAILURE, event.operationStatus());
+    Assertions.assertEquals(OperationType.REVOKE_USER_ROLES, 
event.operationType());
+
+    RevokeUserRolesFailureEvent revokeUserRolesFailureEvent = 
(RevokeUserRolesFailureEvent) event;
+    Assertions.assertEquals(
+        NameIdentifierUtil.ofUser(METALAKE, inExistUserName),
+        revokeUserRolesFailureEvent.identifier());
+    Assertions.assertEquals(inExistUserName, 
revokeUserRolesFailureEvent.userName());
+    Assertions.assertEquals(revokedRoles, revokeUserRolesFailureEvent.roles());
+  }
+
   private AccessControlEventDispatcher mockUserDispatcher() {
     AccessControlEventDispatcher dispatcher = 
mock(AccessControlEventDispatcher.class);
     when(dispatcher.addUser(METALAKE, userName)).thenReturn(user);
diff --git a/docs/gravitino-server-config.md b/docs/gravitino-server-config.md
index 95ac479adf..7dfce90c7e 100644
--- a/docs/gravitino-server-config.md
+++ b/docs/gravitino-server-config.md
@@ -118,19 +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`, [...]
-| user operation                     | `AddUserEvent`, `GetUserEvent`, 
`ListUserNamesEvent`, `ListUsersEvent`, `RemoveUserEvent`, 
`GrantUserRolesEvent`, `RevokeUserRolesEvent`                                   
                                                                                
                                                                                
                                                                                
                                           [...]
-| group operation                     | `AddGroupEvent`, `GetGroupEvent`, 
`ListGroupNamesEvent`, `ListGroupsEvent`, `RemoveGroupEvent`, 
`GrantGroupRolesEvent`, `RevokeGroupRolesEvent`                                 
                                                                                
                                                                                
                                                                                
                                     [...]
+| 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`, 
`GrantUserRolesEvent`, `RevokeUserRolesEvent`, `AddUserFailureEvent`, 
`GetUserFailureEvent`, `GrantUserRolesFailureEvent`, 
`ListUserNamesFailureEvent`, `ListUsersFailureEvent`, `RemoveUserFailureEvent`, 
`RevokeUserRolesFailureEvent`                                                   
                                                                                
[...]
+| group operation                     | `AddGroupEvent`, `GetGroupEvent`, 
`ListGroupNamesEvent`, `ListGroupsEvent`, `RemoveGroupEvent`, 
`GrantGroupRolesEvent`, `RevokeGroupRolesEvent`                                 
                                                                                
                                                                                
                                                                                
                                     [...]
 
 
 


Reply via email to