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

mchades 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 6c0e75aa1e [#9536] feat(core): Add event listener for function 
operations (#10499)
6c0e75aa1e is described below

commit 6c0e75aa1e5f999d6a52290fb678536fb4fe24f3
Author: akshay thorat <[email protected]>
AuthorDate: Thu Mar 26 18:37:31 2026 -0700

    [#9536] feat(core): Add event listener for function operations (#10499)
    
    ### What changes were proposed in this pull request?
    
    Add event/listener hooks for function CRUD operations (register, get,
    alter, drop, list). This follows the same pattern as existing entity
    event dispatchers (Table, Model, etc.).
    
    ### Why are the changes needed?
    
    New files:
    - FunctionInfo: read-only function info for event listeners
    - FunctionEvent/FunctionFailureEvent/FunctionPreEvent: base event
    classes
    - Register/Get/Alter/Drop/ListFunction Event/PreEvent/FailureEvent
    classes
    - FunctionEventDispatcher: decorates FunctionDispatcher with event
    dispatching
    - TestFunctionEvent: unit tests for all function events
    
    Modified files:
    - OperationType: added REGISTER/GET/ALTER/DROP/LIST_FUNCTION
    - GravitinoEnv: wired FunctionEventDispatcher into dispatcher chain
    
    Closes #9536
    
    ### Does this PR introduce _any_ user-facing change?
    No
    
    ### How was this patch tested?
    All tests passed
---
 .../java/org/apache/gravitino/GravitinoEnv.java    |  11 +-
 .../listener/FunctionEventDispatcher.java          | 176 ++++++++++
 .../listener/api/event/OperationType.java          |   8 +
 .../api/event/function/AlterFunctionEvent.java     |  77 +++++
 .../event/function/AlterFunctionFailureEvent.java  |  67 ++++
 .../api/event/function/AlterFunctionPreEvent.java  |  53 +++
 .../api/event/function/DropFunctionEvent.java      |  58 ++++
 .../event/function/DropFunctionFailureEvent.java   |  47 +++
 .../api/event/function/DropFunctionPreEvent.java   |  37 +++
 .../listener/api/event/function/FunctionEvent.java |  48 +++
 .../api/event/function/FunctionFailureEvent.java   |  42 +++
 .../api/event/function/FunctionPreEvent.java       |  32 ++
 .../api/event/function/GetFunctionEvent.java       |  58 ++++
 .../event/function/GetFunctionFailureEvent.java    |  44 +++
 .../api/event/function/GetFunctionPreEvent.java    |  37 +++
 .../api/event/function/ListFunctionEvent.java      |  59 ++++
 .../event/function/ListFunctionFailureEvent.java   |  60 ++++
 .../api/event/function/ListFunctionInfosEvent.java |  72 +++++
 .../api/event/function/ListFunctionPreEvent.java   |  50 +++
 .../api/event/function/RegisterFunctionEvent.java  |  59 ++++
 .../function/RegisterFunctionFailureEvent.java     |  67 ++++
 .../event/function/RegisterFunctionPreEvent.java   |  52 +++
 .../gravitino/listener/api/info/FunctionInfo.java  | 141 ++++++++
 .../listener/api/event/TestFunctionEvent.java      | 360 +++++++++++++++++++++
 docs/gravitino-server-config.md                    |   2 +
 25 files changed, 1712 insertions(+), 5 deletions(-)

diff --git a/core/src/main/java/org/apache/gravitino/GravitinoEnv.java 
b/core/src/main/java/org/apache/gravitino/GravitinoEnv.java
index 4918457bd0..d7c84baca3 100644
--- a/core/src/main/java/org/apache/gravitino/GravitinoEnv.java
+++ b/core/src/main/java/org/apache/gravitino/GravitinoEnv.java
@@ -75,6 +75,7 @@ import org.apache.gravitino.listener.CatalogEventDispatcher;
 import org.apache.gravitino.listener.EventBus;
 import org.apache.gravitino.listener.EventListenerManager;
 import org.apache.gravitino.listener.FilesetEventDispatcher;
+import org.apache.gravitino.listener.FunctionEventDispatcher;
 import org.apache.gravitino.listener.JobEventDispatcher;
 import org.apache.gravitino.listener.MetalakeEventDispatcher;
 import org.apache.gravitino.listener.ModelEventDispatcher;
@@ -612,15 +613,15 @@ public class GravitinoEnv {
         new ModelNormalizeDispatcher(modelHookDispatcher, catalogManager);
     this.modelDispatcher = new ModelEventDispatcher(eventBus, 
modelNormalizeDispatcher);
 
-    // TODO: Add FunctionHookDispatcher and FunctionEventDispatcher when needed
-    // The operation chain should be:
-    // FunctionEventDispatcher -> FunctionNormalizeDispatcher -> 
FunctionHookDispatcher ->
-    // FunctionOperationDispatcher
+    // TODO: Add FunctionHookDispatcher when needed
+    // The operation chain is:
+    // FunctionEventDispatcher -> FunctionNormalizeDispatcher -> 
FunctionOperationDispatcher
     FunctionOperationDispatcher functionOperationDispatcher =
         new FunctionOperationDispatcher(
             catalogManager, schemaOperationDispatcher, entityStore, 
idGenerator);
-    this.functionDispatcher =
+    FunctionNormalizeDispatcher functionNormalizeDispatcher =
         new FunctionNormalizeDispatcher(functionOperationDispatcher, 
catalogManager);
+    this.functionDispatcher = new FunctionEventDispatcher(eventBus, 
functionNormalizeDispatcher);
 
     // TODO: Add ViewHookDispatcher and ViewEventDispatcher when needed for 
view-specific hooks
     //  and event handling.
diff --git 
a/core/src/main/java/org/apache/gravitino/listener/FunctionEventDispatcher.java 
b/core/src/main/java/org/apache/gravitino/listener/FunctionEventDispatcher.java
new file mode 100644
index 0000000000..52eba85e04
--- /dev/null
+++ 
b/core/src/main/java/org/apache/gravitino/listener/FunctionEventDispatcher.java
@@ -0,0 +1,176 @@
+/*
+ * 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;
+
+import java.util.Arrays;
+import org.apache.gravitino.NameIdentifier;
+import org.apache.gravitino.Namespace;
+import org.apache.gravitino.catalog.FunctionDispatcher;
+import org.apache.gravitino.exceptions.FunctionAlreadyExistsException;
+import org.apache.gravitino.exceptions.NoSuchFunctionException;
+import org.apache.gravitino.exceptions.NoSuchSchemaException;
+import org.apache.gravitino.function.Function;
+import org.apache.gravitino.function.FunctionChange;
+import org.apache.gravitino.function.FunctionDefinition;
+import org.apache.gravitino.function.FunctionType;
+import org.apache.gravitino.listener.api.event.function.AlterFunctionEvent;
+import 
org.apache.gravitino.listener.api.event.function.AlterFunctionFailureEvent;
+import org.apache.gravitino.listener.api.event.function.AlterFunctionPreEvent;
+import org.apache.gravitino.listener.api.event.function.DropFunctionEvent;
+import 
org.apache.gravitino.listener.api.event.function.DropFunctionFailureEvent;
+import org.apache.gravitino.listener.api.event.function.DropFunctionPreEvent;
+import org.apache.gravitino.listener.api.event.function.GetFunctionEvent;
+import 
org.apache.gravitino.listener.api.event.function.GetFunctionFailureEvent;
+import org.apache.gravitino.listener.api.event.function.GetFunctionPreEvent;
+import org.apache.gravitino.listener.api.event.function.ListFunctionEvent;
+import 
org.apache.gravitino.listener.api.event.function.ListFunctionFailureEvent;
+import org.apache.gravitino.listener.api.event.function.ListFunctionInfosEvent;
+import org.apache.gravitino.listener.api.event.function.ListFunctionPreEvent;
+import org.apache.gravitino.listener.api.event.function.RegisterFunctionEvent;
+import 
org.apache.gravitino.listener.api.event.function.RegisterFunctionFailureEvent;
+import 
org.apache.gravitino.listener.api.event.function.RegisterFunctionPreEvent;
+import org.apache.gravitino.listener.api.info.FunctionInfo;
+import org.apache.gravitino.utils.PrincipalUtils;
+
+/**
+ * {@code FunctionEventDispatcher} is a decorator for {@link 
FunctionDispatcher} that not only
+ * delegates function operations to the underlying dispatcher but also 
dispatches corresponding
+ * events to an {@link EventBus} after each operation is completed.
+ */
+public class FunctionEventDispatcher implements FunctionDispatcher {
+
+  private final EventBus eventBus;
+  private final FunctionDispatcher dispatcher;
+
+  /**
+   * Constructs a FunctionEventDispatcher with a specified EventBus and 
FunctionDispatcher.
+   *
+   * @param eventBus The EventBus to which events will be dispatched.
+   * @param dispatcher The underlying {@link FunctionDispatcher} that will 
perform the actual
+   *     function operations.
+   */
+  public FunctionEventDispatcher(EventBus eventBus, FunctionDispatcher 
dispatcher) {
+    this.eventBus = eventBus;
+    this.dispatcher = dispatcher;
+  }
+
+  @Override
+  public NameIdentifier[] listFunctions(Namespace namespace) throws 
NoSuchSchemaException {
+    String user = PrincipalUtils.getCurrentUserName();
+    eventBus.dispatchEvent(new ListFunctionPreEvent(user, namespace));
+    try {
+      NameIdentifier[] nameIdentifiers = dispatcher.listFunctions(namespace);
+      eventBus.dispatchEvent(new ListFunctionEvent(user, namespace));
+      return nameIdentifiers;
+    } catch (Exception e) {
+      eventBus.dispatchEvent(new ListFunctionFailureEvent(user, namespace, e));
+      throw e;
+    }
+  }
+
+  @Override
+  public Function[] listFunctionInfos(Namespace namespace) throws 
NoSuchSchemaException {
+    String user = PrincipalUtils.getCurrentUserName();
+    eventBus.dispatchEvent(new ListFunctionPreEvent(user, namespace));
+    try {
+      Function[] functions = dispatcher.listFunctionInfos(namespace);
+      FunctionInfo[] functionInfos =
+          
Arrays.stream(functions).map(FunctionInfo::new).toArray(FunctionInfo[]::new);
+      eventBus.dispatchEvent(new ListFunctionInfosEvent(user, namespace, 
functionInfos));
+      return functions;
+    } catch (Exception e) {
+      eventBus.dispatchEvent(new ListFunctionFailureEvent(user, namespace, e));
+      throw e;
+    }
+  }
+
+  @Override
+  public Function getFunction(NameIdentifier ident) throws 
NoSuchFunctionException {
+    String user = PrincipalUtils.getCurrentUserName();
+    eventBus.dispatchEvent(new GetFunctionPreEvent(user, ident));
+    try {
+      Function function = dispatcher.getFunction(ident);
+      eventBus.dispatchEvent(new GetFunctionEvent(user, ident, new 
FunctionInfo(function)));
+      return function;
+    } catch (Exception e) {
+      eventBus.dispatchEvent(new GetFunctionFailureEvent(user, ident, e));
+      throw e;
+    }
+  }
+
+  @Override
+  public Function registerFunction(
+      NameIdentifier ident,
+      String comment,
+      FunctionType functionType,
+      boolean deterministic,
+      FunctionDefinition[] definitions)
+      throws NoSuchSchemaException, FunctionAlreadyExistsException {
+    String user = PrincipalUtils.getCurrentUserName();
+    FunctionInfo registerFunctionRequest =
+        new FunctionInfo(ident.name(), functionType, deterministic, comment, 
definitions, null);
+    eventBus.dispatchEvent(new RegisterFunctionPreEvent(user, ident, 
registerFunctionRequest));
+    try {
+      Function function =
+          dispatcher.registerFunction(ident, comment, functionType, 
deterministic, definitions);
+      eventBus.dispatchEvent(new RegisterFunctionEvent(user, ident, new 
FunctionInfo(function)));
+      return function;
+    } catch (Exception e) {
+      eventBus.dispatchEvent(
+          new RegisterFunctionFailureEvent(user, ident, e, 
registerFunctionRequest));
+      throw e;
+    }
+  }
+
+  @Override
+  public Function alterFunction(NameIdentifier ident, FunctionChange... 
changes)
+      throws NoSuchFunctionException, IllegalArgumentException {
+    String user = PrincipalUtils.getCurrentUserName();
+    eventBus.dispatchEvent(new AlterFunctionPreEvent(user, ident, changes));
+    try {
+      Function function = dispatcher.alterFunction(ident, changes);
+      eventBus.dispatchEvent(
+          new AlterFunctionEvent(user, ident, changes, new 
FunctionInfo(function)));
+      return function;
+    } catch (Exception e) {
+      eventBus.dispatchEvent(new AlterFunctionFailureEvent(user, ident, e, 
changes));
+      throw e;
+    }
+  }
+
+  @Override
+  public boolean dropFunction(NameIdentifier ident) {
+    String user = PrincipalUtils.getCurrentUserName();
+    eventBus.dispatchEvent(new DropFunctionPreEvent(user, ident));
+    try {
+      boolean isExists = dispatcher.dropFunction(ident);
+      eventBus.dispatchEvent(new DropFunctionEvent(user, ident, isExists));
+      return isExists;
+    } catch (Exception e) {
+      eventBus.dispatchEvent(new DropFunctionFailureEvent(user, ident, e));
+      throw e;
+    }
+  }
+
+  @Override
+  public boolean functionExists(NameIdentifier ident) {
+    return dispatcher.functionExists(ident);
+  }
+}
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 948c50caa2..97c0c9fcee 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
@@ -188,5 +188,13 @@ public enum OperationType {
   ASSOCIATE_POLICIES_FOR_METADATA_OBJECT,
   GET_POLICY_FOR_METADATA_OBJECT,
 
+  // Function operations
+  REGISTER_FUNCTION,
+  GET_FUNCTION,
+  ALTER_FUNCTION,
+  DROP_FUNCTION,
+  LIST_FUNCTION,
+  LIST_FUNCTION_INFOS,
+
   UNKNOWN,
 }
diff --git 
a/core/src/main/java/org/apache/gravitino/listener/api/event/function/AlterFunctionEvent.java
 
b/core/src/main/java/org/apache/gravitino/listener/api/event/function/AlterFunctionEvent.java
new file mode 100644
index 0000000000..e4e0418118
--- /dev/null
+++ 
b/core/src/main/java/org/apache/gravitino/listener/api/event/function/AlterFunctionEvent.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.function;
+
+import java.util.Arrays;
+import org.apache.gravitino.NameIdentifier;
+import org.apache.gravitino.annotation.DeveloperApi;
+import org.apache.gravitino.function.FunctionChange;
+import org.apache.gravitino.listener.api.event.OperationType;
+import org.apache.gravitino.listener.api.info.FunctionInfo;
+
+/** Represents an event fired when a function is successfully altered. */
+@DeveloperApi
+public final class AlterFunctionEvent extends FunctionEvent {
+  private final FunctionInfo updatedFunctionInfo;
+  private final FunctionChange[] functionChanges;
+
+  /**
+   * Constructs an instance of {@code AlterFunctionEvent}.
+   *
+   * @param user The username of the individual responsible for initiating the 
function alteration.
+   * @param identifier The unique identifier of the altered function.
+   * @param functionChanges An array of {@link FunctionChange} objects 
representing the specific
+   *     changes applied to the function.
+   * @param updatedFunctionInfo The post-alteration state of the function.
+   */
+  public AlterFunctionEvent(
+      String user,
+      NameIdentifier identifier,
+      FunctionChange[] functionChanges,
+      FunctionInfo updatedFunctionInfo) {
+    super(user, identifier);
+    this.functionChanges = Arrays.copyOf(functionChanges, 
functionChanges.length);
+    this.updatedFunctionInfo = updatedFunctionInfo;
+  }
+
+  /**
+   * Retrieves the updated state of the function after the successful 
alteration.
+   *
+   * @return A {@link FunctionInfo} instance encapsulating the details of the 
altered function.
+   */
+  public FunctionInfo updatedFunctionInfo() {
+    return updatedFunctionInfo;
+  }
+
+  /**
+   * Retrieves the specific changes that were made to the function during the 
alteration process.
+   *
+   * @return An array of {@link FunctionChange} objects detailing each 
modification applied to the
+   *     function.
+   */
+  public FunctionChange[] functionChanges() {
+    return Arrays.copyOf(functionChanges, functionChanges.length);
+  }
+
+  @Override
+  public OperationType operationType() {
+    return OperationType.ALTER_FUNCTION;
+  }
+}
diff --git 
a/core/src/main/java/org/apache/gravitino/listener/api/event/function/AlterFunctionFailureEvent.java
 
b/core/src/main/java/org/apache/gravitino/listener/api/event/function/AlterFunctionFailureEvent.java
new file mode 100644
index 0000000000..bc3c760d86
--- /dev/null
+++ 
b/core/src/main/java/org/apache/gravitino/listener/api/event/function/AlterFunctionFailureEvent.java
@@ -0,0 +1,67 @@
+/*
+ * 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.function;
+
+import java.util.Arrays;
+import org.apache.gravitino.NameIdentifier;
+import org.apache.gravitino.annotation.DeveloperApi;
+import org.apache.gravitino.function.FunctionChange;
+import org.apache.gravitino.listener.api.event.OperationType;
+
+/**
+ * Represents an event that is triggered when an attempt to alter a function 
fails due to an
+ * exception.
+ */
+@DeveloperApi
+public final class AlterFunctionFailureEvent extends FunctionFailureEvent {
+  private final FunctionChange[] functionChanges;
+
+  /**
+   * Constructs an {@code AlterFunctionFailureEvent} instance.
+   *
+   * @param user The user who initiated the function alteration operation.
+   * @param identifier The identifier of the function that was attempted to be 
altered.
+   * @param exception The exception that was thrown during the function 
alteration operation.
+   * @param functionChanges The changes that were attempted on the function.
+   */
+  public AlterFunctionFailureEvent(
+      String user,
+      NameIdentifier identifier,
+      Exception exception,
+      FunctionChange[] functionChanges) {
+    super(user, identifier, exception);
+    this.functionChanges = Arrays.copyOf(functionChanges, 
functionChanges.length);
+  }
+
+  /**
+   * Retrieves the changes that were attempted on the function.
+   *
+   * @return An array of {@link FunctionChange} objects representing the 
attempted modifications to
+   *     the function.
+   */
+  public FunctionChange[] functionChanges() {
+    return Arrays.copyOf(functionChanges, functionChanges.length);
+  }
+
+  @Override
+  public OperationType operationType() {
+    return OperationType.ALTER_FUNCTION;
+  }
+}
diff --git 
a/core/src/main/java/org/apache/gravitino/listener/api/event/function/AlterFunctionPreEvent.java
 
b/core/src/main/java/org/apache/gravitino/listener/api/event/function/AlterFunctionPreEvent.java
new file mode 100644
index 0000000000..d599f222d0
--- /dev/null
+++ 
b/core/src/main/java/org/apache/gravitino/listener/api/event/function/AlterFunctionPreEvent.java
@@ -0,0 +1,53 @@
+/*
+ * 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.function;
+
+import java.util.Arrays;
+import org.apache.gravitino.NameIdentifier;
+import org.apache.gravitino.annotation.DeveloperApi;
+import org.apache.gravitino.function.FunctionChange;
+import org.apache.gravitino.listener.api.event.OperationType;
+
+/** Represents an event triggered before altering a function. */
+@DeveloperApi
+public class AlterFunctionPreEvent extends FunctionPreEvent {
+  private final FunctionChange[] functionChanges;
+
+  public AlterFunctionPreEvent(
+      String user, NameIdentifier identifier, FunctionChange[] 
functionChanges) {
+    super(user, identifier);
+    this.functionChanges = Arrays.copyOf(functionChanges, 
functionChanges.length);
+  }
+
+  /**
+   * Retrieves the specific changes that were made to the function during the 
alteration process.
+   *
+   * @return An array of {@link FunctionChange} objects detailing each 
modification applied to the
+   *     function.
+   */
+  public FunctionChange[] functionChanges() {
+    return Arrays.copyOf(functionChanges, functionChanges.length);
+  }
+
+  @Override
+  public OperationType operationType() {
+    return OperationType.ALTER_FUNCTION;
+  }
+}
diff --git 
a/core/src/main/java/org/apache/gravitino/listener/api/event/function/DropFunctionEvent.java
 
b/core/src/main/java/org/apache/gravitino/listener/api/event/function/DropFunctionEvent.java
new file mode 100644
index 0000000000..7ab1f63ab1
--- /dev/null
+++ 
b/core/src/main/java/org/apache/gravitino/listener/api/event/function/DropFunctionEvent.java
@@ -0,0 +1,58 @@
+/*
+ * 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.function;
+
+import org.apache.gravitino.NameIdentifier;
+import org.apache.gravitino.annotation.DeveloperApi;
+import org.apache.gravitino.listener.api.event.OperationType;
+
+/** Represents an event that is generated after a function is successfully 
dropped. */
+@DeveloperApi
+public final class DropFunctionEvent extends FunctionEvent {
+  private final boolean isExists;
+
+  /**
+   * Constructs a new {@code DropFunctionEvent} instance.
+   *
+   * @param user The user who initiated the drop function operation.
+   * @param identifier The identifier of the function that was attempted to be 
dropped.
+   * @param isExists A boolean flag indicating whether the function existed at 
the time of the drop
+   *     operation.
+   */
+  public DropFunctionEvent(String user, NameIdentifier identifier, boolean 
isExists) {
+    super(user, identifier);
+    this.isExists = isExists;
+  }
+
+  /**
+   * Retrieves the existence status of the function at the time of the drop 
operation.
+   *
+   * @return A boolean value indicating whether the function existed. {@code 
true} if the function
+   *     existed, otherwise {@code false}.
+   */
+  public boolean isExists() {
+    return isExists;
+  }
+
+  @Override
+  public OperationType operationType() {
+    return OperationType.DROP_FUNCTION;
+  }
+}
diff --git 
a/core/src/main/java/org/apache/gravitino/listener/api/event/function/DropFunctionFailureEvent.java
 
b/core/src/main/java/org/apache/gravitino/listener/api/event/function/DropFunctionFailureEvent.java
new file mode 100644
index 0000000000..2fa4694107
--- /dev/null
+++ 
b/core/src/main/java/org/apache/gravitino/listener/api/event/function/DropFunctionFailureEvent.java
@@ -0,0 +1,47 @@
+/*
+ * 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.function;
+
+import org.apache.gravitino.NameIdentifier;
+import org.apache.gravitino.annotation.DeveloperApi;
+import org.apache.gravitino.listener.api.event.OperationType;
+
+/**
+ * Represents an event that is generated when an attempt to drop a function 
fails due to an
+ * exception.
+ */
+@DeveloperApi
+public final class DropFunctionFailureEvent extends FunctionFailureEvent {
+  /**
+   * Constructs a new {@code DropFunctionFailureEvent} instance.
+   *
+   * @param user The user who initiated the drop function operation.
+   * @param identifier The identifier of the function that the operation 
attempted to drop.
+   * @param exception The exception that was thrown during the drop function 
operation.
+   */
+  public DropFunctionFailureEvent(String user, NameIdentifier identifier, 
Exception exception) {
+    super(user, identifier, exception);
+  }
+
+  @Override
+  public OperationType operationType() {
+    return OperationType.DROP_FUNCTION;
+  }
+}
diff --git 
a/core/src/main/java/org/apache/gravitino/listener/api/event/function/DropFunctionPreEvent.java
 
b/core/src/main/java/org/apache/gravitino/listener/api/event/function/DropFunctionPreEvent.java
new file mode 100644
index 0000000000..863635a157
--- /dev/null
+++ 
b/core/src/main/java/org/apache/gravitino/listener/api/event/function/DropFunctionPreEvent.java
@@ -0,0 +1,37 @@
+/*
+ * 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.function;
+
+import org.apache.gravitino.NameIdentifier;
+import org.apache.gravitino.annotation.DeveloperApi;
+import org.apache.gravitino.listener.api.event.OperationType;
+
+/** Represents an event that is triggered before dropping a function. */
+@DeveloperApi
+public class DropFunctionPreEvent extends FunctionPreEvent {
+  public DropFunctionPreEvent(String user, NameIdentifier identifier) {
+    super(user, identifier);
+  }
+
+  @Override
+  public OperationType operationType() {
+    return OperationType.DROP_FUNCTION;
+  }
+}
diff --git 
a/core/src/main/java/org/apache/gravitino/listener/api/event/function/FunctionEvent.java
 
b/core/src/main/java/org/apache/gravitino/listener/api/event/function/FunctionEvent.java
new file mode 100644
index 0000000000..5bde5e981b
--- /dev/null
+++ 
b/core/src/main/java/org/apache/gravitino/listener/api/event/function/FunctionEvent.java
@@ -0,0 +1,48 @@
+/*
+ * 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.function;
+
+import org.apache.gravitino.NameIdentifier;
+import org.apache.gravitino.annotation.DeveloperApi;
+import org.apache.gravitino.listener.api.event.Event;
+import org.apache.gravitino.listener.api.event.OperationStatus;
+
+/**
+ * Represents an abstract base class for events related to function 
operations. This class extends
+ * {@link Event} to provide a more specific context involving operations on 
functions, such as
+ * registration, deletion, or modification.
+ */
+@DeveloperApi
+public abstract class FunctionEvent extends Event {
+  /**
+   * Constructs a new {@code FunctionEvent} with the specified user and 
function identifier.
+   *
+   * @param user The user responsible for triggering the function operation.
+   * @param identifier The identifier of the function involved in the 
operation.
+   */
+  protected FunctionEvent(String user, NameIdentifier identifier) {
+    super(user, identifier);
+  }
+
+  @Override
+  public OperationStatus operationStatus() {
+    return OperationStatus.SUCCESS;
+  }
+}
diff --git 
a/core/src/main/java/org/apache/gravitino/listener/api/event/function/FunctionFailureEvent.java
 
b/core/src/main/java/org/apache/gravitino/listener/api/event/function/FunctionFailureEvent.java
new file mode 100644
index 0000000000..dfeae48922
--- /dev/null
+++ 
b/core/src/main/java/org/apache/gravitino/listener/api/event/function/FunctionFailureEvent.java
@@ -0,0 +1,42 @@
+/*
+ * 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.function;
+
+import org.apache.gravitino.NameIdentifier;
+import org.apache.gravitino.annotation.DeveloperApi;
+import org.apache.gravitino.listener.api.event.FailureEvent;
+
+/**
+ * An abstract class representing events that are triggered when a function 
operation fails due to
+ * an exception.
+ */
+@DeveloperApi
+public abstract class FunctionFailureEvent extends FailureEvent {
+  /**
+   * Constructs a new {@code FunctionFailureEvent} instance.
+   *
+   * @param user The user associated with the failed function operation.
+   * @param identifier The identifier of the function involved in the failed 
operation.
+   * @param exception The exception that was thrown during the function 
operation.
+   */
+  protected FunctionFailureEvent(String user, NameIdentifier identifier, 
Exception exception) {
+    super(user, identifier, exception);
+  }
+}
diff --git 
a/core/src/main/java/org/apache/gravitino/listener/api/event/function/FunctionPreEvent.java
 
b/core/src/main/java/org/apache/gravitino/listener/api/event/function/FunctionPreEvent.java
new file mode 100644
index 0000000000..76bef1b52d
--- /dev/null
+++ 
b/core/src/main/java/org/apache/gravitino/listener/api/event/function/FunctionPreEvent.java
@@ -0,0 +1,32 @@
+/*
+ * 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.function;
+
+import org.apache.gravitino.NameIdentifier;
+import org.apache.gravitino.annotation.DeveloperApi;
+import org.apache.gravitino.listener.api.event.PreEvent;
+
+/** Represents a pre-event for function operations. */
+@DeveloperApi
+public abstract class FunctionPreEvent extends PreEvent {
+  protected FunctionPreEvent(String user, NameIdentifier identifier) {
+    super(user, identifier);
+  }
+}
diff --git 
a/core/src/main/java/org/apache/gravitino/listener/api/event/function/GetFunctionEvent.java
 
b/core/src/main/java/org/apache/gravitino/listener/api/event/function/GetFunctionEvent.java
new file mode 100644
index 0000000000..1ae131c839
--- /dev/null
+++ 
b/core/src/main/java/org/apache/gravitino/listener/api/event/function/GetFunctionEvent.java
@@ -0,0 +1,58 @@
+/*
+ * 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.function;
+
+import org.apache.gravitino.NameIdentifier;
+import org.apache.gravitino.annotation.DeveloperApi;
+import org.apache.gravitino.listener.api.event.OperationType;
+import org.apache.gravitino.listener.api.info.FunctionInfo;
+
+/** Represents an event triggered upon the successful retrieval of a function. 
*/
+@DeveloperApi
+public final class GetFunctionEvent extends FunctionEvent {
+  private final FunctionInfo functionInfo;
+
+  /**
+   * Constructs an instance of {@code GetFunctionEvent}.
+   *
+   * @param user The username of the individual who initiated the function 
retrieval.
+   * @param identifier The unique identifier of the function that was 
retrieved.
+   * @param functionInfo The state of the function post-retrieval.
+   */
+  public GetFunctionEvent(String user, NameIdentifier identifier, FunctionInfo 
functionInfo) {
+    super(user, identifier);
+    this.functionInfo = functionInfo;
+  }
+
+  /**
+   * Retrieves the state of the function as it was made available to the user 
after successful
+   * retrieval.
+   *
+   * @return A {@link FunctionInfo} instance encapsulating the details of the 
function as retrieved.
+   */
+  public FunctionInfo functionInfo() {
+    return functionInfo;
+  }
+
+  @Override
+  public OperationType operationType() {
+    return OperationType.GET_FUNCTION;
+  }
+}
diff --git 
a/core/src/main/java/org/apache/gravitino/listener/api/event/function/GetFunctionFailureEvent.java
 
b/core/src/main/java/org/apache/gravitino/listener/api/event/function/GetFunctionFailureEvent.java
new file mode 100644
index 0000000000..d5261a8550
--- /dev/null
+++ 
b/core/src/main/java/org/apache/gravitino/listener/api/event/function/GetFunctionFailureEvent.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.function;
+
+import org.apache.gravitino.NameIdentifier;
+import org.apache.gravitino.annotation.DeveloperApi;
+import org.apache.gravitino.listener.api.event.OperationType;
+
+/** Represents an event that occurs when an attempt to get a function fails 
due to an exception. */
+@DeveloperApi
+public final class GetFunctionFailureEvent extends FunctionFailureEvent {
+  /**
+   * Constructs a {@code GetFunctionFailureEvent} instance.
+   *
+   * @param user The user who initiated the function retrieval operation.
+   * @param identifier The identifier of the function that the retrieval 
attempt was made for.
+   * @param exception The exception that was thrown during the function 
retrieval operation.
+   */
+  public GetFunctionFailureEvent(String user, NameIdentifier identifier, 
Exception exception) {
+    super(user, identifier, exception);
+  }
+
+  @Override
+  public OperationType operationType() {
+    return OperationType.GET_FUNCTION;
+  }
+}
diff --git 
a/core/src/main/java/org/apache/gravitino/listener/api/event/function/GetFunctionPreEvent.java
 
b/core/src/main/java/org/apache/gravitino/listener/api/event/function/GetFunctionPreEvent.java
new file mode 100644
index 0000000000..ed33f91fb2
--- /dev/null
+++ 
b/core/src/main/java/org/apache/gravitino/listener/api/event/function/GetFunctionPreEvent.java
@@ -0,0 +1,37 @@
+/*
+ * 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.function;
+
+import org.apache.gravitino.NameIdentifier;
+import org.apache.gravitino.annotation.DeveloperApi;
+import org.apache.gravitino.listener.api.event.OperationType;
+
+/** Represents an event triggered before getting a function. */
+@DeveloperApi
+public class GetFunctionPreEvent extends FunctionPreEvent {
+  public GetFunctionPreEvent(String user, NameIdentifier identifier) {
+    super(user, identifier);
+  }
+
+  @Override
+  public OperationType operationType() {
+    return OperationType.GET_FUNCTION;
+  }
+}
diff --git 
a/core/src/main/java/org/apache/gravitino/listener/api/event/function/ListFunctionEvent.java
 
b/core/src/main/java/org/apache/gravitino/listener/api/event/function/ListFunctionEvent.java
new file mode 100644
index 0000000000..5d2853bcef
--- /dev/null
+++ 
b/core/src/main/java/org/apache/gravitino/listener/api/event/function/ListFunctionEvent.java
@@ -0,0 +1,59 @@
+/*
+ * 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.function;
+
+import org.apache.gravitino.NameIdentifier;
+import org.apache.gravitino.Namespace;
+import org.apache.gravitino.annotation.DeveloperApi;
+import org.apache.gravitino.listener.api.event.OperationType;
+
+/**
+ * Represents an event that is triggered upon the successful listing of 
functions within a
+ * namespace.
+ */
+@DeveloperApi
+public final class ListFunctionEvent extends FunctionEvent {
+  private final Namespace namespace;
+
+  /**
+   * Constructs an instance of {@code ListFunctionEvent}.
+   *
+   * @param user The username of the individual who initiated the function 
listing.
+   * @param namespace The namespace from which functions were listed.
+   */
+  public ListFunctionEvent(String user, Namespace namespace) {
+    super(user, NameIdentifier.of(namespace.levels()));
+    this.namespace = namespace;
+  }
+
+  /**
+   * Provides the namespace associated with this event.
+   *
+   * @return A {@link Namespace} instance from which functions were listed.
+   */
+  public Namespace namespace() {
+    return namespace;
+  }
+
+  @Override
+  public OperationType operationType() {
+    return OperationType.LIST_FUNCTION;
+  }
+}
diff --git 
a/core/src/main/java/org/apache/gravitino/listener/api/event/function/ListFunctionFailureEvent.java
 
b/core/src/main/java/org/apache/gravitino/listener/api/event/function/ListFunctionFailureEvent.java
new file mode 100644
index 0000000000..6a645c5fca
--- /dev/null
+++ 
b/core/src/main/java/org/apache/gravitino/listener/api/event/function/ListFunctionFailureEvent.java
@@ -0,0 +1,60 @@
+/*
+ * 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.function;
+
+import org.apache.gravitino.NameIdentifier;
+import org.apache.gravitino.Namespace;
+import org.apache.gravitino.annotation.DeveloperApi;
+import org.apache.gravitino.listener.api.event.OperationType;
+
+/**
+ * Represents an event that is triggered when an attempt to list functions 
within a namespace fails
+ * due to an exception.
+ */
+@DeveloperApi
+public final class ListFunctionFailureEvent extends FunctionFailureEvent {
+  private final Namespace namespace;
+
+  /**
+   * Constructs a {@code ListFunctionFailureEvent} instance.
+   *
+   * @param user The username of the individual who initiated the operation to 
list functions.
+   * @param namespace The namespace for which the function listing was 
attempted.
+   * @param exception The exception encountered during the attempt to list 
functions.
+   */
+  public ListFunctionFailureEvent(String user, Namespace namespace, Exception 
exception) {
+    super(user, NameIdentifier.of(namespace.levels()), exception);
+    this.namespace = namespace;
+  }
+
+  /**
+   * Retrieves the namespace associated with this failure event.
+   *
+   * @return A {@link Namespace} instance for which the function listing was 
attempted.
+   */
+  public Namespace namespace() {
+    return namespace;
+  }
+
+  @Override
+  public OperationType operationType() {
+    return OperationType.LIST_FUNCTION;
+  }
+}
diff --git 
a/core/src/main/java/org/apache/gravitino/listener/api/event/function/ListFunctionInfosEvent.java
 
b/core/src/main/java/org/apache/gravitino/listener/api/event/function/ListFunctionInfosEvent.java
new file mode 100644
index 0000000000..be5d30a21f
--- /dev/null
+++ 
b/core/src/main/java/org/apache/gravitino/listener/api/event/function/ListFunctionInfosEvent.java
@@ -0,0 +1,72 @@
+/*
+ * 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.function;
+
+import org.apache.gravitino.NameIdentifier;
+import org.apache.gravitino.Namespace;
+import org.apache.gravitino.annotation.DeveloperApi;
+import org.apache.gravitino.listener.api.event.OperationType;
+import org.apache.gravitino.listener.api.info.FunctionInfo;
+
+/**
+ * Represents an event that is triggered upon the successful listing of 
function infos within a
+ * namespace.
+ */
+@DeveloperApi
+public final class ListFunctionInfosEvent extends FunctionEvent {
+  private final Namespace namespace;
+  private final FunctionInfo[] functionInfos;
+
+  /**
+   * Constructs an instance of {@code ListFunctionInfosEvent}.
+   *
+   * @param user The username of the individual who initiated the function 
info listing.
+   * @param namespace The namespace from which function infos were listed.
+   * @param functionInfos The function infos that were listed.
+   */
+  public ListFunctionInfosEvent(String user, Namespace namespace, 
FunctionInfo[] functionInfos) {
+    super(user, NameIdentifier.of(namespace.levels()));
+    this.namespace = namespace;
+    this.functionInfos = functionInfos;
+  }
+
+  /**
+   * Provides the namespace associated with this event.
+   *
+   * @return A {@link Namespace} instance from which function infos were 
listed.
+   */
+  public Namespace namespace() {
+    return namespace;
+  }
+
+  /**
+   * Provides the function infos associated with this event.
+   *
+   * @return An array of {@link FunctionInfo} instances that were listed.
+   */
+  public FunctionInfo[] functionInfos() {
+    return functionInfos;
+  }
+
+  @Override
+  public OperationType operationType() {
+    return OperationType.LIST_FUNCTION_INFOS;
+  }
+}
diff --git 
a/core/src/main/java/org/apache/gravitino/listener/api/event/function/ListFunctionPreEvent.java
 
b/core/src/main/java/org/apache/gravitino/listener/api/event/function/ListFunctionPreEvent.java
new file mode 100644
index 0000000000..89d221ed67
--- /dev/null
+++ 
b/core/src/main/java/org/apache/gravitino/listener/api/event/function/ListFunctionPreEvent.java
@@ -0,0 +1,50 @@
+/*
+ * 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.function;
+
+import org.apache.gravitino.NameIdentifier;
+import org.apache.gravitino.Namespace;
+import org.apache.gravitino.annotation.DeveloperApi;
+import org.apache.gravitino.listener.api.event.OperationType;
+
+/** Represents an event that is triggered before listing functions within a 
namespace. */
+@DeveloperApi
+public class ListFunctionPreEvent extends FunctionPreEvent {
+  private final Namespace namespace;
+
+  public ListFunctionPreEvent(String user, Namespace namespace) {
+    super(user, NameIdentifier.of(namespace.levels()));
+    this.namespace = namespace;
+  }
+
+  /**
+   * Provides the namespace associated with this event.
+   *
+   * @return A {@link Namespace} instance from which functions were listed.
+   */
+  public Namespace namespace() {
+    return namespace;
+  }
+
+  @Override
+  public OperationType operationType() {
+    return OperationType.LIST_FUNCTION;
+  }
+}
diff --git 
a/core/src/main/java/org/apache/gravitino/listener/api/event/function/RegisterFunctionEvent.java
 
b/core/src/main/java/org/apache/gravitino/listener/api/event/function/RegisterFunctionEvent.java
new file mode 100644
index 0000000000..291eac493f
--- /dev/null
+++ 
b/core/src/main/java/org/apache/gravitino/listener/api/event/function/RegisterFunctionEvent.java
@@ -0,0 +1,59 @@
+/*
+ * 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.function;
+
+import org.apache.gravitino.NameIdentifier;
+import org.apache.gravitino.annotation.DeveloperApi;
+import org.apache.gravitino.listener.api.event.OperationType;
+import org.apache.gravitino.listener.api.info.FunctionInfo;
+
+/** Represents an event triggered upon the successful registration of a 
function. */
+@DeveloperApi
+public final class RegisterFunctionEvent extends FunctionEvent {
+  private final FunctionInfo registeredFunctionInfo;
+
+  /**
+   * Constructs an instance of {@code RegisterFunctionEvent}.
+   *
+   * @param user The username of the individual who initiated the function 
registration.
+   * @param identifier The unique identifier of the function that was 
registered.
+   * @param registeredFunctionInfo The final state of the function 
post-registration.
+   */
+  public RegisterFunctionEvent(
+      String user, NameIdentifier identifier, FunctionInfo 
registeredFunctionInfo) {
+    super(user, identifier);
+    this.registeredFunctionInfo = registeredFunctionInfo;
+  }
+
+  /**
+   * Retrieves the final state of the function after successful registration.
+   *
+   * @return A {@link FunctionInfo} instance encapsulating the details of the 
newly registered
+   *     function.
+   */
+  public FunctionInfo registeredFunctionInfo() {
+    return registeredFunctionInfo;
+  }
+
+  @Override
+  public OperationType operationType() {
+    return OperationType.REGISTER_FUNCTION;
+  }
+}
diff --git 
a/core/src/main/java/org/apache/gravitino/listener/api/event/function/RegisterFunctionFailureEvent.java
 
b/core/src/main/java/org/apache/gravitino/listener/api/event/function/RegisterFunctionFailureEvent.java
new file mode 100644
index 0000000000..0a29a734ae
--- /dev/null
+++ 
b/core/src/main/java/org/apache/gravitino/listener/api/event/function/RegisterFunctionFailureEvent.java
@@ -0,0 +1,67 @@
+/*
+ * 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.function;
+
+import org.apache.gravitino.NameIdentifier;
+import org.apache.gravitino.annotation.DeveloperApi;
+import org.apache.gravitino.listener.api.event.OperationType;
+import org.apache.gravitino.listener.api.info.FunctionInfo;
+
+/**
+ * Represents an event that is generated when an attempt to register a 
function fails due to an
+ * exception.
+ */
+@DeveloperApi
+public final class RegisterFunctionFailureEvent extends FunctionFailureEvent {
+  private final FunctionInfo registerFunctionRequest;
+
+  /**
+   * Constructs a {@code RegisterFunctionFailureEvent} instance.
+   *
+   * @param user The user who initiated the function registration operation.
+   * @param identifier The identifier of the function that was attempted to be 
registered.
+   * @param exception The exception that was thrown during the function 
registration operation.
+   * @param registerFunctionRequest The original request information used to 
attempt to register the
+   *     function.
+   */
+  public RegisterFunctionFailureEvent(
+      String user,
+      NameIdentifier identifier,
+      Exception exception,
+      FunctionInfo registerFunctionRequest) {
+    super(user, identifier, exception);
+    this.registerFunctionRequest = registerFunctionRequest;
+  }
+
+  /**
+   * Retrieves the original request information for the attempted function 
registration.
+   *
+   * @return The {@link FunctionInfo} instance representing the request 
information for the failed
+   *     function registration attempt.
+   */
+  public FunctionInfo registerFunctionRequest() {
+    return registerFunctionRequest;
+  }
+
+  @Override
+  public OperationType operationType() {
+    return OperationType.REGISTER_FUNCTION;
+  }
+}
diff --git 
a/core/src/main/java/org/apache/gravitino/listener/api/event/function/RegisterFunctionPreEvent.java
 
b/core/src/main/java/org/apache/gravitino/listener/api/event/function/RegisterFunctionPreEvent.java
new file mode 100644
index 0000000000..fd84cda7bb
--- /dev/null
+++ 
b/core/src/main/java/org/apache/gravitino/listener/api/event/function/RegisterFunctionPreEvent.java
@@ -0,0 +1,52 @@
+/*
+ * 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.function;
+
+import org.apache.gravitino.NameIdentifier;
+import org.apache.gravitino.annotation.DeveloperApi;
+import org.apache.gravitino.listener.api.event.OperationType;
+import org.apache.gravitino.listener.api.info.FunctionInfo;
+
+/** Represents an event triggered before registering a function. */
+@DeveloperApi
+public class RegisterFunctionPreEvent extends FunctionPreEvent {
+  private final FunctionInfo registerFunctionRequest;
+
+  public RegisterFunctionPreEvent(
+      String user, NameIdentifier identifier, FunctionInfo 
registerFunctionRequest) {
+    super(user, identifier);
+    this.registerFunctionRequest = registerFunctionRequest;
+  }
+
+  /**
+   * Retrieves the register function request.
+   *
+   * @return A {@link FunctionInfo} instance encapsulating the details of the 
register function
+   *     request.
+   */
+  public FunctionInfo registerFunctionRequest() {
+    return registerFunctionRequest;
+  }
+
+  @Override
+  public OperationType operationType() {
+    return OperationType.REGISTER_FUNCTION;
+  }
+}
diff --git 
a/core/src/main/java/org/apache/gravitino/listener/api/info/FunctionInfo.java 
b/core/src/main/java/org/apache/gravitino/listener/api/info/FunctionInfo.java
new file mode 100644
index 0000000000..0c09a6e722
--- /dev/null
+++ 
b/core/src/main/java/org/apache/gravitino/listener/api/info/FunctionInfo.java
@@ -0,0 +1,141 @@
+/*
+ * 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.info;
+
+import java.util.Arrays;
+import javax.annotation.Nullable;
+import org.apache.gravitino.Audit;
+import org.apache.gravitino.annotation.DeveloperApi;
+import org.apache.gravitino.function.Function;
+import org.apache.gravitino.function.FunctionDefinition;
+import org.apache.gravitino.function.FunctionType;
+
+/**
+ * FunctionInfo exposes function 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 final class FunctionInfo {
+  private final String name;
+  private final FunctionType functionType;
+  private final boolean deterministic;
+  @Nullable private final String comment;
+  private final FunctionDefinition[] definitions;
+  @Nullable private final Audit auditInfo;
+
+  /**
+   * Constructs a FunctionInfo object from a Function instance.
+   *
+   * @param function The source Function instance.
+   */
+  public FunctionInfo(Function function) {
+    this(
+        function.name(),
+        function.functionType(),
+        function.deterministic(),
+        function.comment(),
+        function.definitions(),
+        function.auditInfo());
+  }
+
+  /**
+   * Constructs a FunctionInfo object with specified details.
+   *
+   * @param name Name of the function.
+   * @param functionType The function type (SCALAR, AGGREGATE, or TABLE).
+   * @param deterministic Whether the function is deterministic.
+   * @param comment Optional comment about the function.
+   * @param definitions The function definitions.
+   * @param auditInfo Optional audit information.
+   */
+  public FunctionInfo(
+      String name,
+      FunctionType functionType,
+      boolean deterministic,
+      String comment,
+      FunctionDefinition[] definitions,
+      Audit auditInfo) {
+    this.name = name;
+    this.functionType = functionType;
+    this.deterministic = deterministic;
+    this.comment = comment;
+    this.definitions =
+        definitions == null
+            ? new FunctionDefinition[0]
+            : Arrays.copyOf(definitions, definitions.length);
+    this.auditInfo = auditInfo;
+  }
+
+  /**
+   * Returns the name of the function.
+   *
+   * @return Function name.
+   */
+  public String name() {
+    return name;
+  }
+
+  /**
+   * Returns the function type.
+   *
+   * @return The function type.
+   */
+  public FunctionType functionType() {
+    return functionType;
+  }
+
+  /**
+   * Returns whether the function is deterministic.
+   *
+   * @return True if the function is deterministic.
+   */
+  public boolean deterministic() {
+    return deterministic;
+  }
+
+  /**
+   * Returns the comment of the function.
+   *
+   * @return Function comment, or {@code null} if not available.
+   */
+  @Nullable
+  public String comment() {
+    return comment;
+  }
+
+  /**
+   * Returns the definitions of the function.
+   *
+   * @return Array of function definitions.
+   */
+  public FunctionDefinition[] definitions() {
+    return Arrays.copyOf(definitions, definitions.length);
+  }
+
+  /**
+   * Returns the audit information for the function.
+   *
+   * @return Audit information, or {@code null} if not available.
+   */
+  @Nullable
+  public Audit auditInfo() {
+    return auditInfo;
+  }
+}
diff --git 
a/core/src/test/java/org/apache/gravitino/listener/api/event/TestFunctionEvent.java
 
b/core/src/test/java/org/apache/gravitino/listener/api/event/TestFunctionEvent.java
new file mode 100644
index 0000000000..b1a2455aa7
--- /dev/null
+++ 
b/core/src/test/java/org/apache/gravitino/listener/api/event/TestFunctionEvent.java
@@ -0,0 +1,360 @@
+/*
+ * 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 static org.mockito.Mockito.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.util.Arrays;
+import org.apache.gravitino.NameIdentifier;
+import org.apache.gravitino.Namespace;
+import org.apache.gravitino.catalog.FunctionDispatcher;
+import org.apache.gravitino.exceptions.GravitinoRuntimeException;
+import org.apache.gravitino.function.Function;
+import org.apache.gravitino.function.FunctionChange;
+import org.apache.gravitino.function.FunctionDefinition;
+import org.apache.gravitino.function.FunctionType;
+import org.apache.gravitino.listener.DummyEventListener;
+import org.apache.gravitino.listener.EventBus;
+import org.apache.gravitino.listener.FunctionEventDispatcher;
+import org.apache.gravitino.listener.api.event.function.AlterFunctionEvent;
+import 
org.apache.gravitino.listener.api.event.function.AlterFunctionFailureEvent;
+import org.apache.gravitino.listener.api.event.function.AlterFunctionPreEvent;
+import org.apache.gravitino.listener.api.event.function.DropFunctionEvent;
+import 
org.apache.gravitino.listener.api.event.function.DropFunctionFailureEvent;
+import org.apache.gravitino.listener.api.event.function.DropFunctionPreEvent;
+import org.apache.gravitino.listener.api.event.function.GetFunctionEvent;
+import 
org.apache.gravitino.listener.api.event.function.GetFunctionFailureEvent;
+import org.apache.gravitino.listener.api.event.function.GetFunctionPreEvent;
+import org.apache.gravitino.listener.api.event.function.ListFunctionEvent;
+import 
org.apache.gravitino.listener.api.event.function.ListFunctionFailureEvent;
+import org.apache.gravitino.listener.api.event.function.ListFunctionInfosEvent;
+import org.apache.gravitino.listener.api.event.function.ListFunctionPreEvent;
+import org.apache.gravitino.listener.api.event.function.RegisterFunctionEvent;
+import 
org.apache.gravitino.listener.api.event.function.RegisterFunctionFailureEvent;
+import 
org.apache.gravitino.listener.api.event.function.RegisterFunctionPreEvent;
+import org.apache.gravitino.listener.api.info.FunctionInfo;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestInstance;
+import org.junit.jupiter.api.TestInstance.Lifecycle;
+
+@TestInstance(Lifecycle.PER_CLASS)
+public class TestFunctionEvent {
+  private FunctionEventDispatcher dispatcher;
+  private FunctionEventDispatcher failureDispatcher;
+  private DummyEventListener dummyEventListener;
+  private Function function;
+
+  @BeforeAll
+  void init() {
+    this.function = mockFunction();
+    this.dummyEventListener = new DummyEventListener();
+    EventBus eventBus = new EventBus(Arrays.asList(dummyEventListener));
+    FunctionDispatcher functionDispatcher = mockFunctionDispatcher();
+    this.dispatcher = new FunctionEventDispatcher(eventBus, 
functionDispatcher);
+    FunctionDispatcher functionExceptionDispatcher = 
mockExceptionFunctionDispatcher();
+    this.failureDispatcher = new FunctionEventDispatcher(eventBus, 
functionExceptionDispatcher);
+  }
+
+  @Test
+  void testRegisterFunctionEvent() {
+    NameIdentifier identifier = NameIdentifier.of("metalake", "catalog", 
"schema", "func");
+    dispatcher.registerFunction(
+        identifier,
+        function.comment(),
+        function.functionType(),
+        function.deterministic(),
+        function.definitions());
+
+    Event event = dummyEventListener.popPostEvent();
+    Assertions.assertEquals(identifier, event.identifier());
+    Assertions.assertEquals(RegisterFunctionEvent.class, event.getClass());
+    FunctionInfo functionInfo = ((RegisterFunctionEvent) 
event).registeredFunctionInfo();
+    checkFunctionInfo(functionInfo, function);
+    Assertions.assertEquals(OperationType.REGISTER_FUNCTION, 
event.operationType());
+    Assertions.assertEquals(OperationStatus.SUCCESS, event.operationStatus());
+
+    PreEvent preEvent = dummyEventListener.popPreEvent();
+    Assertions.assertEquals(identifier, preEvent.identifier());
+    Assertions.assertEquals(RegisterFunctionPreEvent.class, 
preEvent.getClass());
+    FunctionInfo requestInfo = ((RegisterFunctionPreEvent) 
preEvent).registerFunctionRequest();
+    Assertions.assertEquals(function.functionType(), 
requestInfo.functionType());
+    Assertions.assertEquals(function.deterministic(), 
requestInfo.deterministic());
+    Assertions.assertEquals(OperationType.REGISTER_FUNCTION, 
preEvent.operationType());
+    Assertions.assertEquals(OperationStatus.UNPROCESSED, 
preEvent.operationStatus());
+  }
+
+  @Test
+  void testGetFunctionEvent() {
+    NameIdentifier identifier = NameIdentifier.of("metalake", "catalog", 
"schema", "func");
+    dispatcher.getFunction(identifier);
+
+    Event event = dummyEventListener.popPostEvent();
+    Assertions.assertEquals(identifier, event.identifier());
+    Assertions.assertEquals(GetFunctionEvent.class, event.getClass());
+    FunctionInfo functionInfo = ((GetFunctionEvent) event).functionInfo();
+    checkFunctionInfo(functionInfo, function);
+    Assertions.assertEquals(OperationType.GET_FUNCTION, event.operationType());
+    Assertions.assertEquals(OperationStatus.SUCCESS, event.operationStatus());
+
+    PreEvent preEvent = dummyEventListener.popPreEvent();
+    Assertions.assertEquals(identifier, preEvent.identifier());
+    Assertions.assertEquals(GetFunctionPreEvent.class, preEvent.getClass());
+    Assertions.assertEquals(OperationType.GET_FUNCTION, 
preEvent.operationType());
+    Assertions.assertEquals(OperationStatus.UNPROCESSED, 
preEvent.operationStatus());
+  }
+
+  @Test
+  void testAlterFunctionEvent() {
+    NameIdentifier identifier = NameIdentifier.of("metalake", "catalog", 
"schema", "func");
+    FunctionChange change = FunctionChange.updateComment("new comment");
+    dispatcher.alterFunction(identifier, change);
+
+    Event event = dummyEventListener.popPostEvent();
+    Assertions.assertEquals(identifier, event.identifier());
+    Assertions.assertEquals(AlterFunctionEvent.class, event.getClass());
+    FunctionInfo functionInfo = ((AlterFunctionEvent) 
event).updatedFunctionInfo();
+    checkFunctionInfo(functionInfo, function);
+    Assertions.assertEquals(1, ((AlterFunctionEvent) 
event).functionChanges().length);
+    Assertions.assertEquals(change, ((AlterFunctionEvent) 
event).functionChanges()[0]);
+    Assertions.assertEquals(OperationType.ALTER_FUNCTION, 
event.operationType());
+    Assertions.assertEquals(OperationStatus.SUCCESS, event.operationStatus());
+
+    PreEvent preEvent = dummyEventListener.popPreEvent();
+    Assertions.assertEquals(identifier, preEvent.identifier());
+    Assertions.assertEquals(AlterFunctionPreEvent.class, preEvent.getClass());
+    Assertions.assertEquals(1, ((AlterFunctionPreEvent) 
preEvent).functionChanges().length);
+    Assertions.assertEquals(change, ((AlterFunctionPreEvent) 
preEvent).functionChanges()[0]);
+    Assertions.assertEquals(OperationType.ALTER_FUNCTION, 
preEvent.operationType());
+    Assertions.assertEquals(OperationStatus.UNPROCESSED, 
preEvent.operationStatus());
+  }
+
+  @Test
+  void testDropFunctionEvent() {
+    NameIdentifier identifier = NameIdentifier.of("metalake", "catalog", 
"schema", "func");
+    dispatcher.dropFunction(identifier);
+
+    Event event = dummyEventListener.popPostEvent();
+    Assertions.assertEquals(identifier, event.identifier());
+    Assertions.assertEquals(DropFunctionEvent.class, event.getClass());
+    Assertions.assertEquals(true, ((DropFunctionEvent) event).isExists());
+    Assertions.assertEquals(OperationType.DROP_FUNCTION, 
event.operationType());
+    Assertions.assertEquals(OperationStatus.SUCCESS, event.operationStatus());
+
+    PreEvent preEvent = dummyEventListener.popPreEvent();
+    Assertions.assertEquals(identifier, preEvent.identifier());
+    Assertions.assertEquals(DropFunctionPreEvent.class, preEvent.getClass());
+    Assertions.assertEquals(OperationType.DROP_FUNCTION, 
preEvent.operationType());
+    Assertions.assertEquals(OperationStatus.UNPROCESSED, 
preEvent.operationStatus());
+  }
+
+  @Test
+  void testListFunctionEvent() {
+    Namespace namespace = Namespace.of("metalake", "catalog", "schema");
+    dispatcher.listFunctions(namespace);
+
+    Event event = dummyEventListener.popPostEvent();
+    Assertions.assertEquals(namespace.toString(), 
event.identifier().toString());
+    Assertions.assertEquals(ListFunctionEvent.class, event.getClass());
+    Assertions.assertEquals(namespace, ((ListFunctionEvent) 
event).namespace());
+    Assertions.assertEquals(OperationType.LIST_FUNCTION, 
event.operationType());
+    Assertions.assertEquals(OperationStatus.SUCCESS, event.operationStatus());
+
+    PreEvent preEvent = dummyEventListener.popPreEvent();
+    Assertions.assertEquals(namespace.toString(), 
preEvent.identifier().toString());
+    Assertions.assertEquals(ListFunctionPreEvent.class, preEvent.getClass());
+    Assertions.assertEquals(namespace, ((ListFunctionPreEvent) 
preEvent).namespace());
+    Assertions.assertEquals(OperationType.LIST_FUNCTION, 
preEvent.operationType());
+    Assertions.assertEquals(OperationStatus.UNPROCESSED, 
preEvent.operationStatus());
+  }
+
+  @Test
+  void testListFunctionInfosEvent() {
+    Namespace namespace = Namespace.of("metalake", "catalog", "schema");
+    dispatcher.listFunctionInfos(namespace);
+
+    Event event = dummyEventListener.popPostEvent();
+    Assertions.assertEquals(namespace.toString(), 
event.identifier().toString());
+    Assertions.assertEquals(ListFunctionInfosEvent.class, event.getClass());
+    Assertions.assertEquals(namespace, ((ListFunctionInfosEvent) 
event).namespace());
+    FunctionInfo[] functionInfos = ((ListFunctionInfosEvent) 
event).functionInfos();
+    Assertions.assertEquals(1, functionInfos.length);
+    checkFunctionInfo(functionInfos[0], function);
+    Assertions.assertEquals(OperationType.LIST_FUNCTION_INFOS, 
event.operationType());
+    Assertions.assertEquals(OperationStatus.SUCCESS, event.operationStatus());
+
+    PreEvent preEvent = dummyEventListener.popPreEvent();
+    Assertions.assertEquals(namespace.toString(), 
preEvent.identifier().toString());
+    Assertions.assertEquals(ListFunctionPreEvent.class, preEvent.getClass());
+    Assertions.assertEquals(namespace, ((ListFunctionPreEvent) 
preEvent).namespace());
+    Assertions.assertEquals(OperationType.LIST_FUNCTION, 
preEvent.operationType());
+    Assertions.assertEquals(OperationStatus.UNPROCESSED, 
preEvent.operationStatus());
+  }
+
+  @Test
+  void testRegisterFunctionFailureEvent() {
+    NameIdentifier identifier = NameIdentifier.of("metalake", "catalog", 
"schema", "func");
+    Assertions.assertThrowsExactly(
+        GravitinoRuntimeException.class,
+        () ->
+            failureDispatcher.registerFunction(
+                identifier,
+                function.comment(),
+                function.functionType(),
+                function.deterministic(),
+                function.definitions()));
+    Event event = dummyEventListener.popPostEvent();
+    Assertions.assertEquals(identifier, event.identifier());
+    Assertions.assertEquals(RegisterFunctionFailureEvent.class, 
event.getClass());
+    Assertions.assertEquals(
+        GravitinoRuntimeException.class,
+        ((RegisterFunctionFailureEvent) event).exception().getClass());
+    Assertions.assertNotNull(((RegisterFunctionFailureEvent) 
event).registerFunctionRequest());
+    Assertions.assertEquals(OperationType.REGISTER_FUNCTION, 
event.operationType());
+    Assertions.assertEquals(OperationStatus.FAILURE, event.operationStatus());
+  }
+
+  @Test
+  void testGetFunctionFailureEvent() {
+    NameIdentifier identifier = NameIdentifier.of("metalake", "catalog", 
"schema", "func");
+    Assertions.assertThrowsExactly(
+        GravitinoRuntimeException.class, () -> 
failureDispatcher.getFunction(identifier));
+    Event event = dummyEventListener.popPostEvent();
+    Assertions.assertEquals(identifier, event.identifier());
+    Assertions.assertEquals(GetFunctionFailureEvent.class, event.getClass());
+    Assertions.assertEquals(
+        GravitinoRuntimeException.class, ((GetFunctionFailureEvent) 
event).exception().getClass());
+    Assertions.assertEquals(OperationType.GET_FUNCTION, event.operationType());
+    Assertions.assertEquals(OperationStatus.FAILURE, event.operationStatus());
+  }
+
+  @Test
+  void testAlterFunctionFailureEvent() {
+    NameIdentifier identifier = NameIdentifier.of("metalake", "catalog", 
"schema", "func");
+    FunctionChange change = FunctionChange.updateComment("new comment");
+    Assertions.assertThrowsExactly(
+        GravitinoRuntimeException.class, () -> 
failureDispatcher.alterFunction(identifier, change));
+    Event event = dummyEventListener.popPostEvent();
+    Assertions.assertEquals(identifier, event.identifier());
+    Assertions.assertEquals(AlterFunctionFailureEvent.class, event.getClass());
+    Assertions.assertEquals(
+        GravitinoRuntimeException.class,
+        ((AlterFunctionFailureEvent) event).exception().getClass());
+    Assertions.assertEquals(1, ((AlterFunctionFailureEvent) 
event).functionChanges().length);
+    Assertions.assertEquals(change, ((AlterFunctionFailureEvent) 
event).functionChanges()[0]);
+    Assertions.assertEquals(OperationType.ALTER_FUNCTION, 
event.operationType());
+    Assertions.assertEquals(OperationStatus.FAILURE, event.operationStatus());
+  }
+
+  @Test
+  void testDropFunctionFailureEvent() {
+    NameIdentifier identifier = NameIdentifier.of("metalake", "catalog", 
"schema", "func");
+    Assertions.assertThrowsExactly(
+        GravitinoRuntimeException.class, () -> 
failureDispatcher.dropFunction(identifier));
+    Event event = dummyEventListener.popPostEvent();
+    Assertions.assertEquals(identifier, event.identifier());
+    Assertions.assertEquals(DropFunctionFailureEvent.class, event.getClass());
+    Assertions.assertEquals(
+        GravitinoRuntimeException.class, ((DropFunctionFailureEvent) 
event).exception().getClass());
+    Assertions.assertEquals(OperationType.DROP_FUNCTION, 
event.operationType());
+    Assertions.assertEquals(OperationStatus.FAILURE, event.operationStatus());
+  }
+
+  @Test
+  void testListFunctionFailureEvent() {
+    Namespace namespace = Namespace.of("metalake", "catalog", "schema");
+    Assertions.assertThrowsExactly(
+        GravitinoRuntimeException.class, () -> 
failureDispatcher.listFunctions(namespace));
+    Event event = dummyEventListener.popPostEvent();
+    Assertions.assertEquals(namespace.toString(), 
event.identifier().toString());
+    Assertions.assertEquals(ListFunctionFailureEvent.class, event.getClass());
+    Assertions.assertEquals(
+        GravitinoRuntimeException.class, ((ListFunctionFailureEvent) 
event).exception().getClass());
+    Assertions.assertEquals(namespace, ((ListFunctionFailureEvent) 
event).namespace());
+    Assertions.assertEquals(OperationType.LIST_FUNCTION, 
event.operationType());
+    Assertions.assertEquals(OperationStatus.FAILURE, event.operationStatus());
+  }
+
+  @Test
+  void testListFunctionInfosFailureEvent() {
+    Namespace namespace = Namespace.of("metalake", "catalog", "schema");
+    Assertions.assertThrowsExactly(
+        GravitinoRuntimeException.class, () -> 
failureDispatcher.listFunctionInfos(namespace));
+    Event event = dummyEventListener.popPostEvent();
+    Assertions.assertEquals(namespace.toString(), 
event.identifier().toString());
+    Assertions.assertEquals(ListFunctionFailureEvent.class, event.getClass());
+    Assertions.assertEquals(
+        GravitinoRuntimeException.class, ((ListFunctionFailureEvent) 
event).exception().getClass());
+    Assertions.assertEquals(namespace, ((ListFunctionFailureEvent) 
event).namespace());
+    Assertions.assertEquals(OperationType.LIST_FUNCTION, 
event.operationType());
+    Assertions.assertEquals(OperationStatus.FAILURE, event.operationStatus());
+  }
+
+  private void checkFunctionInfo(FunctionInfo functionInfo, Function func) {
+    Assertions.assertEquals(func.name(), functionInfo.name());
+    Assertions.assertEquals(func.functionType(), functionInfo.functionType());
+    Assertions.assertEquals(func.deterministic(), 
functionInfo.deterministic());
+    Assertions.assertEquals(func.comment(), functionInfo.comment());
+    Assertions.assertArrayEquals(func.definitions(), 
functionInfo.definitions());
+    Assertions.assertEquals(func.auditInfo(), functionInfo.auditInfo());
+  }
+
+  private Function mockFunction() {
+    Function func = mock(Function.class);
+    when(func.name()).thenReturn("func");
+    when(func.comment()).thenReturn("test function");
+    when(func.functionType()).thenReturn(FunctionType.SCALAR);
+    when(func.deterministic()).thenReturn(true);
+    when(func.definitions()).thenReturn(new FunctionDefinition[0]);
+    when(func.auditInfo()).thenReturn(null);
+    return func;
+  }
+
+  private FunctionDispatcher mockFunctionDispatcher() {
+    FunctionDispatcher dispatcher = mock(FunctionDispatcher.class);
+    when(dispatcher.registerFunction(
+            any(NameIdentifier.class),
+            any(String.class),
+            any(FunctionType.class),
+            any(Boolean.class),
+            any(FunctionDefinition[].class)))
+        .thenReturn(function);
+    
when(dispatcher.getFunction(any(NameIdentifier.class))).thenReturn(function);
+    when(dispatcher.dropFunction(any(NameIdentifier.class))).thenReturn(true);
+    when(dispatcher.listFunctions(any(Namespace.class))).thenReturn(null);
+    when(dispatcher.listFunctionInfos(any(Namespace.class))).thenReturn(new 
Function[] {function});
+    when(dispatcher.alterFunction(any(NameIdentifier.class), 
any(FunctionChange.class)))
+        .thenReturn(function);
+    return dispatcher;
+  }
+
+  private FunctionDispatcher mockExceptionFunctionDispatcher() {
+    FunctionDispatcher dispatcher =
+        mock(
+            FunctionDispatcher.class,
+            invocation -> {
+              throw new GravitinoRuntimeException("Exception for all methods");
+            });
+    return dispatcher;
+  }
+}
diff --git a/docs/gravitino-server-config.md b/docs/gravitino-server-config.md
index 4b938952a6..e01c56ec05 100644
--- a/docs/gravitino-server-config.md
+++ b/docs/gravitino-server-config.md
@@ -193,6 +193,7 @@ Gravitino triggers a pre-event before the operation, a 
post-event after the comp
 | Gravitino server job operation          | `RunJobEvent`, `GetJobEvent`, 
`ListJobsEvent`, `CancelJobEvent`, `RunJobFailureEvent`, `GetJobFailureEvent`, 
`ListJobsFailureEvent`, `CancelJobFailureEvent`                                 
                                                                                
                                                                                
                                                                                
                    [...]
 | Gravitino server statistics operation   | `ListStatisticsEvent`, 
`UpdateStatisticsEvent`, `DropStatisticsEvent`, `ListPartitionStatisticsEvent`, 
`UpdatePartitionStatisticsEvent`, `DropPartitionStatisticsEvent`, 
`ListStatisticsFailureEvent`, `UpdateStatisticsFailureEvent`, 
`DropStatisticsFailureEvent`, `ListPartitionStatisticsFailureEvent`, 
`UpdatePartitionStatisticsFailureEvent`, `DropPartitionStatisticsFailureEvent`  
                                                                     [...]
 | policy operation                        | `CreatePolicyEvent`, 
`AlterPolicyEvent`, `DeletePolicyEvent`, `GetPolicyEvent`, `ListPoliciesEvent`, 
`AssociatePoliciesForMetadataObjectEvent`, 
`ListAssociatedPoliciesForMetadataObjectEvent`, `CreatePolicyFailureEvent`, 
`AlterPolicyFailureEvent`, `DeletePolicyFailureEvent`, `GetPolicyFailureEvent`, 
`ListPoliciesFailureEvent`, `AssociatePoliciesForMetadataObjectFailureEvent`, 
`ListAssociatedPoliciesForMetadataObjectFailureEvent` | 1.1.0            |
+| function operation                      | `RegisterFunctionEvent`, 
`GetFunctionEvent`, `AlterFunctionEvent`, `DropFunctionEvent`, 
`ListFunctionEvent`, `ListFunctionInfosEvent`, `RegisterFunctionFailureEvent`, 
`GetFunctionFailureEvent`, `AlterFunctionFailureEvent`, 
`DropFunctionFailureEvent`, `ListFunctionFailureEvent`                          
                                                                                
                                             | 1.3.0            |
 
 ##### Pre-event
 
@@ -217,6 +218,7 @@ Gravitino triggers a pre-event before the operation, a 
post-event after the comp
 | Gravitino server job operation          | `RunJobPreEvent`, 
`GetJobPreEvent`, `ListJobsPreEvent`, `CancelJobPreEvent`                       
                                                                                
                                                                                
                                                         | 1.0.1            |
 | Gravitino server statistics operation   | `ListStatisticsPreEvent`, 
`UpdateStatisticsPreEvent`, `DropStatisticsPreEvent`, 
`ListPartitionStatisticsPreEvent`, `UpdatePartitionStatisticsPreEvent`, 
`DropPartitionStatisticsPreEvent`                                               
                                                                                
   | 1.1.0            |
 | policy operation                        | `CreatePolicyPreEvent`, 
`AlterPolicyPreEvent`, `DeletePolicyPreEvent`, `GetPolicyPreEvent`, 
`ListPoliciesPreEvent`, `AssociatePoliciesForMetadataObjectPreEvent`, 
`ListAssociatedPoliciesForMetadataObjectPreEvent`                               
                                                                                
 | 1.1.0 |
+| function operation                      | `RegisterFunctionPreEvent`, 
`GetFunctionPreEvent`, `AlterFunctionPreEvent`, `DropFunctionPreEvent`, 
`ListFunctionPreEvent`                                                          
                                                                                
                                                              | 1.3.0 |
 
 #### Event listener plugin
 

Reply via email to