diff --git a/core/src/main/java/org/apache/gravitino/listener/ModelEventDispatcher.java b/core/src/main/java/org/apache/gravitino/listener/ModelEventDispatcher.java index 9ffd7e8ae66..b98d12f4575 100644 --- a/core/src/main/java/org/apache/gravitino/listener/ModelEventDispatcher.java +++ b/core/src/main/java/org/apache/gravitino/listener/ModelEventDispatcher.java @@ -28,14 +28,23 @@ import org.apache.gravitino.exceptions.NoSuchModelException; import org.apache.gravitino.exceptions.NoSuchModelVersionException; import org.apache.gravitino.exceptions.NoSuchSchemaException; +import org.apache.gravitino.listener.api.event.DeleteModelFailureEvent; import org.apache.gravitino.listener.api.event.DeleteModelPreEvent; +import org.apache.gravitino.listener.api.event.DeleteModelVersionFailureEvent; import org.apache.gravitino.listener.api.event.DeleteModelVersionPreEvent; +import org.apache.gravitino.listener.api.event.GetModelFailureEvent; import org.apache.gravitino.listener.api.event.GetModelPreEvent; +import org.apache.gravitino.listener.api.event.GetModelVersionFailureEvent; import org.apache.gravitino.listener.api.event.GetModelVersionPreEvent; +import org.apache.gravitino.listener.api.event.LinkModelVersionFailureEvent; import org.apache.gravitino.listener.api.event.LinkModelVersionPreEvent; +import org.apache.gravitino.listener.api.event.ListModelFailureEvent; import org.apache.gravitino.listener.api.event.ListModelPreEvent; +import org.apache.gravitino.listener.api.event.ListModelVersionFailureEvent; import org.apache.gravitino.listener.api.event.ListModelVersionPreEvent; +import org.apache.gravitino.listener.api.event.RegisterAndLinkModelFailureEvent; import org.apache.gravitino.listener.api.event.RegisterAndLinkModelPreEvent; +import org.apache.gravitino.listener.api.event.RegisterModelFailureEvent; import org.apache.gravitino.listener.api.event.RegisterModelPreEvent; import org.apache.gravitino.listener.api.info.ModelInfo; import org.apache.gravitino.listener.api.info.ModelVersionInfo; @@ -70,15 +79,15 @@ public ModelEventDispatcher(EventBus eventBus, ModelDispatcher dispatcher) { @Override public Model registerModel(NameIdentifier ident, String comment, Map properties) throws NoSuchSchemaException, ModelAlreadyExistsException { + String user = PrincipalUtils.getCurrentUserName(); ModelInfo registerRequest = new ModelInfo(ident.name(), properties, comment); - eventBus.dispatchEvent( - new RegisterModelPreEvent(PrincipalUtils.getCurrentUserName(), ident, registerRequest)); + eventBus.dispatchEvent(new RegisterModelPreEvent(user, ident, registerRequest)); try { Model model = dispatcher.registerModel(ident, comment, properties); // TODO: ModelEvent return model; } catch (Exception e) { - // TODO: failureEvent + eventBus.dispatchEvent(new RegisterModelFailureEvent(user, ident, e, registerRequest)); throw e; } } @@ -96,18 +105,19 @@ public Model registerModel( ModelInfo registerModelRequest = new ModelInfo(ident.name(), properties, comment); ModelVersionInfo linkModelVersionRequest = new ModelVersionInfo(uri, comment, properties, aliases); + String user = PrincipalUtils.getCurrentUserName(); RegisterAndLinkModelPreEvent registerAndLinkModelPreEvent = new RegisterAndLinkModelPreEvent( - PrincipalUtils.getCurrentUserName(), - ident, - registerModelRequest, - linkModelVersionRequest); + user, ident, registerModelRequest, linkModelVersionRequest); eventBus.dispatchEvent(registerAndLinkModelPreEvent); try { // TODO: ModelEvent return dispatcher.registerModel(ident, uri, aliases, comment, properties); } catch (Exception e) { + eventBus.dispatchEvent( + new RegisterAndLinkModelFailureEvent( + user, ident, e, registerModelRequest, linkModelVersionRequest)); throw e; } } @@ -115,13 +125,14 @@ public Model registerModel( /** {@inheritDoc} */ @Override public Model getModel(NameIdentifier ident) throws NoSuchModelException { - eventBus.dispatchEvent(new GetModelPreEvent(PrincipalUtils.getCurrentUserName(), ident)); + String user = PrincipalUtils.getCurrentUserName(); + eventBus.dispatchEvent(new GetModelPreEvent(user, ident)); try { Model model = dispatcher.getModel(ident); // TODO: ModelEvent return model; } catch (Exception e) { - // TODO: failureEvent + eventBus.dispatchEvent(new GetModelFailureEvent(user, ident, e)); throw e; } } @@ -129,12 +140,13 @@ public Model getModel(NameIdentifier ident) throws NoSuchModelException { /** {@inheritDoc} */ @Override public boolean deleteModel(NameIdentifier ident) { - eventBus.dispatchEvent(new DeleteModelPreEvent(PrincipalUtils.getCurrentUserName(), ident)); + String user = PrincipalUtils.getCurrentUserName(); + eventBus.dispatchEvent(new DeleteModelPreEvent(user, ident)); try { // TODO: ModelEvent return dispatcher.deleteModel(ident); } catch (Exception e) { - // TODO: failureEvent + eventBus.dispatchEvent(new DeleteModelFailureEvent(user, ident, e)); throw e; } } @@ -142,13 +154,14 @@ public boolean deleteModel(NameIdentifier ident) { /** {@inheritDoc} */ @Override public NameIdentifier[] listModels(Namespace namespace) throws NoSuchSchemaException { - eventBus.dispatchEvent(new ListModelPreEvent(PrincipalUtils.getCurrentUserName(), namespace)); + String user = PrincipalUtils.getCurrentUserName(); + eventBus.dispatchEvent(new ListModelPreEvent(user, namespace)); try { NameIdentifier[] models = dispatcher.listModels(namespace); // TODO: ModelEvent return models; } catch (Exception e) { - // TODO: failureEvent + eventBus.dispatchEvent(new ListModelFailureEvent(user, namespace, e)); throw e; } } @@ -163,13 +176,14 @@ public void linkModelVersion( Map properties) throws NoSuchModelException, ModelVersionAliasesAlreadyExistException { ModelVersionInfo linkModelRequest = new ModelVersionInfo(uri, comment, properties, aliases); - eventBus.dispatchEvent( - new LinkModelVersionPreEvent(PrincipalUtils.getCurrentUserName(), ident, linkModelRequest)); + String user = PrincipalUtils.getCurrentUserName(); + + eventBus.dispatchEvent(new LinkModelVersionPreEvent(user, ident, linkModelRequest)); try { dispatcher.linkModelVersion(ident, uri, aliases, comment, properties); // TODO: ModelEvent } catch (Exception e) { - // TODO: failureEvent + eventBus.dispatchEvent(new LinkModelVersionFailureEvent(user, ident, e, linkModelRequest)); throw e; } } @@ -178,13 +192,14 @@ public void linkModelVersion( @Override public ModelVersion getModelVersion(NameIdentifier ident, int version) throws NoSuchModelVersionException { - eventBus.dispatchEvent( - new GetModelVersionPreEvent(PrincipalUtils.getCurrentUserName(), ident, null, version)); + String user = PrincipalUtils.getCurrentUserName(); + + eventBus.dispatchEvent(new GetModelVersionPreEvent(user, ident, null, version)); try { // TODO: ModelEvent return dispatcher.getModelVersion(ident, version); } catch (Exception e) { - // TODO: failureEvent + eventBus.dispatchEvent(new GetModelVersionFailureEvent(user, ident, e, null, version)); throw e; } } @@ -193,14 +208,15 @@ public ModelVersion getModelVersion(NameIdentifier ident, int version) @Override public ModelVersion getModelVersion(NameIdentifier ident, String alias) throws NoSuchModelVersionException { - eventBus.dispatchEvent( - new GetModelVersionPreEvent(PrincipalUtils.getCurrentUserName(), ident, alias, null)); + String user = PrincipalUtils.getCurrentUserName(); + + eventBus.dispatchEvent(new GetModelVersionPreEvent(user, ident, alias, null)); try { ModelVersion modelVersion = dispatcher.getModelVersion(ident, alias); // TODO: ModelEvent return modelVersion; } catch (Exception e) { - // TODO: failureEvent + eventBus.dispatchEvent(new GetModelVersionFailureEvent(user, ident, e, alias, null)); throw e; } } @@ -208,14 +224,15 @@ public ModelVersion getModelVersion(NameIdentifier ident, String alias) /** {@inheritDoc} */ @Override public boolean deleteModelVersion(NameIdentifier ident, int version) { - eventBus.dispatchEvent( - new DeleteModelVersionPreEvent(PrincipalUtils.getCurrentUserName(), ident, null, version)); + String user = PrincipalUtils.getCurrentUserName(); + + eventBus.dispatchEvent(new DeleteModelVersionPreEvent(user, ident, null, version)); try { boolean isExists = dispatcher.deleteModelVersion(ident, version); // TODO: ModelEvent return isExists; } catch (Exception e) { - // TODO: failureEvent + eventBus.dispatchEvent(new DeleteModelVersionFailureEvent(user, ident, e, null, version)); throw e; } } @@ -223,14 +240,15 @@ public boolean deleteModelVersion(NameIdentifier ident, int version) { /** {@inheritDoc} */ @Override public boolean deleteModelVersion(NameIdentifier ident, String alias) { - eventBus.dispatchEvent( - new DeleteModelVersionPreEvent(PrincipalUtils.getCurrentUserName(), ident, alias, null)); + String user = PrincipalUtils.getCurrentUserName(); + + eventBus.dispatchEvent(new DeleteModelVersionPreEvent(user, ident, alias, null)); try { boolean isExists = dispatcher.deleteModelVersion(ident, alias); // TODO: ModelEvent return isExists; } catch (Exception e) { - // TODO: failureEvent + eventBus.dispatchEvent(new DeleteModelVersionFailureEvent(user, ident, e, alias, null)); throw e; } } @@ -238,14 +256,15 @@ public boolean deleteModelVersion(NameIdentifier ident, String alias) { /** {@inheritDoc} */ @Override public int[] listModelVersions(NameIdentifier ident) throws NoSuchModelException { - eventBus.dispatchEvent( - new ListModelVersionPreEvent(PrincipalUtils.getCurrentUserName(), ident)); + String user = PrincipalUtils.getCurrentUserName(); + + eventBus.dispatchEvent(new ListModelVersionPreEvent(user, ident)); try { int[] versions = dispatcher.listModelVersions(ident); // TODO: ModelEvent return versions; } catch (Exception e) { - // TODO: failureEvent + eventBus.dispatchEvent(new ListModelVersionFailureEvent(user, ident, e)); throw e; } } diff --git a/core/src/main/java/org/apache/gravitino/listener/api/event/DeleteModelFailureEvent.java b/core/src/main/java/org/apache/gravitino/listener/api/event/DeleteModelFailureEvent.java new file mode 100644 index 00000000000..959398fd962 --- /dev/null +++ b/core/src/main/java/org/apache/gravitino/listener/api/event/DeleteModelFailureEvent.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; + +import org.apache.gravitino.NameIdentifier; +import org.apache.gravitino.annotation.DeveloperApi; + +/** + * Represents an event that is generated when an attempt to drop a model from the schema fails due + * to an exception. + */ +@DeveloperApi +public class DeleteModelFailureEvent extends ModelFailureEvent { + /** + * Construct a new {@link DeleteModelFailureEvent} instance, capturing detailed information about + * the failed attempt to drop a model. + * + * @param user The user who initiated the drop model operation. + * @param identifier The identifier of the model that the operation attempted to drop. + * @param exception The exception that was thrown during the drop model operation, offering + * insights into what went wrong and why the operation failed. + */ + public DeleteModelFailureEvent(String user, NameIdentifier identifier, Exception exception) { + super(user, identifier, exception); + } + + /** + * Returns the type of operation. + * + * @return the operation type. + */ + @Override + public OperationType operationType() { + return OperationType.DELETE_MODEL; + } +} diff --git a/core/src/main/java/org/apache/gravitino/listener/api/event/DeleteModelVersionFailureEvent.java b/core/src/main/java/org/apache/gravitino/listener/api/event/DeleteModelVersionFailureEvent.java new file mode 100644 index 00000000000..69ebdfee6f8 --- /dev/null +++ b/core/src/main/java/org/apache/gravitino/listener/api/event/DeleteModelVersionFailureEvent.java @@ -0,0 +1,85 @@ +/* + * 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.Optional; +import org.apache.gravitino.NameIdentifier; +import org.apache.gravitino.annotation.DeveloperApi; + +/** + * Represents an event that is generated when an attempt to delete a model version from a model + * fails due to an exception. + */ +@DeveloperApi +public class DeleteModelVersionFailureEvent extends ModelFailureEvent { + private final Optional alias; + private final Optional version; + + /** + * Constructs a new instance of {@link DeleteModelVersionFailureEvent} instance, capturing + * detailed information about the failed attempt to delete a model version. only one of alias or + * version are valid. + * + * @param user The user who initiated the delete model version operation. + * @param identifier The identifier of the model that the operation attempted to delete a version + * from. + * @param exception The exception that was thrown during the delete model version operation, + * offering insights into what went wrong and why the operation failed. + * @param alias The alias of the model version to be deleted. + * @param version The version of the model version to be deleted. + */ + public DeleteModelVersionFailureEvent( + String user, NameIdentifier identifier, Exception exception, String alias, Integer version) { + super(user, identifier, exception); + + this.alias = Optional.ofNullable(alias); + this.version = Optional.ofNullable(version); + } + + /** + * Returns the alias of the model version to be deleted. + * + * @return A {@link Optional} instance containing the alias if it was provided, or an empty {@link + * Optional} otherwise. + */ + public Optional alias() { + return alias; + } + + /** + * Returns the version of the model version to be deleted. + * + * @return A {@link Optional} instance containing the version if it was provided, or an empty + * {@link Optional} otherwise. + */ + public Optional version() { + return version; + } + + /** + * Returns the type of operation. + * + * @return the operation type. + */ + @Override + public OperationType operationType() { + return OperationType.DELETE_MODEL_VERSION; + } +} diff --git a/core/src/main/java/org/apache/gravitino/listener/api/event/GetModelFailureEvent.java b/core/src/main/java/org/apache/gravitino/listener/api/event/GetModelFailureEvent.java new file mode 100644 index 00000000000..402a34ec822 --- /dev/null +++ b/core/src/main/java/org/apache/gravitino/listener/api/event/GetModelFailureEvent.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; + +import org.apache.gravitino.NameIdentifier; +import org.apache.gravitino.annotation.DeveloperApi; + +/** + * Represents an event that is generated when an attempt to get a model fails due to an exception. + */ +@DeveloperApi +public class GetModelFailureEvent extends ModelFailureEvent { + /** + * Construct a new {@link GetModelFailureEvent} instance, capturing detailed information about the + * failed attempt to get a model. + * + * @param user The user who initiated the get model operation. + * @param identifier The identifier of the model that the operation attempted to get. + * @param exception The exception that was thrown during the get model operation, offering + * insights into what went wrong and why the operation failed. + */ + public GetModelFailureEvent(String user, NameIdentifier identifier, Exception exception) { + super(user, identifier, exception); + } + + /** + * Returns the type of operation. + * + * @return the operation type. + */ + @Override + public OperationType operationType() { + return OperationType.GET_MODEL; + } +} diff --git a/core/src/main/java/org/apache/gravitino/listener/api/event/GetModelVersionFailureEvent.java b/core/src/main/java/org/apache/gravitino/listener/api/event/GetModelVersionFailureEvent.java new file mode 100644 index 00000000000..bf4f6210130 --- /dev/null +++ b/core/src/main/java/org/apache/gravitino/listener/api/event/GetModelVersionFailureEvent.java @@ -0,0 +1,83 @@ +/* + * 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.Optional; +import org.apache.gravitino.NameIdentifier; +import org.apache.gravitino.annotation.DeveloperApi; + +/** + * Represents an event that is generated when an attempt to get a model version fails due to an + * exception. + */ +@DeveloperApi +public class GetModelVersionFailureEvent extends ModelFailureEvent { + private final Optional alias; + private final Optional version; + + /** + * Construct a new {@link GetModelVersionFailureEvent} instance, capturing detailed information + * about the failed attempt to get a model version. only one of alias or version are valid. + * + * @param user The user associated with the failed model operation. + * @param identifier The identifier of the model that was involved in the failed operation. + * @param exception The exception that was thrown during the get model version operation, offering + * insights into what went wrong and why the operation failed. + * @param alias The alias of the model version to get. + * @param version The version of the model version to get. + */ + public GetModelVersionFailureEvent( + String user, NameIdentifier identifier, Exception exception, String alias, Integer version) { + super(user, identifier, exception); + + this.alias = Optional.ofNullable(alias); + this.version = Optional.ofNullable(version); + } + + /** + * Returns the alias of the model version to get. + * + * @return A {@link Optional} instance containing the alias if it was provided, or an empty {@link + * Optional} otherwise. + */ + public Optional alias() { + return alias; + } + + /** + * Returns the version of the model version to get. + * + * @return A {@link Optional} instance containing the version if it was provided, or an empty + * {@link Optional} otherwise. + */ + public Optional version() { + return version; + } + + /** + * Returns the type of operation. + * + * @return the operation type. + */ + @Override + public OperationType operationType() { + return OperationType.GET_MODEL_VERSION; + } +} diff --git a/core/src/main/java/org/apache/gravitino/listener/api/event/LinkModelVersionFailureEvent.java b/core/src/main/java/org/apache/gravitino/listener/api/event/LinkModelVersionFailureEvent.java new file mode 100644 index 00000000000..e47a853f385 --- /dev/null +++ b/core/src/main/java/org/apache/gravitino/listener/api/event/LinkModelVersionFailureEvent.java @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.gravitino.listener.api.event; + +import org.apache.gravitino.NameIdentifier; +import org.apache.gravitino.annotation.DeveloperApi; +import org.apache.gravitino.listener.api.info.ModelVersionInfo; + +/** + * Represents an event that is triggered when an attempt to link a model version fails due to an + * exception. + */ +@DeveloperApi +public class LinkModelVersionFailureEvent extends ModelFailureEvent { + private final ModelVersionInfo linkModelVersionRequest; + /** + * Construct a new {@link LinkModelVersionFailureEvent} instance, capturing information about the + * failed model version operation. + * + * @param user The username of the individual who initiated the operation to link a model version. + * @param identifier The identifier of the model that was involved in the failed operation. + * @param exception The exception encountered during the attempt to link a model version. + */ + public LinkModelVersionFailureEvent( + String user, + NameIdentifier identifier, + Exception exception, + ModelVersionInfo linkModelVersionRequest) { + super(user, identifier, exception); + + this.linkModelVersionRequest = linkModelVersionRequest; + } + + /** + * Retrieves the linked model version information. + * + * @return the model version information. + */ + public ModelVersionInfo linkModelVersionRequest() { + return linkModelVersionRequest; + } + + /** + * Returns the type of operation. + * + * @return the operation type. + */ + @Override + public OperationType operationType() { + return OperationType.LINK_MODEL_VERSION; + } +} diff --git a/core/src/main/java/org/apache/gravitino/listener/api/event/ListModelFailureEvent.java b/core/src/main/java/org/apache/gravitino/listener/api/event/ListModelFailureEvent.java new file mode 100644 index 00000000000..81b46ca7cc6 --- /dev/null +++ b/core/src/main/java/org/apache/gravitino/listener/api/event/ListModelFailureEvent.java @@ -0,0 +1,64 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.gravitino.listener.api.event; + +import org.apache.gravitino.NameIdentifier; +import org.apache.gravitino.Namespace; +import org.apache.gravitino.annotation.DeveloperApi; + +/** + * Represents an event that is triggered when an attempt to list models within a namespace fails due + * to an exception. + */ +@DeveloperApi +public class ListModelFailureEvent extends ModelFailureEvent { + private final Namespace namespace; + + /** + * Construct a new {@link ListModelFailureEvent} instance. + * + * @param user The username of the individual who initiated the operation to list models. + * @param namespace The namespace for which the model listing was attempted. + * @param exception The exception encountered during the attempt to list models. + */ + public ListModelFailureEvent(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 model listing was attempted + */ + public Namespace namespace() { + return namespace; + } + + /** + * Returns the type of operation. + * + * @return the operation type. + */ + @Override + public OperationType operationType() { + return OperationType.LIST_MODEL; + } +} diff --git a/core/src/main/java/org/apache/gravitino/listener/api/event/ListModelVersionFailureEvent.java b/core/src/main/java/org/apache/gravitino/listener/api/event/ListModelVersionFailureEvent.java new file mode 100644 index 00000000000..50bed4a9294 --- /dev/null +++ b/core/src/main/java/org/apache/gravitino/listener/api/event/ListModelVersionFailureEvent.java @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.gravitino.listener.api.event; + +import org.apache.gravitino.NameIdentifier; +import org.apache.gravitino.annotation.DeveloperApi; + +/** + * Represents an event that is generated when an attempt to list versions of a model fails due to an + * exception. + */ +@DeveloperApi +public class ListModelVersionFailureEvent extends ModelFailureEvent { + + /** + * Constuct a new {@link ListModelVersionFailureEvent} instance, capturing detailed information + * about the failed attempt to list versions of a model. + * + * @param user The user who initiated the list model version operation. + * @param identifier The identifier of the model that the operation attempted to list versions + * for. + * @param exception The exception that was thrown during the list model version operation, + * offering insights into what went wrong and why the operation failed. + */ + public ListModelVersionFailureEvent(String user, NameIdentifier identifier, Exception exception) { + super(user, identifier, exception); + } + + /** + * Returns the type of operation. + * + * @return the operation type. + */ + @Override + public OperationType operationType() { + return OperationType.LIST_MODEL_VERSIONS; + } +} diff --git a/core/src/main/java/org/apache/gravitino/listener/api/event/ModelFailureEvent.java b/core/src/main/java/org/apache/gravitino/listener/api/event/ModelFailureEvent.java new file mode 100644 index 00000000000..6d556232948 --- /dev/null +++ b/core/src/main/java/org/apache/gravitino/listener/api/event/ModelFailureEvent.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; + +import org.apache.gravitino.NameIdentifier; +import org.apache.gravitino.annotation.DeveloperApi; + +/** + * An abstract class representing events that are triggered when a model operation fails due to an + * exception. This class extends {@link FailureEvent} to provide a more specific context related to + * model operations, encapsulating details about the user who initiated the operation, the + * identifier of the model involved, and the exception that led to the failure. + * + *

Implementations of this class can be used to convey detailed information about failures in + * operations such as creating, updating, deleting, or querying tables, making it easier to diagnose + * and respond to issues. + */ +@DeveloperApi +public abstract class ModelFailureEvent extends FailureEvent { + + /** + * Creates a new instance of {@code ModelFailureEvent}, capturing information about the failed + * model operation. + * + * @param user The user associated with the failed model operation. + * @param identifier The identifier of the model that was involved in the failed operation. + * @param exception The exception that was thrown during the model operation, indicating the cause + * of the failure. + */ + protected ModelFailureEvent(String user, NameIdentifier identifier, Exception exception) { + super(user, identifier, exception); + } +} diff --git a/core/src/main/java/org/apache/gravitino/listener/api/event/RegisterAndLinkModelFailureEvent.java b/core/src/main/java/org/apache/gravitino/listener/api/event/RegisterAndLinkModelFailureEvent.java new file mode 100644 index 00000000000..523883e99a3 --- /dev/null +++ b/core/src/main/java/org/apache/gravitino/listener/api/event/RegisterAndLinkModelFailureEvent.java @@ -0,0 +1,87 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.gravitino.listener.api.event; + +import org.apache.gravitino.NameIdentifier; +import org.apache.gravitino.annotation.DeveloperApi; +import org.apache.gravitino.listener.api.info.ModelInfo; +import org.apache.gravitino.listener.api.info.ModelVersionInfo; + +/** + * Represents an event that is generated when an attempt to register a model or link a model version + * of a model fails due to an exception. + */ +@DeveloperApi +public class RegisterAndLinkModelFailureEvent extends ModelFailureEvent { + private final ModelInfo registerModelRequest; + private final ModelVersionInfo linkModelVersionRequest; + + /** + * Create a new {@link RegisterAndLinkModelFailureEvent} instance, capturing detailed information + * about * the failed attempt to register a model. + * + * @param user The user who initiated the register/link model operation. + * @param identifier The identifier of the model that was involved in the failed operation. + * @param exception The exception encountered during the attempt to register a model or link a + * model version. + * @param registerModelRequest the model information that was requested to be registered. + * @param linkModelVersionRequest The version information of the model that was requested to be + * linked. + */ + public RegisterAndLinkModelFailureEvent( + String user, + NameIdentifier identifier, + Exception exception, + ModelInfo registerModelRequest, + ModelVersionInfo linkModelVersionRequest) { + super(user, identifier, exception); + + this.registerModelRequest = registerModelRequest; + this.linkModelVersionRequest = linkModelVersionRequest; + } + + /** + * Retrieves the registered model information. + * + * @return the model information. + */ + public ModelInfo registerModelRequest() { + return registerModelRequest; + } + + /** + * Retrieves the linked model version information. + * + * @return the model version information. + */ + public ModelVersionInfo linkModelVersionRequest() { + return linkModelVersionRequest; + } + + /** + * Returns the type of operation. + * + * @return the operation type. + */ + @Override + public OperationType operationType() { + return OperationType.REGISTER_AND_LINK_MODEL_VERSION; + } +} diff --git a/core/src/main/java/org/apache/gravitino/listener/api/event/RegisterModelFailureEvent.java b/core/src/main/java/org/apache/gravitino/listener/api/event/RegisterModelFailureEvent.java new file mode 100644 index 00000000000..90d14f4228a --- /dev/null +++ b/core/src/main/java/org/apache/gravitino/listener/api/event/RegisterModelFailureEvent.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; + +import org.apache.gravitino.NameIdentifier; +import org.apache.gravitino.annotation.DeveloperApi; +import org.apache.gravitino.listener.api.info.ModelInfo; + +/** + * Represents an event that is generated when an attempt to register a model fails due to an + * exception. + */ +@DeveloperApi +public class RegisterModelFailureEvent extends ModelFailureEvent { + private final ModelInfo registerModelRequest; + /** + * Construct a {@link RegisterModelFailureEvent} instance, capturing detailed information about + * the failed attempt to register a model. + * + * @param user The user who initiated the register model operation. + * @param identifier The identifier of the model that the operation attempted to register. + * @param exception The exception that was thrown during the register model operation, offering + * insights into what went wrong and why the operation failed. + * @param registerModelRequest the model information that was requested to be registered. + */ + public RegisterModelFailureEvent( + String user, NameIdentifier identifier, Exception exception, ModelInfo registerModelRequest) { + super(user, identifier, exception); + this.registerModelRequest = registerModelRequest; + } + + /** + * Retrieves the registered model information. + * + * @return the model information. + */ + public ModelInfo registerModelRequest() { + return registerModelRequest; + } + + /** + * Returns the type of operation. + * + * @return the operation type. + */ + @Override + public OperationType operationType() { + return OperationType.REGISTER_MODEL; + } +} diff --git a/core/src/main/java/org/apache/gravitino/listener/api/info/ModelInfo.java b/core/src/main/java/org/apache/gravitino/listener/api/info/ModelInfo.java index 870f725277d..88e85caea71 100644 --- a/core/src/main/java/org/apache/gravitino/listener/api/info/ModelInfo.java +++ b/core/src/main/java/org/apache/gravitino/listener/api/info/ModelInfo.java @@ -39,24 +39,40 @@ public class ModelInfo { private final Optional lastVersion; /** - * Constructs model information based on a given model. + * Constructs a {@link ModelInfo} instance based on a given model. * * @param model the model to expose information for. */ public ModelInfo(Model model) { - this.name = model.name(); - this.properties = - model.properties() == null ? ImmutableMap.of() : ImmutableMap.copyOf(model.properties()); - - this.comment = Optional.ofNullable(model.comment()); - this.audit = Optional.ofNullable(model.auditInfo()); - this.lastVersion = Optional.ofNullable(model.latestVersion()); + this( + model.name(), + model.properties(), + model.comment(), + model.auditInfo(), + model.latestVersion()); } + /** + * Constructs a {@link ModelInfo} instance based on name, properties, and comment. + * + * @param name the name of the model. + * @param properties the properties of the model. + * @param comment the comment of the model. + */ public ModelInfo(String name, Map properties, String comment) { this(name, properties, comment, null, null); } + /** + * Constructs a {@link ModelInfo} instance based on name, properties, comment, audit, and last + * version. + * + * @param name the name of the model. + * @param properties the properties of the model. + * @param comment the comment of the model. + * @param audit the audit information of the model. + * @param lastVersion the last version of the model. + */ public ModelInfo( String name, Map properties, 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 a9a953a86e6..5eea942d1fd 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 @@ -38,7 +38,7 @@ public class ModelVersionInfo { private final Optional auditInfo; /** - * Constructs model version information based on a given {@link ModelVersion}. + * Constructs a {@link ModelVersionInfo} instance based on a given {@link ModelVersion}. * * @param modelVersion the model version to expose information for. */ @@ -51,18 +51,29 @@ public ModelVersionInfo(ModelVersion modelVersion) { modelVersion.auditInfo()); } + /** + * Constructs a {@link ModelVersionInfo} instance based on given URI, comment, properties, and + * aliases. + * + * @param uri The URI of the model version. + * @param comment The comment of the model version. + * @param properties The properties of the model version. + * @param aliases The aliases of the model version. + */ public ModelVersionInfo( String uri, String comment, Map properties, String[] aliases) { this(uri, comment, properties, aliases, null); } /** - * Constructs model version information based on a given arguments. + * Constructs a {@link ModelVersionInfo} instance based on given uri, comment, properties, + * aliases, and audit information. * - * @param uri - * @param aliases - * @param comment - * @param properties + * @param uri The URI of the model version. + * @param comment The comment of the model version. + * @param properties The properties of the model version. + * @param aliases The aliases of the model version. + * @param auditInfo The audit information of the model version. */ public ModelVersionInfo( String uri, diff --git a/core/src/test/java/org/apache/gravitino/listener/api/event/TestModelEvent.java b/core/src/test/java/org/apache/gravitino/listener/api/event/TestModelEvent.java index 8489301435e..3ffa7c38b92 100644 --- a/core/src/test/java/org/apache/gravitino/listener/api/event/TestModelEvent.java +++ b/core/src/test/java/org/apache/gravitino/listener/api/event/TestModelEvent.java @@ -26,6 +26,7 @@ import java.time.Instant; import java.util.Collections; import java.util.Map; +import java.util.Optional; import org.apache.gravitino.Audit; import org.apache.gravitino.NameIdentifier; import org.apache.gravitino.Namespace; @@ -61,23 +62,24 @@ public class TestModelEvent { @BeforeAll void init() { this.namespace = Namespace.of("metalake", "catalog", "schema"); + this.existingIdentA = NameIdentifierUtil.ofModel("metalake", "catalog", "schema", "modelA"); + this.existingIdentB = NameIdentifierUtil.ofModel("metalake", "catalog", "schema", "modelB"); + this.modelA = getMockModel("modelA", "commentA"); this.modelB = getMockModel("modelB", "commentB"); + this.firstModelVersion = mockModelVersion("uriA", new String[] {"aliasProduction"}, "versionInfoA"); this.secondModelVersion = mockModelVersion("uriB", new String[] {"aliasTest"}, "versionInfoB"); - System.out.println(secondModelVersion.toString()); - this.existingIdentA = NameIdentifierUtil.ofModel("metalake", "catalog", "schema", "modelA"); - this.existingIdentB = NameIdentifierUtil.ofModel("metalake", "catalog", "schema", "modelB"); + this.notExistingIdent = NameIdentifierUtil.ofModel("metalake", "catalog", "schema", "not_exist"); + this.dummyEventListener = new DummyEventListener(); EventBus eventBus = new EventBus(Collections.singletonList(dummyEventListener)); this.dispatcher = new ModelEventDispatcher(eventBus, mockTagDispatcher()); this.failureDispatcher = new ModelEventDispatcher(eventBus, mockExceptionModelDispatcher()); - // TODO: add failure dispatcher tests. - System.out.println(this.failureDispatcher.toString()); } @Test @@ -85,19 +87,7 @@ void testModelInfo() { Model mockModel = getMockModel("model", "comment"); ModelInfo modelInfo = new ModelInfo(mockModel); - Assertions.assertEquals("model", modelInfo.name()); - Assertions.assertEquals(1, modelInfo.properties().size()); - Assertions.assertEquals("#FFFFFF", modelInfo.properties().get("color")); - - Assertions.assertTrue(modelInfo.comment().isPresent()); - String comment = modelInfo.comment().get(); - Assertions.assertEquals("comment", comment); - - Assertions.assertFalse(modelInfo.audit().isPresent()); - - Assertions.assertTrue(modelInfo.lastVersion().isPresent()); - int lastVersion = modelInfo.lastVersion().get(); - Assertions.assertEquals(1, lastVersion); + checkModelInfo(modelInfo, mockModel); } @Test @@ -105,7 +95,7 @@ void testModelInfoWithoutComment() { Model mockModel = getMockModel("model", null); ModelInfo modelInfo = new ModelInfo(mockModel); - Assertions.assertFalse(modelInfo.comment().isPresent()); + checkModelInfo(modelInfo, mockModel); } @Test @@ -113,20 +103,33 @@ void testModelInfoWithAudit() { Model mockModel = getMockModelWithAudit("model", "comment"); ModelInfo modelInfo = new ModelInfo(mockModel); - Assertions.assertEquals("model", modelInfo.name()); - Assertions.assertEquals(1, modelInfo.properties().size()); - Assertions.assertEquals("#FFFFFF", modelInfo.properties().get("color")); + checkModelInfo(modelInfo, mockModel); + } - Assertions.assertTrue(modelInfo.comment().isPresent()); - String comment = modelInfo.comment().get(); - Assertions.assertEquals("comment", comment); + @Test + void testModelVersionInfo() { + ModelVersion modelVersion = + mockModelVersion("uriA", new String[] {"aliasProduction"}, "versionInfoA"); + ModelVersionInfo modelVersionInfo = new ModelVersionInfo(modelVersion); - Assertions.assertTrue(modelInfo.audit().isPresent()); - Audit audit = modelInfo.audit().get(); - Assertions.assertEquals("demo_user", audit.creator()); - Assertions.assertEquals(1611111111111L, audit.createTime().toEpochMilli()); - Assertions.assertEquals("demo_user", audit.lastModifier()); - Assertions.assertEquals(1611111111111L, audit.lastModifiedTime().toEpochMilli()); + checkModelVersionInfo(modelVersionInfo, modelVersion); + } + + @Test + void testModelVersionInfoWithoutComment() { + ModelVersion modelVersion = mockModelVersion("uriA", new String[] {"aliasProduction"}, null); + ModelVersionInfo modelVersionInfo = new ModelVersionInfo(modelVersion); + + checkModelVersionInfo(modelVersionInfo, modelVersion); + } + + @Test + void testModelVersionInfoWithAudit() { + ModelVersion modelVersion = + getMockModelWithAudit("uriA", new String[] {"aliasProduction"}, "versionInfoA"); + ModelVersionInfo modelVersionInfo = new ModelVersionInfo(modelVersion); + + checkModelVersionInfo(modelVersionInfo, modelVersion); } @Test @@ -144,13 +147,30 @@ void testRegisterModelEvent() { Assertions.assertEquals(existingIdentA, registerModelPreEvent.identifier()); ModelInfo modelInfoPreEvent = registerModelPreEvent.registerModelRequest(); - Assertions.assertEquals("modelA", modelInfoPreEvent.name()); - Assertions.assertEquals(ImmutableMap.of("color", "#FFFFFF"), modelInfoPreEvent.properties()); - Assertions.assertTrue(modelInfoPreEvent.comment().isPresent()); - String comment = modelInfoPreEvent.comment().get(); - Assertions.assertEquals("commentA", comment); - Assertions.assertFalse(modelInfoPreEvent.audit().isPresent()); - Assertions.assertFalse(modelInfoPreEvent.lastVersion().isPresent()); + checkModelInfo(modelInfoPreEvent, modelA); + } + + @Test + void testRegisterModelFailureEvent() { + Assertions.assertThrowsExactly( + GravitinoRuntimeException.class, + () -> + failureDispatcher.registerModel( + existingIdentA, "commentA", ImmutableMap.of("color", "#FFFFFF"))); + + Event event = dummyEventListener.popPostEvent(); + + Assertions.assertEquals(existingIdentA, event.identifier()); + Assertions.assertEquals(RegisterModelFailureEvent.class, event.getClass()); + Assertions.assertEquals( + GravitinoRuntimeException.class, + ((RegisterModelFailureEvent) event).exception().getClass()); + Assertions.assertEquals(OperationType.REGISTER_MODEL, event.operationType()); + Assertions.assertEquals(OperationStatus.FAILURE, event.operationStatus()); + ModelInfo registerModelRequest = ((RegisterModelFailureEvent) event).registerModelRequest(); + + // check model-info + checkModelInfo(registerModelRequest, modelA); } @Test @@ -158,7 +178,7 @@ void testRegisterAndLinkModelEvent() { dispatcher.registerModel( existingIdentA, "uriA", - new String[] {"aliasProduction", "aliasTest"}, + new String[] {"aliasProduction"}, "commentA", ImmutableMap.of("color", "#FFFFFF")); // validate pre-event @@ -173,23 +193,54 @@ void testRegisterAndLinkModelEvent() { (RegisterAndLinkModelPreEvent) preEvent; ModelInfo registerModelRequest = registerAndLinkModelPreEvent.registerModelRequest(); - Assertions.assertEquals("modelA", registerModelRequest.name()); - Assertions.assertEquals(ImmutableMap.of("color", "#FFFFFF"), registerModelRequest.properties()); - Assertions.assertTrue(registerModelRequest.comment().isPresent()); - String comment = registerModelRequest.comment().get(); - Assertions.assertEquals("commentA", comment); - Assertions.assertFalse(registerModelRequest.audit().isPresent()); - Assertions.assertFalse(registerModelRequest.lastVersion().isPresent()); + checkModelInfo(registerModelRequest, modelA); // validate pre-event model version info - ModelVersionInfo modelVersionInfoPreEvent = + ModelVersionInfo linkModelVersionRequest = registerAndLinkModelPreEvent.linkModelVersionRequest(); - Assertions.assertEquals("uriA", modelVersionInfoPreEvent.uri()); - Assertions.assertTrue(modelVersionInfoPreEvent.aliases().isPresent()); - String[] aliases = modelVersionInfoPreEvent.aliases().get(); - Assertions.assertEquals(2, aliases.length); - Assertions.assertEquals("aliasProduction", aliases[0]); - Assertions.assertEquals("aliasTest", aliases[1]); + + Assertions.assertEquals(firstModelVersion.uri(), linkModelVersionRequest.uri()); + Assertions.assertEquals("commentA", linkModelVersionRequest.comment().orElse(null)); + checkArray(firstModelVersion.aliases(), linkModelVersionRequest.aliases().orElse(null)); + checkProperties(firstModelVersion.properties(), linkModelVersionRequest.properties()); + checkAudit(firstModelVersion.auditInfo(), linkModelVersionRequest.audit()); + } + + @Test + void testRegisterAndLinkModelFailureEvent() { + Assertions.assertThrowsExactly( + GravitinoRuntimeException.class, + () -> + failureDispatcher.registerModel( + existingIdentA, + "uriA", + new String[] {"aliasProduction"}, + "commentA", + ImmutableMap.of("color", "#FFFFFF"))); + + Event event = dummyEventListener.popPostEvent(); + + Assertions.assertEquals(RegisterAndLinkModelFailureEvent.class, event.getClass()); + Assertions.assertEquals(existingIdentA, event.identifier()); + Assertions.assertEquals( + GravitinoRuntimeException.class, + ((RegisterAndLinkModelFailureEvent) event).exception().getClass()); + Assertions.assertEquals(OperationType.REGISTER_AND_LINK_MODEL_VERSION, event.operationType()); + Assertions.assertEquals(OperationStatus.FAILURE, event.operationStatus()); + + // validate model info + RegisterAndLinkModelFailureEvent registerAndLinkModelFailureEvent = + (RegisterAndLinkModelFailureEvent) event; + ModelInfo registerModelRequest = registerAndLinkModelFailureEvent.registerModelRequest(); + ModelVersionInfo linkModelVersionRequest = + registerAndLinkModelFailureEvent.linkModelVersionRequest(); + + checkModelInfo(registerModelRequest, modelA); + Assertions.assertEquals(firstModelVersion.uri(), linkModelVersionRequest.uri()); + Assertions.assertEquals("commentA", linkModelVersionRequest.comment().orElse(null)); + checkArray(firstModelVersion.aliases(), linkModelVersionRequest.aliases().orElse(null)); + checkProperties(firstModelVersion.properties(), linkModelVersionRequest.properties()); + checkAudit(firstModelVersion.auditInfo(), linkModelVersionRequest.audit()); } @Test @@ -207,7 +258,24 @@ void testGetModelEvent() { } @Test - void testDeleteExistsModelEvent() { + void testGetModelFailureEvent() { + Assertions.assertThrowsExactly( + GravitinoRuntimeException.class, () -> failureDispatcher.getModel(notExistingIdent)); + + Event event = dummyEventListener.popPostEvent(); + + Assertions.assertEquals(GetModelFailureEvent.class, event.getClass()); + Assertions.assertEquals( + GravitinoRuntimeException.class, ((GetModelFailureEvent) event).exception().getClass()); + Assertions.assertEquals(OperationType.GET_MODEL, event.operationType()); + Assertions.assertEquals(OperationStatus.FAILURE, event.operationStatus()); + + GetModelFailureEvent getModelFailureEvent = (GetModelFailureEvent) event; + Assertions.assertEquals(notExistingIdent, getModelFailureEvent.identifier()); + } + + @Test + void testDeleteModelEvent() { dispatcher.deleteModel(existingIdentA); // validate pre-event @@ -220,6 +288,23 @@ void testDeleteExistsModelEvent() { Assertions.assertEquals(existingIdentA, deleteModelPreEvent.identifier()); } + @Test + void testDeleteModelFailureEvent() { + Assertions.assertThrowsExactly( + GravitinoRuntimeException.class, () -> failureDispatcher.deleteModel(notExistingIdent)); + + Event event = dummyEventListener.popPostEvent(); + + Assertions.assertEquals(DeleteModelFailureEvent.class, event.getClass()); + Assertions.assertEquals( + GravitinoRuntimeException.class, ((DeleteModelFailureEvent) event).exception().getClass()); + Assertions.assertEquals(OperationType.DELETE_MODEL, event.operationType()); + Assertions.assertEquals(OperationStatus.FAILURE, event.operationStatus()); + + DeleteModelFailureEvent deleteModelFailureEvent = (DeleteModelFailureEvent) event; + Assertions.assertEquals(notExistingIdent, deleteModelFailureEvent.identifier()); + } + @Test void testListModelEvent() { dispatcher.listModels(namespace); @@ -234,12 +319,29 @@ void testListModelEvent() { Assertions.assertEquals(namespace, listModelPreEvent.namespace()); } + @Test + void testListModelFailureEvent() { + Assertions.assertThrowsExactly( + GravitinoRuntimeException.class, () -> failureDispatcher.listModels(namespace)); + + Event event = dummyEventListener.popPostEvent(); + + Assertions.assertEquals(ListModelFailureEvent.class, event.getClass()); + Assertions.assertEquals( + GravitinoRuntimeException.class, ((ListModelFailureEvent) event).exception().getClass()); + Assertions.assertEquals(OperationType.LIST_MODEL, event.operationType()); + Assertions.assertEquals(OperationStatus.FAILURE, event.operationStatus()); + + ListModelFailureEvent listModelFailureEvent = (ListModelFailureEvent) event; + checkArray(namespace.levels(), listModelFailureEvent.namespace().levels()); + } + @Test void testLinkModelVersionEvent() { dispatcher.linkModelVersion( existingIdentA, "uriA", - new String[] {"aliasProduction", "aliasTest"}, + new String[] {"aliasProduction"}, "versionInfoA", ImmutableMap.of("color", "#FFFFFF")); @@ -253,21 +355,35 @@ void testLinkModelVersionEvent() { Assertions.assertEquals(existingIdentA, linkModelVersionPreEvent.identifier()); ModelVersionInfo modelVersionInfo = linkModelVersionPreEvent.linkModelVersionRequest(); - Assertions.assertEquals(1, modelVersionInfo.properties().size()); - Assertions.assertEquals("#FFFFFF", modelVersionInfo.properties().get("color")); + checkModelVersionInfo(modelVersionInfo, firstModelVersion); + } - Assertions.assertEquals("uriA", modelVersionInfo.uri()); - Assertions.assertTrue(modelVersionInfo.aliases().isPresent()); - String[] aliases = modelVersionInfo.aliases().get(); - Assertions.assertEquals(2, aliases.length); - Assertions.assertEquals("aliasProduction", aliases[0]); - Assertions.assertEquals("aliasTest", aliases[1]); + @Test + void testLinkModelVersionFailureEvent() { + Assertions.assertThrowsExactly( + GravitinoRuntimeException.class, + () -> + failureDispatcher.linkModelVersion( + existingIdentA, + "uriA", + new String[] {"aliasProduction"}, + "versionInfoA", + ImmutableMap.of("color", "#FFFFFF"))); + + Event event = dummyEventListener.popPostEvent(); + + Assertions.assertEquals(LinkModelVersionFailureEvent.class, event.getClass()); + Assertions.assertEquals( + GravitinoRuntimeException.class, + ((LinkModelVersionFailureEvent) event).exception().getClass()); + Assertions.assertEquals(OperationType.LINK_MODEL_VERSION, event.operationType()); + Assertions.assertEquals(OperationStatus.FAILURE, event.operationStatus()); - Assertions.assertTrue(modelVersionInfo.comment().isPresent()); - String comment = modelVersionInfo.comment().get(); - Assertions.assertEquals("versionInfoA", comment); + LinkModelVersionFailureEvent linkModelVersionFailureEvent = + (LinkModelVersionFailureEvent) event; + ModelVersionInfo modelVersionInfo = linkModelVersionFailureEvent.linkModelVersionRequest(); - Assertions.assertFalse(modelVersionInfo.audit().isPresent()); + checkModelVersionInfo(modelVersionInfo, firstModelVersion); } @Test @@ -282,6 +398,32 @@ void testGetModelVersionEventViaVersion() { GetModelVersionPreEvent getModelVersionPreEvent = (GetModelVersionPreEvent) preEvent; Assertions.assertEquals(existingIdentA, getModelVersionPreEvent.identifier()); + + // validate pre-event fields + Assertions.assertTrue(getModelVersionPreEvent.version().isPresent()); + Assertions.assertEquals(1, getModelVersionPreEvent.version().get()); + Assertions.assertFalse(getModelVersionPreEvent.alias().isPresent()); + } + + @Test + void testGetModelVersionFailureEventViaVersion() { + Assertions.assertThrowsExactly( + GravitinoRuntimeException.class, + () -> failureDispatcher.getModelVersion(existingIdentA, 3)); + + Event event = dummyEventListener.popPostEvent(); + + Assertions.assertEquals(GetModelVersionFailureEvent.class, event.getClass()); + Assertions.assertEquals( + GravitinoRuntimeException.class, + ((GetModelVersionFailureEvent) event).exception().getClass()); + Assertions.assertEquals(OperationType.GET_MODEL_VERSION, event.operationType()); + Assertions.assertEquals(OperationStatus.FAILURE, event.operationStatus()); + + GetModelVersionFailureEvent getModelVersionFailureEvent = (GetModelVersionFailureEvent) event; + Assertions.assertTrue(getModelVersionFailureEvent.version().isPresent()); + Assertions.assertEquals(3, getModelVersionFailureEvent.version().get()); + Assertions.assertFalse(getModelVersionFailureEvent.alias().isPresent()); } @Test @@ -294,6 +436,7 @@ void testGetModelVersionEventViaAlias() { Assertions.assertEquals(OperationType.GET_MODEL_VERSION, preEvent.operationType()); Assertions.assertEquals(OperationStatus.UNPROCESSED, preEvent.operationStatus()); + // validate pre-event fields GetModelVersionPreEvent getModelVersionPreEvent = (GetModelVersionPreEvent) preEvent; Assertions.assertEquals(existingIdentB, getModelVersionPreEvent.identifier()); Assertions.assertTrue(getModelVersionPreEvent.alias().isPresent()); @@ -301,6 +444,27 @@ void testGetModelVersionEventViaAlias() { Assertions.assertFalse(getModelVersionPreEvent.version().isPresent()); } + @Test + void testGetModelVersionFailureEventViaAlias() { + Assertions.assertThrowsExactly( + GravitinoRuntimeException.class, + () -> failureDispatcher.getModelVersion(existingIdentB, "aliasNotExist")); + + Event event = dummyEventListener.popPostEvent(); + + Assertions.assertEquals(GetModelVersionFailureEvent.class, event.getClass()); + Assertions.assertEquals( + GravitinoRuntimeException.class, + ((GetModelVersionFailureEvent) event).exception().getClass()); + Assertions.assertEquals(OperationType.GET_MODEL_VERSION, event.operationType()); + Assertions.assertEquals(OperationStatus.FAILURE, event.operationStatus()); + + GetModelVersionFailureEvent getModelVersionFailureEvent = (GetModelVersionFailureEvent) event; + Assertions.assertTrue(getModelVersionFailureEvent.alias().isPresent()); + Assertions.assertEquals("aliasNotExist", getModelVersionFailureEvent.alias().get()); + Assertions.assertFalse(getModelVersionFailureEvent.version().isPresent()); + } + @Test void testDeleteModelVersionEventViaVersion() { dispatcher.deleteModelVersion(existingIdentA, 1); @@ -318,6 +482,28 @@ void testDeleteModelVersionEventViaVersion() { Assertions.assertFalse(deleteModelVersionPreEvent.alias().isPresent()); } + @Test + void testDeleteModelVersionFailureEventViaVersion() { + Assertions.assertThrowsExactly( + GravitinoRuntimeException.class, + () -> failureDispatcher.deleteModelVersion(existingIdentA, 3)); + + Event event = dummyEventListener.popPostEvent(); + + Assertions.assertEquals(DeleteModelVersionFailureEvent.class, event.getClass()); + Assertions.assertEquals( + GravitinoRuntimeException.class, + ((DeleteModelVersionFailureEvent) event).exception().getClass()); + Assertions.assertEquals(OperationType.DELETE_MODEL_VERSION, event.operationType()); + Assertions.assertEquals(OperationStatus.FAILURE, event.operationStatus()); + + DeleteModelVersionFailureEvent deleteModelVersionFailureEvent = + (DeleteModelVersionFailureEvent) event; + Assertions.assertTrue(deleteModelVersionFailureEvent.version().isPresent()); + Assertions.assertEquals(3, deleteModelVersionFailureEvent.version().get()); + Assertions.assertFalse(deleteModelVersionFailureEvent.alias().isPresent()); + } + @Test void testDeleteModelVersionEventViaAlias() { dispatcher.deleteModelVersion(existingIdentB, "aliasTest"); @@ -335,6 +521,28 @@ void testDeleteModelVersionEventViaAlias() { Assertions.assertFalse(deleteModelVersionPreEvent.version().isPresent()); } + @Test + void testDeleteModelVersionFailureEventViaAlias() { + Assertions.assertThrowsExactly( + GravitinoRuntimeException.class, + () -> failureDispatcher.deleteModelVersion(existingIdentB, "aliasNotExist")); + + Event event = dummyEventListener.popPostEvent(); + + Assertions.assertEquals(DeleteModelVersionFailureEvent.class, event.getClass()); + Assertions.assertEquals( + GravitinoRuntimeException.class, + ((DeleteModelVersionFailureEvent) event).exception().getClass()); + Assertions.assertEquals(OperationType.DELETE_MODEL_VERSION, event.operationType()); + Assertions.assertEquals(OperationStatus.FAILURE, event.operationStatus()); + + DeleteModelVersionFailureEvent deleteModelVersionFailureEvent = + (DeleteModelVersionFailureEvent) event; + Assertions.assertTrue(deleteModelVersionFailureEvent.alias().isPresent()); + Assertions.assertEquals("aliasNotExist", deleteModelVersionFailureEvent.alias().get()); + Assertions.assertFalse(deleteModelVersionFailureEvent.version().isPresent()); + } + @Test void testListModelVersionsEvent() { dispatcher.listModelVersions(existingIdentA); @@ -349,6 +557,25 @@ void testListModelVersionsEvent() { Assertions.assertEquals(existingIdentA, listModelVersionsPreEvent.identifier()); } + @Test + void testListModelVersionsFailureEvent() { + Assertions.assertThrowsExactly( + GravitinoRuntimeException.class, () -> failureDispatcher.listModelVersions(existingIdentA)); + + Event event = dummyEventListener.popPostEvent(); + + Assertions.assertEquals(ListModelVersionFailureEvent.class, event.getClass()); + Assertions.assertEquals( + GravitinoRuntimeException.class, + ((ListModelVersionFailureEvent) event).exception().getClass()); + Assertions.assertEquals(OperationType.LIST_MODEL_VERSIONS, event.operationType()); + Assertions.assertEquals(OperationStatus.FAILURE, event.operationStatus()); + + ListModelVersionFailureEvent listModelVersionsFailureEvent = + (ListModelVersionFailureEvent) event; + Assertions.assertEquals(existingIdentA, listModelVersionsFailureEvent.identifier()); + } + private ModelDispatcher mockExceptionModelDispatcher() { return mock( ModelDispatcher.class, @@ -419,9 +646,80 @@ private ModelVersion mockModelVersion(String uri, String[] aliases, String comme when(modelVersion.version()).thenReturn(1); when(modelVersion.uri()).thenReturn(uri); when(modelVersion.aliases()).thenReturn(aliases); - when(modelVersion.comment()).thenReturn("model version " + comment); + when(modelVersion.comment()).thenReturn(comment); when(modelVersion.properties()).thenReturn(ImmutableMap.of("color", "#FFFFFF")); return modelVersion; } + + private ModelVersion getMockModelWithAudit(String uri, String[] aliases, String comment) { + ModelVersion modelVersion = mockModelVersion(uri, aliases, comment); + Audit mockAudit = mock(Audit.class); + + when(mockAudit.creator()).thenReturn("demo_user"); + when(mockAudit.createTime()).thenReturn(Instant.ofEpochMilli(1611111111111L)); + when(mockAudit.lastModifier()).thenReturn("demo_user"); + when(mockAudit.lastModifiedTime()).thenReturn(Instant.ofEpochMilli(1611111111111L)); + when(modelVersion.auditInfo()).thenReturn(mockAudit); + + return modelVersion; + } + + private void checkModelInfo(ModelInfo modelInfo, Model model) { + // check normal fields + Assertions.assertEquals(model.name(), modelInfo.name()); + Assertions.assertEquals(model.comment(), modelInfo.comment().orElse(null)); + + // check properties + checkProperties(model.properties(), modelInfo.properties()); + + // check audit + checkAudit(model.auditInfo(), modelInfo.audit()); + } + + private void checkModelVersionInfo(ModelVersionInfo modelVersionInfo, ModelVersion modelVersion) { + // check normal fields + Assertions.assertEquals(modelVersion.uri(), modelVersionInfo.uri()); + Assertions.assertEquals(modelVersion.comment(), modelVersionInfo.comment().orElse(null)); + + // check aliases + checkArray(modelVersion.aliases(), modelVersionInfo.aliases().orElse(null)); + + // check properties + checkProperties(modelVersion.properties(), modelVersionInfo.properties()); + + // check audit + checkAudit(modelVersion.auditInfo(), modelVersionInfo.audit()); + } + + private void checkProperties( + Map expectedProperties, Map properties) { + Assertions.assertEquals(expectedProperties.size(), properties.size()); + expectedProperties.forEach( + (key, value) -> { + Assertions.assertTrue(properties.containsKey(key)); + Assertions.assertEquals(value, properties.get(key)); + }); + } + + private void checkAudit(Audit expectedAudit, Optional audit) { + if (expectedAudit == null) { + Assertions.assertFalse(audit.isPresent()); + return; + } + + Assertions.assertTrue(audit.isPresent()); + Audit auditInfo = audit.get(); + + Assertions.assertEquals(auditInfo.creator(), auditInfo.creator()); + Assertions.assertEquals(auditInfo.createTime(), auditInfo.createTime()); + Assertions.assertEquals(auditInfo.lastModifier(), auditInfo.lastModifier()); + Assertions.assertEquals(auditInfo.lastModifiedTime(), auditInfo.lastModifiedTime()); + } + + private void checkArray(String[] expected, String[] actual) { + Assertions.assertNotNull(actual); + Assertions.assertEquals(expected.length, actual.length); + Assertions.assertArrayEquals(expected, actual); + } } diff --git a/docs/gravitino-server-config.md b/docs/gravitino-server-config.md index 3f30c2f2c27..5cb4de6b6ab 100644 --- a/docs/gravitino-server-config.md +++ b/docs/gravitino-server-config.md @@ -126,6 +126,7 @@ Gravitino triggers a pre-event before the operation, a post-event after the comp | metalake operation | `CreateMetalakeEvent`, `AlterMetalakeEvent`, `DropMetalakeEvent`, `LoadMetalakeEvent`, `ListMetalakeEvent`, `CreateMetalakeFailureEvent`, `AlterMetalakeFailureEvent`, `DropMetalakeFailureEvent`, `LoadMetalakeFailureEvent`, `ListMetalakeFailureEvent` | 0.5.0 | | Iceberg REST server table operation | `IcebergCreateTableEvent`, `IcebergUpdateTableEvent`, `IcebergDropTableEvent`, `IcebergLoadTableEvent`, `IcebergListTableEvent`, `IcebergTableExistsEvent`, `IcebergRenameTableEvent`, `IcebergCreateTableFailureEvent`, `IcebergUpdateTableFailureEvent`, `IcebergDropTableFailureEvent`, `IcebergLoadTableFailureEvent`, `IcebergListTableFailureEvent`, `IcebergRenameTableFailureEvent`, `IcebergTableExistsFailureEvent` | 0.7.0-incubating | | tag operation | `ListTagsEvent`, `ListTagsInfoEvent`, `CreateTagEvent`, `GetTagEvent`, `AlterTagEvent`, `DeleteTagEvent`, `ListMetadataObjectsForTagEvent`, `ListTagsForMetadataObjectEvent`, `ListTagsInfoForMetadataObjectEvent`, `AssociateTagsForMetadataObjectEvent`, `GetTagForMetadataObjectEvent`, `ListTagsFailureEvent`, `ListTagInfoFailureEvent`, `CreateTagFailureEvent`, `GetTagFailureEvent`, `AlterTagFailureEvent`, `DeleteTagFailureEvent`, `ListMetadataObjectsForTagFailureEvent`, `ListTagsForMetadataObjectFailureEvent`, `ListTagsInfoForMetadataObjectFailureEvent`, `AssociateTagsForMetadataObjectFailureEvent`, `GetTagForMetadataObjectFailureEvent` | 0.9.0-incubating | +| model operation | `DeleteModelFailureEvent`, `DeleteModelVersionFailureEvent`, `GetModelFailureEvent`, `GetModelVersionFailureEvent`, `LinkModelVersionFailureEvent`, `ListModelFailureEvent`, `ListModelVersionFailureEvent`, `RegisterAndLinkModelFailureEvent`, `RegisterModelFailureEvent` | 0.9.0-incubating | ##### Pre-event