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

### 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