From 559bd90c0e4324d24bc7354a470e23d49e4e6d60 Mon Sep 17 00:00:00 2001 From: pancx Date: Tue, 7 Jan 2025 15:15:51 +0800 Subject: [PATCH 1/7] [#6078] feat(core): Support model event to Gravitino server Support model event to Gravitino server. Add list, get, create and delete events to both model and model version. --- .../listener/api/event/DropModelEvent.java | 75 +++++++++++++++ .../api/event/DropModelVersionEvent.java | 78 +++++++++++++++ .../listener/api/event/GetModelEvent.java | 60 ++++++++++++ .../api/event/GetModelVersionEvent.java | 61 ++++++++++++ .../api/event/LinkModelVersionEvent.java | 63 ++++++++++++ .../listener/api/event/ListModelEvent.java | 65 +++++++++++++ .../api/event/ListModelVersionsEvent.java | 63 ++++++++++++ .../listener/api/event/ModelEvent.java | 50 ++++++++++ .../listener/api/event/OperationType.java | 12 +++ .../api/event/RegisterModelEvent.java | 63 ++++++++++++ .../listener/api/info/ModelInfo.java | 96 +++++++++++++++++++ .../listener/api/event/TestModelEvent.java | 32 +++++++ 12 files changed, 718 insertions(+) create mode 100644 core/src/main/java/org/apache/gravitino/listener/api/event/DropModelEvent.java create mode 100644 core/src/main/java/org/apache/gravitino/listener/api/event/DropModelVersionEvent.java create mode 100644 core/src/main/java/org/apache/gravitino/listener/api/event/GetModelEvent.java create mode 100644 core/src/main/java/org/apache/gravitino/listener/api/event/GetModelVersionEvent.java create mode 100644 core/src/main/java/org/apache/gravitino/listener/api/event/LinkModelVersionEvent.java create mode 100644 core/src/main/java/org/apache/gravitino/listener/api/event/ListModelEvent.java create mode 100644 core/src/main/java/org/apache/gravitino/listener/api/event/ListModelVersionsEvent.java create mode 100644 core/src/main/java/org/apache/gravitino/listener/api/event/ModelEvent.java create mode 100644 core/src/main/java/org/apache/gravitino/listener/api/event/RegisterModelEvent.java create mode 100644 core/src/main/java/org/apache/gravitino/listener/api/info/ModelInfo.java create mode 100644 core/src/test/java/org/apache/gravitino/listener/api/event/TestModelEvent.java diff --git a/core/src/main/java/org/apache/gravitino/listener/api/event/DropModelEvent.java b/core/src/main/java/org/apache/gravitino/listener/api/event/DropModelEvent.java new file mode 100644 index 00000000000..5a063ea0ee6 --- /dev/null +++ b/core/src/main/java/org/apache/gravitino/listener/api/event/DropModelEvent.java @@ -0,0 +1,75 @@ +/* + * 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.listener.api.info.ModelInfo; + +/** Event representing the successful drop of a model. */ +public class DropModelEvent extends ModelEvent { + private final ModelInfo dropModelInfo; + private final boolean isExists; + + /** + * Constructs an instance of {@code DropModelEvent}, capturing essential details about the + * successful drop of a model. + * + * @param user The username of the individual who initiated the model drop operation. + * @param identifier The unique identifier of the model that was dropped. + * @param dropModelInfo The state of the model post-drop operation. + * @param isExists A boolean flag indicating whether the model existed at the time of the drop + * operation. + */ + public DropModelEvent( + String user, NameIdentifier identifier, ModelInfo dropModelInfo, boolean isExists) { + super(user, identifier); + this.dropModelInfo = dropModelInfo; + this.isExists = isExists; + } + + /** + * Retrieves the state of the model post-drop operation. + * + * @return The state of the model post-drop operation. + */ + public ModelInfo DropModelInfo() { + return dropModelInfo; + } + + /** + * Retrieves the existence status of the model at the time of the drop operation. + * + * @return A boolean value indicating whether the model existed. {@code true} if the model + * existed, otherwise {@code false}. + */ + public boolean isExists() { + return isExists; + } + + /** + * Returns the type of operation. + * + * @return the operation type. + */ + @Override + public OperationType operationType() { + return OperationType.DROP_MODEL; + } +} diff --git a/core/src/main/java/org/apache/gravitino/listener/api/event/DropModelVersionEvent.java b/core/src/main/java/org/apache/gravitino/listener/api/event/DropModelVersionEvent.java new file mode 100644 index 00000000000..d329a2ef676 --- /dev/null +++ b/core/src/main/java/org/apache/gravitino/listener/api/event/DropModelVersionEvent.java @@ -0,0 +1,78 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.gravitino.listener.api.event; + +import org.apache.gravitino.NameIdentifier; +import org.apache.gravitino.listener.api.info.ModelInfo; + +/** + * Represents an event that is generated after a model version is successfully dropped from the + * model. + */ +public class DropModelVersionEvent extends ModelEvent { + + private final ModelInfo dropModelVersionInfo; + private final boolean isExists; + + /** + * Constructs a new {@code DropModelVersionEvent} instance, encapsulating information about the + * outcome of a model version drop operation. + * + * @param user The user who initiated the drop model version operation. + * @param identifier The identifier of the model that was attempted to be dropped a version. + * @param isExists A boolean flag indicating whether the model version existed at the time of the + * drop operation. + */ + public DropModelVersionEvent( + String user, NameIdentifier identifier, ModelInfo dropModelVersionInfo, boolean isExists) { + super(user, identifier); + this.dropModelVersionInfo = dropModelVersionInfo; + this.isExists = isExists; + } + + /** + * Retrieves the state of the model after the drop version operation. + * + * @return The state of the model after the drop version operation. + */ + public ModelInfo DropModelVersionInfo() { + return dropModelVersionInfo; + } + + /** + * Retrieves the existence status of the model version at the time of the drop operation. + * + * @return A boolean value indicating whether the model version existed. {@code true} if the table + * existed, otherwise {@code false}. + */ + public boolean isExists() { + return isExists; + } + + /** + * Returns the type of operation. + * + * @return the operation type. + */ + @Override + public OperationType operationType() { + return OperationType.DROP_MODEL_VERSION; + } +} diff --git a/core/src/main/java/org/apache/gravitino/listener/api/event/GetModelEvent.java b/core/src/main/java/org/apache/gravitino/listener/api/event/GetModelEvent.java new file mode 100644 index 00000000000..fd10fc5afad --- /dev/null +++ b/core/src/main/java/org/apache/gravitino/listener/api/event/GetModelEvent.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; + +import org.apache.gravitino.NameIdentifier; +import org.apache.gravitino.listener.api.info.ModelInfo; + +/** Represents an event triggered upon the successful getting of a model. */ +public class GetModelEvent extends ModelEvent { + private final ModelInfo modelInfo; + + /** + * Constructs an instance of {@code GetModelEvent}, capturing essential details about the + * successful getting of a model. + * + * @param user The username of the individual who initiated the model get. + * @param identifier The unique identifier of the model that was get. + * @param modelInfo The state of the model post-get. + */ + public GetModelEvent(String user, NameIdentifier identifier, ModelInfo modelInfo) { + super(user, identifier); + this.modelInfo = modelInfo; + } + + /** + * Retrieves the state of the model as it was made available to the user after successful getting. + * + * @return A {@link ModelInfo} instance encapsulating the details of the model as get. + */ + public ModelInfo getModelInfo() { + return modelInfo; + } + + /** + * 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/GetModelVersionEvent.java b/core/src/main/java/org/apache/gravitino/listener/api/event/GetModelVersionEvent.java new file mode 100644 index 00000000000..b8519c38edf --- /dev/null +++ b/core/src/main/java/org/apache/gravitino/listener/api/event/GetModelVersionEvent.java @@ -0,0 +1,61 @@ +/* + * 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.listener.api.info.ModelInfo; + +/** Represents an event triggered upon the successful getting the version of a model. */ +public class GetModelVersionEvent extends ModelEvent { + public final ModelInfo GetModelVersionInfo; + + /** + * Constructs an instance of {@code GetModelVersionEvent}. + * + * @param user The username of the individual who initiated the get model version event. + * @param identifier The unique identifier of the model that was getting the version. + * @param getModelVersionInfo The state of the model after the version was loaded. + */ + public GetModelVersionEvent( + String user, NameIdentifier identifier, ModelInfo getModelVersionInfo) { + super(user, identifier); + GetModelVersionInfo = getModelVersionInfo; + } + + /** + * Retrieves the state of the model as it was made available to the user after successful getting + * the version. + * + * @return A {@link ModelInfo} instance encapsulating the details of the model version. + */ + public ModelInfo getModelVersionInfo() { + return GetModelVersionInfo; + } + + /** + * 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/LinkModelVersionEvent.java b/core/src/main/java/org/apache/gravitino/listener/api/event/LinkModelVersionEvent.java new file mode 100644 index 00000000000..17eae5d5de0 --- /dev/null +++ b/core/src/main/java/org/apache/gravitino/listener/api/event/LinkModelVersionEvent.java @@ -0,0 +1,63 @@ +/* + * 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.listener.api.info.ModelInfo; + +/** Represents an event triggered upon the successful linking of a model version. */ +public class LinkModelVersionEvent extends ModelEvent { + private ModelInfo linkModelVersionInfo; + + /** + * Constructs an instance of {@code LinkModelVersionEvent}, capturing essential details about the + * successful linking of a model version. + * + * @param user The username of the individual who initiated the model version linking. + * @param identifier The unique identifier of the model that was linked. + * @param linkModelVersionInfo The final state of the model after linking. + */ + public LinkModelVersionEvent( + String user, NameIdentifier identifier, ModelInfo linkModelVersionInfo) { + super(user, identifier); + this.linkModelVersionInfo = linkModelVersionInfo; + } + + /** + * Retrieves the final state of the model, as it was returned to the user after successful link a + * model version. + * + * @return A {@link ModelInfo} instance encapsulating the comprehensive details of the newly model + * version. + */ + public ModelInfo linkModelVersionInfo() { + return linkModelVersionInfo; + } + + /** + * 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/ListModelEvent.java b/core/src/main/java/org/apache/gravitino/listener/api/event/ListModelEvent.java new file mode 100644 index 00000000000..cf430e9c6e0 --- /dev/null +++ b/core/src/main/java/org/apache/gravitino/listener/api/event/ListModelEvent.java @@ -0,0 +1,65 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.gravitino.listener.api.event; + +import org.apache.gravitino.NameIdentifier; +import org.apache.gravitino.Namespace; + +/** + * Represents an event that is triggered upon the successful list of models within a namespace. + * + *

To optimize memory usage and avoid the potential overhead associated with storing a large + * number of tables directly within the ListTableEvent, the actual tables listed are not maintained + * in this event. This design decision helps in managing resource efficiency, especially in + * environments with extensive table listings. + */ +public class ListModelEvent extends ModelEvent { + private final Namespace namespace; + + /** + * Constructs an instance of {@code ListTableEvent}. + * + * @param user The username of the individual who initiated the model listing. + * @param namespace The namespace from which models were listed. + */ + public ListModelEvent(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 models were listed. + */ + 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/ListModelVersionsEvent.java b/core/src/main/java/org/apache/gravitino/listener/api/event/ListModelVersionsEvent.java new file mode 100644 index 00000000000..5892b2d73ea --- /dev/null +++ b/core/src/main/java/org/apache/gravitino/listener/api/event/ListModelVersionsEvent.java @@ -0,0 +1,63 @@ +/* + * 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.listener.api.info.ModelInfo; + +/** + * Represents an event that is triggered upon the successful list of model versions within a model. + */ +public class ListModelVersionsEvent extends ModelEvent { + + private final ModelInfo listModelVersionInfo; + + /** + * Constructs an instance of {@code ListModelVersionsEvent}. + * + * @param user The username of the individual who initiated the model version listing. + * @param identifier The unique identifier of the model that it's version was listed. + * @param listModelVersionInfo The model information containing the list of model versions. + */ + public ListModelVersionsEvent( + String user, NameIdentifier identifier, ModelInfo listModelVersionInfo) { + super(user, identifier); + this.listModelVersionInfo = listModelVersionInfo; + } + + /** + * Retrieves the model information containing the list of model versions. + * + * @return A {@link ModelInfo} instance containing the list of model versions. + */ + public ModelInfo listModelVersionInfo() { + return listModelVersionInfo; + } + + /** + * 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/ModelEvent.java b/core/src/main/java/org/apache/gravitino/listener/api/event/ModelEvent.java new file mode 100644 index 00000000000..fff03355c76 --- /dev/null +++ b/core/src/main/java/org/apache/gravitino/listener/api/event/ModelEvent.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; + +/** + * Represents an abstract base class for events related to Model operations. This class extends + * {@link Event} to provide a more specific context involving operations on Models, such as link, + * register, or modification. It captures essential information including the user performing the + * operation and the identifier of the model being operated on. + * + *

Concrete implementations of this class should provide additional details pertinent to the + * specific type of model operation being represented. + */ +public abstract class ModelEvent extends Event { + + /** + * Constructs a new ModelEvent with the specified user and model identifier. + * + * @param user The user responsible for triggering the model operation. + * @param identifier The identifier of the Model involved in the operation. This encapsulates + * details such as the metalake, catalog, schema, and Model name. + */ + protected ModelEvent(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/OperationType.java b/core/src/main/java/org/apache/gravitino/listener/api/event/OperationType.java index 515e63a7c30..0585984665f 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 @@ -99,5 +99,17 @@ public enum OperationType { RENAME_VIEW, LIST_VIEW, + // Model event + REGISTER_MODEL, + DROP_MODEL, + GET_MODEL, + LIST_MODEL, + + // Model Version + LINK_MODEL_VERSION, + DROP_MODEL_VERSION, + GET_MODEL_VERSION, + LIST_MODEL_VERSIONS, + UNKNOWN, } diff --git a/core/src/main/java/org/apache/gravitino/listener/api/event/RegisterModelEvent.java b/core/src/main/java/org/apache/gravitino/listener/api/event/RegisterModelEvent.java new file mode 100644 index 00000000000..feeb1a1dfdf --- /dev/null +++ b/core/src/main/java/org/apache/gravitino/listener/api/event/RegisterModelEvent.java @@ -0,0 +1,63 @@ +/* + * 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.listener.api.info.ModelInfo; + +/** Represents an event triggered upon the successful registration of a model. */ +public class RegisterModelEvent extends ModelEvent { + private final ModelInfo registeredTopicInfo; + + /** + * Constructs an instance of RegisterModelEvent, capturing essential details about the successful + * registration of a model. + * + * @param user The user responsible for triggering the model operation. + * @param identifier The identifier of the Model involved in the operation. This encapsulates + * details such as the metalake, catalog, schema, and Model name. + * @param registeredTopicInfo The final state of the model post-creation. + */ + protected RegisterModelEvent( + String user, NameIdentifier identifier, ModelInfo registeredTopicInfo) { + super(user, identifier); + this.registeredTopicInfo = registeredTopicInfo; + } + + /** + * Retrieves the final state of the model as it was returned to the user after successful + * registration. + * + * @return the model information. + */ + public ModelInfo registeredModelInfo() { + return registeredTopicInfo; + } + + /** + * 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 new file mode 100644 index 00000000000..5d271c2347e --- /dev/null +++ b/core/src/main/java/org/apache/gravitino/listener/api/info/ModelInfo.java @@ -0,0 +1,96 @@ +/* + * 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.Map; +import javax.annotation.Nullable; +import lombok.Getter; +import org.apache.gravitino.Audit; +import org.apache.gravitino.annotation.DeveloperApi; +import org.apache.gravitino.model.Model; +import org.apache.gravitino.model.ModelVersion; + +/** + * ModelInfo exposes model information for event listener, it's supposed to be read only. Most of + * the fields are shallow copied internally not deep copies for performance. + */ +@DeveloperApi +public class ModelInfo { + @Getter private final String name; + @Nullable private final String comment; + @Getter private final Map properties; + @Nullable private final Audit audit; + @Getter private final int lastVersion; + private final ModelVersion[] versions; + + /** + * Constructs model information based on a given model. + * + * @param model the model to expose information for. + */ + public ModelInfo(Model model) { + this(model, null); + } + + /** + * Constructs model information based on a given model and model versions. + * + * @param model the model to expose information for. + * @param modelVersion the versions of the model. + */ + public ModelInfo(Model model, ModelVersion[] modelVersion) { + this.name = model.name(); + this.properties = model.properties(); + this.comment = model.comment(); + this.audit = model.auditInfo(); + this.lastVersion = model.latestVersion(); + this.versions = modelVersion; + } + + /** + * Returns the comment of the model. + * + * @return the comment of the model or null if not set. + */ + @Nullable + public String getComment() { + return comment; + } + + /** + * Returns the audit information of the model. + * + * @return the audit information of the model or null if not set. + */ + @Nullable + public Audit getAudit() { + return audit; + } + + /** + * Returns the versions of the model. + * + * @return the versions of the model or null if not set. + */ + @Nullable + public ModelVersion[] getModelVersion() { + return versions; + } +} 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 new file mode 100644 index 00000000000..4638d22314d --- /dev/null +++ b/core/src/test/java/org/apache/gravitino/listener/api/event/TestModelEvent.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; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.TestInstance; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +public class TestModelEvent { + + @BeforeAll + void init() { + // TODO: Implement tests for ModelEvent + } +} From 596abb0dead7f7ece7c796d3d8521eefb8576336 Mon Sep 17 00:00:00 2001 From: pancx Date: Tue, 7 Jan 2025 15:20:10 +0800 Subject: [PATCH 2/7] [#6078] feat(core): Support model event to Gravitino server Fix some class comments. --- .../listener/api/event/DropModelVersionEvent.java | 4 ++-- .../gravitino/listener/api/event/ListModelEvent.java | 11 ++--------- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/core/src/main/java/org/apache/gravitino/listener/api/event/DropModelVersionEvent.java b/core/src/main/java/org/apache/gravitino/listener/api/event/DropModelVersionEvent.java index d329a2ef676..d7118565fac 100644 --- a/core/src/main/java/org/apache/gravitino/listener/api/event/DropModelVersionEvent.java +++ b/core/src/main/java/org/apache/gravitino/listener/api/event/DropModelVersionEvent.java @@ -59,8 +59,8 @@ public ModelInfo DropModelVersionInfo() { /** * Retrieves the existence status of the model version at the time of the drop operation. * - * @return A boolean value indicating whether the model version existed. {@code true} if the table - * existed, otherwise {@code false}. + * @return A boolean value indicating whether the model version existed. {@code true} if the model + * version existed, otherwise {@code false}. */ public boolean isExists() { return isExists; diff --git a/core/src/main/java/org/apache/gravitino/listener/api/event/ListModelEvent.java b/core/src/main/java/org/apache/gravitino/listener/api/event/ListModelEvent.java index cf430e9c6e0..b929532a8a8 100644 --- a/core/src/main/java/org/apache/gravitino/listener/api/event/ListModelEvent.java +++ b/core/src/main/java/org/apache/gravitino/listener/api/event/ListModelEvent.java @@ -22,19 +22,12 @@ import org.apache.gravitino.NameIdentifier; import org.apache.gravitino.Namespace; -/** - * Represents an event that is triggered upon the successful list of models within a namespace. - * - *

To optimize memory usage and avoid the potential overhead associated with storing a large - * number of tables directly within the ListTableEvent, the actual tables listed are not maintained - * in this event. This design decision helps in managing resource efficiency, especially in - * environments with extensive table listings. - */ +/** Represents an event that is triggered upon the successful list of models within a namespace. */ public class ListModelEvent extends ModelEvent { private final Namespace namespace; /** - * Constructs an instance of {@code ListTableEvent}. + * Constructs an instance of {@code ListModelEvent}. * * @param user The username of the individual who initiated the model listing. * @param namespace The namespace from which models were listed. From b85a34f8447a13ad9d66c2dde4b1343478bf0865 Mon Sep 17 00:00:00 2001 From: pancx Date: Thu, 9 Jan 2025 09:35:33 +0800 Subject: [PATCH 3/7] [#6078] feat(core): Support model event to Gravitino server Fix some error. --- .../gravitino/listener/api/event/GetModelVersionEvent.java | 6 +++--- .../org/apache/gravitino/listener/api/info/ModelInfo.java | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/core/src/main/java/org/apache/gravitino/listener/api/event/GetModelVersionEvent.java b/core/src/main/java/org/apache/gravitino/listener/api/event/GetModelVersionEvent.java index b8519c38edf..527fdd485e9 100644 --- a/core/src/main/java/org/apache/gravitino/listener/api/event/GetModelVersionEvent.java +++ b/core/src/main/java/org/apache/gravitino/listener/api/event/GetModelVersionEvent.java @@ -24,7 +24,7 @@ /** Represents an event triggered upon the successful getting the version of a model. */ public class GetModelVersionEvent extends ModelEvent { - public final ModelInfo GetModelVersionInfo; + public final ModelInfo getModelVersionInfo; /** * Constructs an instance of {@code GetModelVersionEvent}. @@ -36,7 +36,7 @@ public class GetModelVersionEvent extends ModelEvent { public GetModelVersionEvent( String user, NameIdentifier identifier, ModelInfo getModelVersionInfo) { super(user, identifier); - GetModelVersionInfo = getModelVersionInfo; + this.getModelVersionInfo = getModelVersionInfo; } /** @@ -46,7 +46,7 @@ public GetModelVersionEvent( * @return A {@link ModelInfo} instance encapsulating the details of the model version. */ public ModelInfo getModelVersionInfo() { - return GetModelVersionInfo; + return getModelVersionInfo; } /** 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 5d271c2347e..c62dacc942c 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 @@ -53,15 +53,15 @@ public ModelInfo(Model model) { * Constructs model information based on a given model and model versions. * * @param model the model to expose information for. - * @param modelVersion the versions of the model. + * @param modelVersions the versions of the model. */ - public ModelInfo(Model model, ModelVersion[] modelVersion) { + public ModelInfo(Model model, ModelVersion[] modelVersions) { this.name = model.name(); this.properties = model.properties(); this.comment = model.comment(); this.audit = model.auditInfo(); this.lastVersion = model.latestVersion(); - this.versions = modelVersion; + this.versions = modelVersions; } /** From 6b672fe00877ebfcce3ea63975cd999983509a29 Mon Sep 17 00:00:00 2001 From: pancx Date: Tue, 14 Jan 2025 12:10:23 +0800 Subject: [PATCH 4/7] [#6078] feat(core): Support model event to Gravitino server Fix some error and add ModelEventDispatcher to Gravitino server. --- .../listener/ModelEventDispatcher.java | 400 ++++++++++++++++++ .../listener/api/event/DropModelEvent.java | 26 +- .../api/event/DropModelVersionEvent.java | 20 +- .../api/event/GetModelVersionEvent.java | 11 +- .../api/event/LinkModelVersionEvent.java | 11 +- .../api/event/ListModelVersionsEvent.java | 11 +- .../api/event/RegisterModelEvent.java | 3 +- .../listener/api/info/ModelInfo.java | 7 +- .../listener/api/info/ModelVersionInfo.java | 88 ++++ .../listener/api/event/TestModelEvent.java | 351 ++++++++++++++- 10 files changed, 874 insertions(+), 54 deletions(-) create mode 100644 core/src/main/java/org/apache/gravitino/listener/ModelEventDispatcher.java create mode 100644 core/src/main/java/org/apache/gravitino/listener/api/info/ModelVersionInfo.java diff --git a/core/src/main/java/org/apache/gravitino/listener/ModelEventDispatcher.java b/core/src/main/java/org/apache/gravitino/listener/ModelEventDispatcher.java new file mode 100644 index 00000000000..7e9b0ca7532 --- /dev/null +++ b/core/src/main/java/org/apache/gravitino/listener/ModelEventDispatcher.java @@ -0,0 +1,400 @@ +/* + * 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.Map; +import org.apache.gravitino.NameIdentifier; +import org.apache.gravitino.Namespace; +import org.apache.gravitino.catalog.ModelDispatcher; +import org.apache.gravitino.exceptions.ModelAlreadyExistsException; +import org.apache.gravitino.exceptions.ModelVersionAliasesAlreadyExistException; +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.DropModelEvent; +import org.apache.gravitino.listener.api.event.DropModelVersionEvent; +import org.apache.gravitino.listener.api.event.GetModelEvent; +import org.apache.gravitino.listener.api.event.GetModelVersionEvent; +import org.apache.gravitino.listener.api.event.LinkModelVersionEvent; +import org.apache.gravitino.listener.api.event.ListModelEvent; +import org.apache.gravitino.listener.api.event.ListModelVersionsEvent; +import org.apache.gravitino.listener.api.event.RegisterModelEvent; +import org.apache.gravitino.listener.api.info.ModelInfo; +import org.apache.gravitino.listener.api.info.ModelVersionInfo; +import org.apache.gravitino.model.Model; +import org.apache.gravitino.model.ModelCatalog; +import org.apache.gravitino.model.ModelVersion; +import org.apache.gravitino.utils.PrincipalUtils; + +/** + * {@code ModelEventDispatcher} is a decorator for {@link ModelDispatcher} that not only delegates + * model operations to the underlying catalog dispatcher but also dispatches corresponding events to + * an {@link org.apache.gravitino.listener.EventBus} after each operation is completed. This allows + * for event-driven workflows or monitoring of model operations. + */ +public class ModelEventDispatcher implements ModelDispatcher { + private final EventBus eventBus; + private final ModelDispatcher dispatcher; + + /** + * Constructs a {@link ModelEventDispatcher} with a specified EventBus and {@link + * ModelDispatcher}. + * + * @param eventBus The EventBus to which events will be dispatched. + * @param dispatcher The underlying {@link ModelDispatcher} that will perform the actual model + * operations. + */ + public ModelEventDispatcher(EventBus eventBus, ModelDispatcher dispatcher) { + this.eventBus = eventBus; + this.dispatcher = dispatcher; + } + + /** + * Register a model in the catalog if the model is not existed, otherwise the {@link + * ModelAlreadyExistsException} will be thrown. The {@link Model} object will be created when the + * model is registered, users can call {@link ModelCatalog#linkModelVersion(NameIdentifier, + * String, String[], String, Map)} to link the model version to the registered {@link Model}. + * + * @param ident The name identifier of the model. + * @param comment The comment of the model. The comment is optional and can be null. + * @param properties The properties of the model. The properties are optional and can be null or + * empty. + * @return The registered model object. + * @throws NoSuchSchemaException If the schema does not exist. + * @throws ModelAlreadyExistsException If the model already registered. + */ + @Override + public Model registerModel(NameIdentifier ident, String comment, Map properties) + throws NoSuchSchemaException, ModelAlreadyExistsException { + // TODO: preEvent + try { + Model model = dispatcher.registerModel(ident, comment, properties); + ModelInfo modelInfo = new ModelInfo(model); + eventBus.dispatchEvent( + new RegisterModelEvent(PrincipalUtils.getCurrentUserName(), ident, modelInfo)); + return model; + } catch (Exception e) { + // TODO: failureEvent + throw e; + } + } + + /** + * Register a model in the catalog if the model is not existed, otherwise the {@link + * ModelAlreadyExistsException} will be thrown. The {@link Model} object will be created when the + * model is registered, in the meantime, the model version (version 0) will also be created and + * linked to the registered model. + * + * @param ident The name identifier of the model. + * @param uri The model artifact URI. + * @param aliases The aliases of the model version. The aliases should be unique in this model, + * otherwise the {@link ModelVersionAliasesAlreadyExistException} will be thrown. The aliases + * are optional and can be empty. Also, be aware that the alias cannot be a number or a number + * string. + * @param comment The comment of the model. The comment is optional and can be null. + * @param properties The properties of the model. The properties are optional and can be null or + * empty. + * @return The registered model object. + * @throws NoSuchSchemaException If the schema does not exist when register a model. + * @throws ModelAlreadyExistsException If the model already registered. + * @throws ModelVersionAliasesAlreadyExistException If the aliases already exist in the model. + */ + @Override + public Model registerModel( + NameIdentifier ident, + String uri, + String[] aliases, + String comment, + Map properties) + throws NoSuchSchemaException, ModelAlreadyExistsException, + ModelVersionAliasesAlreadyExistException { + return dispatcher.registerModel(ident, uri, aliases, comment, properties); + } + + /** + * Get a model metadata by {@link NameIdentifier} from the catalog. + * + * @param ident A model identifier. + * @return The model metadata. + * @throws NoSuchModelException If the model does not exist. + */ + @Override + public Model getModel(NameIdentifier ident) throws NoSuchModelException { + // TODO: preEvent + try { + Model model = dispatcher.getModel(ident); + ModelInfo modelInfo = new ModelInfo(model); + eventBus.dispatchEvent( + new GetModelEvent(PrincipalUtils.getCurrentUserName(), ident, modelInfo)); + return model; + } catch (Exception e) { + // TODO: failureEvent + throw e; + } + } + + /** + * Delete the model from the catalog. If the model does not exist, return false. Otherwise, return + * true. The deletion of the model will also delete all the model versions linked to this model. + * + * @param ident The name identifier of the model. + * @return True if the model is deleted, false if the model does not exist. + */ + @Override + public boolean deleteModel(NameIdentifier ident) { + // TODO: preEvent + try { + boolean isExists = dispatcher.deleteModel(ident); + eventBus.dispatchEvent( + new DropModelEvent(PrincipalUtils.getCurrentUserName(), ident, isExists)); + return isExists; + } catch (Exception e) { + // TODO: failureEvent + throw e; + } + } + + /** + * List the models in a schema namespace from the catalog. + * + * @param namespace A schema namespace. + * @return An array of model identifiers in the namespace. + * @throws NoSuchModelException If the model does not exist. + */ + @Override + public NameIdentifier[] listModels(Namespace namespace) throws NoSuchSchemaException { + // TODO: preEvent + try { + NameIdentifier[] models = dispatcher.listModels(namespace); + eventBus.dispatchEvent(new ListModelEvent(PrincipalUtils.getCurrentUserName(), namespace)); + return models; + } catch (Exception e) { + // TODO: failureEvent + throw e; + } + } + + /** + * Link a new model version to the registered model object. The new model version will be added to + * the model object. If the model object does not exist, it will throw an exception. If the + * version alias already exists in the model, it will throw an exception. + * + * @param ident The name identifier of the model. + * @param uri The URI of the model version artifact. + * @param aliases The aliases of the model version. The aliases should be unique in this model, + * otherwise the {@link ModelVersionAliasesAlreadyExistException} will be thrown. The aliases + * are optional and can be empty. Also, be aware that the alias cannot be a number or a number + * string. + * @param comment The comment of the model version. The comment is optional and can be null. + * @param properties The properties of the model version. The properties are optional and can be + * null or empty. + * @throws NoSuchModelException If the model does not exist. + * @throws ModelVersionAliasesAlreadyExistException If the aliases already exist in the model. + */ + @Override + public void linkModelVersion( + NameIdentifier ident, + String uri, + String[] aliases, + String comment, + Map properties) + throws NoSuchModelException, ModelVersionAliasesAlreadyExistException { + // TODO: preEvent + try { + Model model = dispatcher.getModel(ident); + ModelVersionInfo modelVersionInfo = new ModelVersionInfo(uri, aliases, comment, properties); + ModelInfo modelInfo = new ModelInfo(model, new ModelVersionInfo[] {modelVersionInfo}); + dispatcher.linkModelVersion(ident, uri, aliases, comment, properties); + eventBus.dispatchEvent( + new LinkModelVersionEvent(PrincipalUtils.getCurrentUserName(), ident, modelInfo)); + } catch (Exception e) { + // TODO: failureEvent + throw e; + } + } + + /** + * Get a model version by the {@link NameIdentifier} and version number from the catalog. + * + * @param ident The name identifier of the model. + * @param version The version number of the model. + * @return The model version object. + * @throws NoSuchModelVersionException If the model version does not exist. + */ + @Override + public ModelVersion getModelVersion(NameIdentifier ident, int version) + throws NoSuchModelVersionException { + // TODO: preEvent + try { + ModelVersion modelVersion = dispatcher.getModelVersion(ident, version); + ModelInfo modelInfo = getModelInfo(ident, version); + eventBus.dispatchEvent( + new GetModelVersionEvent(PrincipalUtils.getCurrentUserName(), ident, modelInfo)); + return modelVersion; + } catch (Exception e) { + // TODO: failureEvent + throw e; + } + } + + /** + * Get a model version by the {@link NameIdentifier} and version alias from the catalog. + * + * @param ident The name identifier of the model. + * @param alias The version alias of the model. + * @return The model version object. + * @throws NoSuchModelVersionException If the model version does not exist. + */ + @Override + public ModelVersion getModelVersion(NameIdentifier ident, String alias) + throws NoSuchModelVersionException { + // TODO: preEvent + try { + ModelVersion modelVersion = dispatcher.getModelVersion(ident, alias); + ModelInfo modelInfo = getModelInfo(ident, alias); + eventBus.dispatchEvent( + new GetModelVersionEvent(PrincipalUtils.getCurrentUserName(), ident, modelInfo)); + return modelVersion; + } catch (Exception e) { + // TODO: failureEvent + throw e; + } + } + + /** + * Delete the model version by the {@link NameIdentifier} and version number. If the model version + * does not exist, return false. If the model version is deleted, return true. + * + * @param ident The name identifier of the model. + * @param version The version number of the model. + * @return True if the model version is deleted, false if the model version does not exist. + */ + @Override + public boolean deleteModelVersion(NameIdentifier ident, int version) { + // TODO: preEvent + try { + boolean isExists = dispatcher.deleteModelVersion(ident, version); + eventBus.dispatchEvent( + new DropModelVersionEvent(PrincipalUtils.getCurrentUserName(), ident, isExists)); + return isExists; + } catch (Exception e) { + // TODO: failureEvent + throw e; + } + } + + /** + * Delete the model version by the {@link NameIdentifier} and version alias. If the model version + * does not exist, return false. If the model version is deleted, return true. + * + * @param ident The name identifier of the model. + * @param alias The version alias of the model. + * @return True if the model version is deleted, false if the model version does not exist. + */ + @Override + public boolean deleteModelVersion(NameIdentifier ident, String alias) { + // TODO: preEvent + try { + boolean isExists = dispatcher.deleteModelVersion(ident, alias); + eventBus.dispatchEvent( + new DropModelVersionEvent(PrincipalUtils.getCurrentUserName(), ident, isExists)); + return isExists; + } catch (Exception e) { + // TODO: failureEvent + throw e; + } + } + + /** + * List all the versions of the register model by {@link NameIdentifier} in the catalog. + * + * @param ident The name identifier of the model. + * @return An array of version numbers of the model. + * @throws NoSuchModelException If the model does not exist. + */ + @Override + public int[] listModelVersions(NameIdentifier ident) throws NoSuchModelException { + // TODO: preEvent + try { + int[] versions = dispatcher.listModelVersions(ident); + Model model = dispatcher.getModel(ident); + ModelInfo modelInfo = new ModelInfo(model); + eventBus.dispatchEvent( + new ListModelVersionsEvent(PrincipalUtils.getCurrentUserName(), ident, modelInfo)); + return versions; + } catch (Exception e) { + // TODO: failureEvent + throw e; + } + } + + /** + * Check if a model exists using an {@link NameIdentifier} from the catalog. + * + * @param ident A model identifier. + * @return true If the model exists, false if the model does not exist. + */ + @Override + public boolean modelExists(NameIdentifier ident) { + return dispatcher.modelExists(ident); + } + + /** + * Check if the model version exists by the {@link NameIdentifier} and version number. If the + * model version exists, return true, otherwise return false. + * + * @param ident The name identifier of the model. + * @param version The version number of the model. + * @return True if the model version exists, false if the model version does not exist. + */ + @Override + public boolean modelVersionExists(NameIdentifier ident, int version) { + return dispatcher.modelVersionExists(ident, version); + } + + /** + * Check if the model version exists by the {@link NameIdentifier} and version alias. If the model + * version exists, return true, otherwise return false. + * + * @param ident The name identifier of the model. + * @param alias The version alias of the model. + * @return True if the model version exists, false if the model version does not exist. + */ + @Override + public boolean modelVersionExists(NameIdentifier ident, String alias) { + return dispatcher.modelVersionExists(ident, alias); + } + + private ModelInfo getModelInfo(NameIdentifier modelIdent, int version) { + Model model = getModel(modelIdent); + ModelVersion modelVersion = dispatcher.getModelVersion(modelIdent, version); + ModelVersionInfo modelVersionInfo = new ModelVersionInfo(modelVersion); + + return new ModelInfo(model, new ModelVersionInfo[] {modelVersionInfo}); + } + + private ModelInfo getModelInfo(NameIdentifier modelIdent, String alias) { + Model model = getModel(modelIdent); + ModelVersion modelVersion = dispatcher.getModelVersion(modelIdent, alias); + ModelVersionInfo modelVersionInfo = new ModelVersionInfo(modelVersion); + + return new ModelInfo(model, new ModelVersionInfo[] {modelVersionInfo}); + } +} diff --git a/core/src/main/java/org/apache/gravitino/listener/api/event/DropModelEvent.java b/core/src/main/java/org/apache/gravitino/listener/api/event/DropModelEvent.java index 5a063ea0ee6..7a8ec3cb95a 100644 --- a/core/src/main/java/org/apache/gravitino/listener/api/event/DropModelEvent.java +++ b/core/src/main/java/org/apache/gravitino/listener/api/event/DropModelEvent.java @@ -20,11 +20,9 @@ package org.apache.gravitino.listener.api.event; import org.apache.gravitino.NameIdentifier; -import org.apache.gravitino.listener.api.info.ModelInfo; /** Event representing the successful drop of a model. */ public class DropModelEvent extends ModelEvent { - private final ModelInfo dropModelInfo; private final boolean isExists; /** @@ -33,26 +31,14 @@ public class DropModelEvent extends ModelEvent { * * @param user The username of the individual who initiated the model drop operation. * @param identifier The unique identifier of the model that was dropped. - * @param dropModelInfo The state of the model post-drop operation. * @param isExists A boolean flag indicating whether the model existed at the time of the drop * operation. */ - public DropModelEvent( - String user, NameIdentifier identifier, ModelInfo dropModelInfo, boolean isExists) { + public DropModelEvent(String user, NameIdentifier identifier, boolean isExists) { super(user, identifier); - this.dropModelInfo = dropModelInfo; this.isExists = isExists; } - /** - * Retrieves the state of the model post-drop operation. - * - * @return The state of the model post-drop operation. - */ - public ModelInfo DropModelInfo() { - return dropModelInfo; - } - /** * Retrieves the existence status of the model at the time of the drop operation. * @@ -72,4 +58,14 @@ public boolean isExists() { public OperationType operationType() { return OperationType.DROP_MODEL; } + + /** + * The status of the operation. + * + * @return The operation status. + */ + @Override + public OperationStatus operationStatus() { + return isExists() ? OperationStatus.SUCCESS : OperationStatus.UNPROCESSED; + } } diff --git a/core/src/main/java/org/apache/gravitino/listener/api/event/DropModelVersionEvent.java b/core/src/main/java/org/apache/gravitino/listener/api/event/DropModelVersionEvent.java index d7118565fac..e74b4416fe8 100644 --- a/core/src/main/java/org/apache/gravitino/listener/api/event/DropModelVersionEvent.java +++ b/core/src/main/java/org/apache/gravitino/listener/api/event/DropModelVersionEvent.java @@ -20,7 +20,6 @@ package org.apache.gravitino.listener.api.event; import org.apache.gravitino.NameIdentifier; -import org.apache.gravitino.listener.api.info.ModelInfo; /** * Represents an event that is generated after a model version is successfully dropped from the @@ -28,7 +27,6 @@ */ public class DropModelVersionEvent extends ModelEvent { - private final ModelInfo dropModelVersionInfo; private final boolean isExists; /** @@ -40,22 +38,11 @@ public class DropModelVersionEvent extends ModelEvent { * @param isExists A boolean flag indicating whether the model version existed at the time of the * drop operation. */ - public DropModelVersionEvent( - String user, NameIdentifier identifier, ModelInfo dropModelVersionInfo, boolean isExists) { + public DropModelVersionEvent(String user, NameIdentifier identifier, boolean isExists) { super(user, identifier); - this.dropModelVersionInfo = dropModelVersionInfo; this.isExists = isExists; } - /** - * Retrieves the state of the model after the drop version operation. - * - * @return The state of the model after the drop version operation. - */ - public ModelInfo DropModelVersionInfo() { - return dropModelVersionInfo; - } - /** * Retrieves the existence status of the model version at the time of the drop operation. * @@ -75,4 +62,9 @@ public boolean isExists() { public OperationType operationType() { return OperationType.DROP_MODEL_VERSION; } + + @Override + public OperationStatus operationStatus() { + return isExists() ? OperationStatus.SUCCESS : OperationStatus.UNPROCESSED; + } } diff --git a/core/src/main/java/org/apache/gravitino/listener/api/event/GetModelVersionEvent.java b/core/src/main/java/org/apache/gravitino/listener/api/event/GetModelVersionEvent.java index 527fdd485e9..1f26b949bc0 100644 --- a/core/src/main/java/org/apache/gravitino/listener/api/event/GetModelVersionEvent.java +++ b/core/src/main/java/org/apache/gravitino/listener/api/event/GetModelVersionEvent.java @@ -24,19 +24,18 @@ /** Represents an event triggered upon the successful getting the version of a model. */ public class GetModelVersionEvent extends ModelEvent { - public final ModelInfo getModelVersionInfo; + public final ModelInfo modelInfo; /** * Constructs an instance of {@code GetModelVersionEvent}. * * @param user The username of the individual who initiated the get model version event. * @param identifier The unique identifier of the model that was getting the version. - * @param getModelVersionInfo The state of the model after the version was loaded. + * @param modelInfo The state of the model after the version was loaded. */ - public GetModelVersionEvent( - String user, NameIdentifier identifier, ModelInfo getModelVersionInfo) { + public GetModelVersionEvent(String user, NameIdentifier identifier, ModelInfo modelInfo) { super(user, identifier); - this.getModelVersionInfo = getModelVersionInfo; + this.modelInfo = modelInfo; } /** @@ -46,7 +45,7 @@ public GetModelVersionEvent( * @return A {@link ModelInfo} instance encapsulating the details of the model version. */ public ModelInfo getModelVersionInfo() { - return getModelVersionInfo; + return modelInfo; } /** diff --git a/core/src/main/java/org/apache/gravitino/listener/api/event/LinkModelVersionEvent.java b/core/src/main/java/org/apache/gravitino/listener/api/event/LinkModelVersionEvent.java index 17eae5d5de0..7683c8fe701 100644 --- a/core/src/main/java/org/apache/gravitino/listener/api/event/LinkModelVersionEvent.java +++ b/core/src/main/java/org/apache/gravitino/listener/api/event/LinkModelVersionEvent.java @@ -24,7 +24,7 @@ /** Represents an event triggered upon the successful linking of a model version. */ public class LinkModelVersionEvent extends ModelEvent { - private ModelInfo linkModelVersionInfo; + private ModelInfo modelInfo; /** * Constructs an instance of {@code LinkModelVersionEvent}, capturing essential details about the @@ -32,12 +32,11 @@ public class LinkModelVersionEvent extends ModelEvent { * * @param user The username of the individual who initiated the model version linking. * @param identifier The unique identifier of the model that was linked. - * @param linkModelVersionInfo The final state of the model after linking. + * @param modelInfo The final state of the model after linking. */ - public LinkModelVersionEvent( - String user, NameIdentifier identifier, ModelInfo linkModelVersionInfo) { + public LinkModelVersionEvent(String user, NameIdentifier identifier, ModelInfo modelInfo) { super(user, identifier); - this.linkModelVersionInfo = linkModelVersionInfo; + this.modelInfo = modelInfo; } /** @@ -48,7 +47,7 @@ public LinkModelVersionEvent( * version. */ public ModelInfo linkModelVersionInfo() { - return linkModelVersionInfo; + return modelInfo; } /** diff --git a/core/src/main/java/org/apache/gravitino/listener/api/event/ListModelVersionsEvent.java b/core/src/main/java/org/apache/gravitino/listener/api/event/ListModelVersionsEvent.java index 5892b2d73ea..029558f695e 100644 --- a/core/src/main/java/org/apache/gravitino/listener/api/event/ListModelVersionsEvent.java +++ b/core/src/main/java/org/apache/gravitino/listener/api/event/ListModelVersionsEvent.java @@ -27,19 +27,18 @@ */ public class ListModelVersionsEvent extends ModelEvent { - private final ModelInfo listModelVersionInfo; + private final ModelInfo modelInfo; /** * Constructs an instance of {@code ListModelVersionsEvent}. * * @param user The username of the individual who initiated the model version listing. * @param identifier The unique identifier of the model that it's version was listed. - * @param listModelVersionInfo The model information containing the list of model versions. + * @param modelInfo The model information containing the list of model versions. */ - public ListModelVersionsEvent( - String user, NameIdentifier identifier, ModelInfo listModelVersionInfo) { + public ListModelVersionsEvent(String user, NameIdentifier identifier, ModelInfo modelInfo) { super(user, identifier); - this.listModelVersionInfo = listModelVersionInfo; + this.modelInfo = modelInfo; } /** @@ -48,7 +47,7 @@ public ListModelVersionsEvent( * @return A {@link ModelInfo} instance containing the list of model versions. */ public ModelInfo listModelVersionInfo() { - return listModelVersionInfo; + return modelInfo; } /** diff --git a/core/src/main/java/org/apache/gravitino/listener/api/event/RegisterModelEvent.java b/core/src/main/java/org/apache/gravitino/listener/api/event/RegisterModelEvent.java index feeb1a1dfdf..376c79e4267 100644 --- a/core/src/main/java/org/apache/gravitino/listener/api/event/RegisterModelEvent.java +++ b/core/src/main/java/org/apache/gravitino/listener/api/event/RegisterModelEvent.java @@ -35,8 +35,7 @@ public class RegisterModelEvent extends ModelEvent { * details such as the metalake, catalog, schema, and Model name. * @param registeredTopicInfo The final state of the model post-creation. */ - protected RegisterModelEvent( - String user, NameIdentifier identifier, ModelInfo registeredTopicInfo) { + public RegisterModelEvent(String user, NameIdentifier identifier, ModelInfo registeredTopicInfo) { super(user, identifier); this.registeredTopicInfo = registeredTopicInfo; } 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 c62dacc942c..c5aeaeb1af5 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 @@ -25,7 +25,6 @@ import org.apache.gravitino.Audit; import org.apache.gravitino.annotation.DeveloperApi; import org.apache.gravitino.model.Model; -import org.apache.gravitino.model.ModelVersion; /** * ModelInfo exposes model information for event listener, it's supposed to be read only. Most of @@ -38,7 +37,7 @@ public class ModelInfo { @Getter private final Map properties; @Nullable private final Audit audit; @Getter private final int lastVersion; - private final ModelVersion[] versions; + private final ModelVersionInfo[] versions; /** * Constructs model information based on a given model. @@ -55,7 +54,7 @@ public ModelInfo(Model model) { * @param model the model to expose information for. * @param modelVersions the versions of the model. */ - public ModelInfo(Model model, ModelVersion[] modelVersions) { + public ModelInfo(Model model, ModelVersionInfo[] modelVersions) { this.name = model.name(); this.properties = model.properties(); this.comment = model.comment(); @@ -90,7 +89,7 @@ public Audit getAudit() { * @return the versions of the model or null if not set. */ @Nullable - public ModelVersion[] getModelVersion() { + public ModelVersionInfo[] modelVersions() { return versions; } } 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 new file mode 100644 index 00000000000..8c196d35c50 --- /dev/null +++ b/core/src/main/java/org/apache/gravitino/listener/api/info/ModelVersionInfo.java @@ -0,0 +1,88 @@ +/* + * 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.Map; +import javax.annotation.Nullable; +import lombok.Getter; +import org.apache.gravitino.Audit; +import org.apache.gravitino.model.ModelVersion; + +/** + * {@link ModelVersionInfo} exposes model version information for event listener, it's supposed to + * be read only. Most of the fields are shallow copied internally not deep copies for performance. + */ +public class ModelVersionInfo { + @Getter private final String uri; + @Getter @Nullable private final String[] aliases; + @Nullable private final String comment; + @Getter private final Map properties; + @Nullable private final Audit auditInfo; + + /** + * Constructs model version information based on a given {@link ModelVersion}. + * + * @param modelVersion the model version to expose information for. + */ + public ModelVersionInfo(ModelVersion modelVersion) { + this.uri = modelVersion.uri(); + this.aliases = modelVersion.aliases(); + this.comment = modelVersion.comment(); + this.properties = modelVersion.properties(); + this.auditInfo = modelVersion.auditInfo(); + } + + /** + * Constructs model version information based on a given arguments. + * + * @param uri + * @param aliases + * @param comment + * @param properties + */ + public ModelVersionInfo( + String uri, String[] aliases, String comment, Map properties) { + this.uri = uri; + this.aliases = aliases; + this.comment = comment; + this.properties = properties; + this.auditInfo = null; + } + + /** + * Returns the comment of the model version. + * + * @return the comment of the model version or null if not set. + */ + @Nullable + public String getComment() { + return comment; + } + + /** + * Returns the audit information of the model version. + * + * @return the audit information of the model version or null if not set. + */ + @Nullable + public Audit getAudit() { + return auditInfo; + } +} 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 4638d22314d..05c7b7ba42b 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 @@ -19,14 +19,363 @@ package org.apache.gravitino.listener.api.event; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import com.google.common.collect.ImmutableMap; +import java.util.Collections; +import org.apache.gravitino.NameIdentifier; +import org.apache.gravitino.Namespace; +import org.apache.gravitino.catalog.ModelDispatcher; +import org.apache.gravitino.exceptions.GravitinoRuntimeException; +import org.apache.gravitino.listener.DummyEventListener; +import org.apache.gravitino.listener.EventBus; +import org.apache.gravitino.listener.ModelEventDispatcher; +import org.apache.gravitino.listener.api.info.ModelInfo; +import org.apache.gravitino.listener.api.info.ModelVersionInfo; +import org.apache.gravitino.model.Model; +import org.apache.gravitino.model.ModelVersion; +import org.apache.gravitino.utils.NameIdentifierUtil; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestInstance; @TestInstance(TestInstance.Lifecycle.PER_CLASS) public class TestModelEvent { + private ModelEventDispatcher dispatcher; + private ModelEventDispatcher failureDispatcher; + private DummyEventListener dummyEventListener; + private Model modelA; + private Model modelB; + private NameIdentifier existingIdentA; + private NameIdentifier existingIdentB; + private NameIdentifier notExistingIdent; + private Namespace namespace; + private ModelVersion firstModelVersion; + private ModelVersion secondModelVersion; @BeforeAll void init() { - // TODO: Implement tests for ModelEvent + this.namespace = Namespace.of("metalake", "catalog", "schema"); + this.modelA = mockModel("modelA", "commentA"); + this.modelB = mockModel("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 + void testRegisterModelEvent() { + dispatcher.registerModel(existingIdentA, "comment", ImmutableMap.of("color", "#FFFFFF")); + Event event = dummyEventListener.popPostEvent(); + Assertions.assertEquals(RegisterModelEvent.class, event.getClass()); + Assertions.assertEquals(OperationType.REGISTER_MODEL, event.operationType()); + Assertions.assertEquals(OperationStatus.SUCCESS, event.operationStatus()); + + RegisterModelEvent registerModelEvent = (RegisterModelEvent) event; + ModelInfo modelInfo = registerModelEvent.registeredModelInfo(); + Assertions.assertEquals("modelA", modelInfo.getName()); + Assertions.assertEquals("commentA", modelInfo.getComment()); + Assertions.assertEquals(ImmutableMap.of("color", "#FFFFFF"), modelInfo.getProperties()); + Assertions.assertNull(modelInfo.modelVersions()); + } + + @Test + void testGetModelEvent() { + Model model = dispatcher.getModel(existingIdentA); + Event event = dummyEventListener.popPostEvent(); + Assertions.assertEquals(GetModelEvent.class, event.getClass()); + Assertions.assertEquals(OperationType.GET_MODEL, event.operationType()); + Assertions.assertEquals(OperationStatus.SUCCESS, event.operationStatus()); + Assertions.assertNotNull(model); + + // validate model info + GetModelEvent getModelEvent = (GetModelEvent) event; + ModelInfo modelInfo = getModelEvent.getModelInfo(); + Assertions.assertEquals("modelA", modelInfo.getName()); + Assertions.assertEquals("commentA", modelInfo.getComment()); + Assertions.assertEquals(ImmutableMap.of("color", "#FFFFFF"), modelInfo.getProperties()); + Assertions.assertNull(modelInfo.modelVersions()); + } + + @Test + void testDeleteExistsModelEvent() { + boolean isExists = dispatcher.deleteModel(existingIdentA); + Event event = dummyEventListener.popPostEvent(); + Assertions.assertEquals(DropModelEvent.class, event.getClass()); + Assertions.assertEquals(OperationType.DROP_MODEL, event.operationType()); + Assertions.assertEquals(OperationStatus.SUCCESS, event.operationStatus()); + Assertions.assertTrue(isExists); + + DropModelEvent dropModelEvent = (DropModelEvent) event; + Assertions.assertEquals(existingIdentA, dropModelEvent.identifier()); + Assertions.assertEquals(DropModelEvent.class, dropModelEvent.getClass()); + Assertions.assertEquals(OperationType.DROP_MODEL, dropModelEvent.operationType()); + Assertions.assertEquals(OperationStatus.SUCCESS, dropModelEvent.operationStatus()); + } + + @Test + void testDeleteNotExistsModelEvent() { + boolean isExists = dispatcher.deleteModel(notExistingIdent); + Event event = dummyEventListener.popPostEvent(); + Assertions.assertEquals(DropModelEvent.class, event.getClass()); + Assertions.assertEquals(OperationType.DROP_MODEL, event.operationType()); + Assertions.assertEquals(OperationStatus.UNPROCESSED, event.operationStatus()); + Assertions.assertFalse(isExists); + + DropModelEvent dropModelEvent = (DropModelEvent) event; + Assertions.assertEquals(DropModelEvent.class, dropModelEvent.getClass()); + Assertions.assertEquals(OperationType.DROP_MODEL, dropModelEvent.operationType()); + Assertions.assertEquals(OperationStatus.UNPROCESSED, dropModelEvent.operationStatus()); + } + + @Test + void testListModelEvent() { + NameIdentifier[] nameIdentifiers = dispatcher.listModels(namespace); + Event event = dummyEventListener.popPostEvent(); + Assertions.assertEquals(ListModelEvent.class, event.getClass()); + Assertions.assertEquals(OperationType.LIST_MODEL, event.operationType()); + Assertions.assertEquals(OperationStatus.SUCCESS, event.operationStatus()); + + ListModelEvent listModelEvent = (ListModelEvent) event; + Assertions.assertEquals(namespace, listModelEvent.namespace()); + + Assertions.assertEquals(2, nameIdentifiers.length); + Assertions.assertEquals(existingIdentA, nameIdentifiers[0]); + Assertions.assertEquals(existingIdentB, nameIdentifiers[1]); + } + + @Test + void testLinkModelVersionEvent() { + dispatcher.linkModelVersion( + existingIdentA, + "uriA", + new String[] {"aliasProduction"}, + "versionInfoA", + ImmutableMap.of("color", "#FFFFFF")); + Event event = dummyEventListener.popPostEvent(); + Assertions.assertEquals(LinkModelVersionEvent.class, event.getClass()); + Assertions.assertEquals(OperationType.LINK_MODEL_VERSION, event.operationType()); + Assertions.assertEquals(OperationStatus.SUCCESS, event.operationStatus()); + + // validate model info + LinkModelVersionEvent linkModelVersionEvent = (LinkModelVersionEvent) event; + ModelInfo modelInfo = linkModelVersionEvent.linkModelVersionInfo(); + Assertions.assertEquals("modelA", modelInfo.getName()); + Assertions.assertEquals("commentA", modelInfo.getComment()); + Assertions.assertEquals(ImmutableMap.of("color", "#FFFFFF"), modelInfo.getProperties()); + + // validate model version info + ModelVersionInfo[] modelVersionInfos = modelInfo.modelVersions(); + Assertions.assertNotNull(modelVersionInfos); + Assertions.assertEquals(1, modelVersionInfos.length); + Assertions.assertEquals("versionInfoA", modelVersionInfos[0].getComment()); + Assertions.assertEquals("uriA", modelVersionInfos[0].getUri()); + Assertions.assertEquals("aliasProduction", modelVersionInfos[0].getAliases()[0]); + } + + @Test + void testGetModelVersionEventViaVersion() { + dispatcher.getModelVersion(existingIdentA, 1); + Event event = dummyEventListener.popPostEvent(); + Assertions.assertEquals(GetModelVersionEvent.class, event.getClass()); + Assertions.assertEquals(OperationType.GET_MODEL_VERSION, event.operationType()); + Assertions.assertEquals(OperationStatus.SUCCESS, event.operationStatus()); + + // validate model info + GetModelVersionEvent getModelVersionEvent = (GetModelVersionEvent) event; + ModelInfo modelInfo = getModelVersionEvent.getModelVersionInfo(); + Assertions.assertEquals("modelA", modelInfo.getName()); + Assertions.assertEquals("commentA", modelInfo.getComment()); + Assertions.assertEquals(ImmutableMap.of("color", "#FFFFFF"), modelInfo.getProperties()); + + // validate model version info + ModelVersionInfo[] modelVersionInfos = modelInfo.modelVersions(); + Assertions.assertNotNull(modelVersionInfos); + Assertions.assertEquals(1, modelVersionInfos.length); + Assertions.assertEquals("model version versionInfoA", modelVersionInfos[0].getComment()); + Assertions.assertEquals("uriA", modelVersionInfos[0].getUri()); + Assertions.assertEquals("aliasProduction", modelVersionInfos[0].getAliases()[0]); + } + + @Test + void testGetModelVersionEventViaAlias() { + dispatcher.getModelVersion(existingIdentB, "aliasTest"); + Event event = dummyEventListener.popPostEvent(); + Assertions.assertEquals(GetModelVersionEvent.class, event.getClass()); + Assertions.assertEquals(OperationType.GET_MODEL_VERSION, event.operationType()); + Assertions.assertEquals(OperationStatus.SUCCESS, event.operationStatus()); + + // validate model info + GetModelVersionEvent getModelVersionEvent = (GetModelVersionEvent) event; + ModelInfo modelInfo = getModelVersionEvent.getModelVersionInfo(); + Assertions.assertEquals("modelB", modelInfo.getName()); + Assertions.assertEquals("commentB", modelInfo.getComment()); + Assertions.assertEquals(ImmutableMap.of("color", "#FFFFFF"), modelInfo.getProperties()); + + // validate model version info + ModelVersionInfo[] modelVersionInfos = modelInfo.modelVersions(); + Assertions.assertNotNull(modelVersionInfos); + Assertions.assertEquals(1, modelVersionInfos.length); + Assertions.assertEquals("model version versionInfoB", modelVersionInfos[0].getComment()); + Assertions.assertEquals("uriB", modelVersionInfos[0].getUri()); + Assertions.assertEquals("aliasTest", modelVersionInfos[0].getAliases()[0]); + } + + @Test + void testDeleteModelVersionEventViaVersion() { + boolean isExists = dispatcher.deleteModelVersion(existingIdentA, 1); + Event event = dummyEventListener.popPostEvent(); + Assertions.assertEquals(DropModelVersionEvent.class, event.getClass()); + Assertions.assertEquals(OperationType.DROP_MODEL_VERSION, event.operationType()); + Assertions.assertEquals(OperationStatus.SUCCESS, event.operationStatus()); + Assertions.assertTrue(isExists); + + // validate model info + DropModelVersionEvent dropModelVersionEvent = (DropModelVersionEvent) event; + Assertions.assertEquals(existingIdentA, dropModelVersionEvent.identifier()); + Assertions.assertEquals(DropModelVersionEvent.class, dropModelVersionEvent.getClass()); + Assertions.assertEquals( + OperationType.DROP_MODEL_VERSION, dropModelVersionEvent.operationType()); + Assertions.assertEquals(OperationStatus.SUCCESS, dropModelVersionEvent.operationStatus()); + } + + @Test + void testDeleteModelVersionEventViaAlias() { + boolean isExists = dispatcher.deleteModelVersion(existingIdentB, "aliasTest"); + Event event = dummyEventListener.popPostEvent(); + Assertions.assertEquals(DropModelVersionEvent.class, event.getClass()); + Assertions.assertEquals(OperationType.DROP_MODEL_VERSION, event.operationType()); + Assertions.assertEquals(OperationStatus.SUCCESS, event.operationStatus()); + Assertions.assertTrue(isExists); + + // validate model info + DropModelVersionEvent dropModelVersionEvent = (DropModelVersionEvent) event; + Assertions.assertEquals(existingIdentB, dropModelVersionEvent.identifier()); + Assertions.assertEquals(DropModelVersionEvent.class, dropModelVersionEvent.getClass()); + Assertions.assertEquals( + OperationType.DROP_MODEL_VERSION, dropModelVersionEvent.operationType()); + Assertions.assertEquals(OperationStatus.SUCCESS, dropModelVersionEvent.operationStatus()); + } + + @Test + void testDeleteModelVersionEventViaVersionNotExists() { + boolean isExists = dispatcher.deleteModelVersion(existingIdentA, 3); + Event event = dummyEventListener.popPostEvent(); + Assertions.assertEquals(DropModelVersionEvent.class, event.getClass()); + Assertions.assertEquals(OperationType.DROP_MODEL_VERSION, event.operationType()); + Assertions.assertEquals(OperationStatus.UNPROCESSED, event.operationStatus()); + Assertions.assertFalse(isExists); + + // validate model info + DropModelVersionEvent dropModelVersionEvent = (DropModelVersionEvent) event; + Assertions.assertEquals(DropModelVersionEvent.class, dropModelVersionEvent.getClass()); + Assertions.assertEquals( + OperationType.DROP_MODEL_VERSION, dropModelVersionEvent.operationType()); + Assertions.assertEquals(OperationStatus.UNPROCESSED, dropModelVersionEvent.operationStatus()); + } + + @Test + void testListModelVersionsEvent() { + int[] versions = dispatcher.listModelVersions(existingIdentA); + Event event = dummyEventListener.popPostEvent(); + Assertions.assertEquals(ListModelVersionsEvent.class, event.getClass()); + Assertions.assertEquals(OperationType.LIST_MODEL_VERSIONS, event.operationType()); + Assertions.assertEquals(OperationStatus.SUCCESS, event.operationStatus()); + Assertions.assertEquals(2, versions.length); + Assertions.assertEquals(1, versions[0]); + Assertions.assertEquals(2, versions[1]); + + // validate model info + ListModelVersionsEvent listModelVersionsEvent = (ListModelVersionsEvent) event; + ModelInfo modelInfo = listModelVersionsEvent.listModelVersionInfo(); + Assertions.assertEquals("modelA", modelInfo.getName()); + Assertions.assertEquals("commentA", modelInfo.getComment()); + Assertions.assertEquals(ImmutableMap.of("color", "#FFFFFF"), modelInfo.getProperties()); + Assertions.assertNull(modelInfo.modelVersions()); + } + + private ModelDispatcher mockExceptionModelDispatcher() { + return mock( + ModelDispatcher.class, + invocation -> { + throw new GravitinoRuntimeException("Exception for all methods"); + }); + } + + private ModelDispatcher mockTagDispatcher() { + ModelDispatcher dispatcher = mock(ModelDispatcher.class); + + when(dispatcher.registerModel(existingIdentA, "comment", ImmutableMap.of("color", "#FFFFFF"))) + .thenReturn(modelA); + when(dispatcher.registerModel(existingIdentB, "comment", ImmutableMap.of("color", "#FFFFFF"))) + .thenReturn(modelB); + + when(dispatcher.getModel(existingIdentA)).thenReturn(modelA); + when(dispatcher.getModel(existingIdentB)).thenReturn(modelB); + + when(dispatcher.deleteModel(existingIdentA)).thenReturn(true); + when(dispatcher.deleteModel(notExistingIdent)).thenReturn(false); + + when(dispatcher.listModels(namespace)) + .thenReturn(new NameIdentifier[] {existingIdentA, existingIdentB}); + + when(dispatcher.getModelVersion(existingIdentA, 1)).thenReturn(firstModelVersion); + when(dispatcher.getModelVersion(existingIdentB, "aliasTest")).thenReturn(secondModelVersion); + + when(dispatcher.deleteModelVersion(existingIdentA, 1)).thenReturn(true); + when(dispatcher.deleteModelVersion(existingIdentB, "aliasTest")).thenReturn(true); + when(dispatcher.deleteModelVersion(existingIdentA, 3)).thenReturn(false); + + when(dispatcher.listModelVersions(existingIdentA)).thenReturn(new int[] {1, 2}); + + return dispatcher; + } + + /** + * Mock a model with given name and comment. + * + * @param name name of the model + * @param comment comment of the model + * @return a mock model + */ + private Model mockModel(String name, String comment) { + Model model = mock(Model.class); + when(model.name()).thenReturn(name); + when(model.comment()).thenReturn(comment); + when(model.properties()).thenReturn(ImmutableMap.of("color", "#FFFFFF")); + return model; + } + + /** + * Mock a model version with given uri, aliases, and comment. + * + * @param uri uri of the model version + * @param aliases aliases of the model version + * @param comment comment of the model version, added "model version " prefix. + * @return a mock model version + */ + private ModelVersion mockModelVersion(String uri, String[] aliases, String comment) { + ModelVersion modelVersion = mock(ModelVersion.class); + when(modelVersion.version()).thenReturn(1); + when(modelVersion.uri()).thenReturn(uri); + when(modelVersion.aliases()).thenReturn(aliases); + when(modelVersion.comment()).thenReturn("model version " + comment); + when(modelVersion.properties()).thenReturn(ImmutableMap.of("color", "#FFFFFF")); + + return modelVersion; } } From b28b1897c5ace3f185dfaad14178786c812f97e4 Mon Sep 17 00:00:00 2001 From: pancx Date: Wed, 15 Jan 2025 11:12:23 +0800 Subject: [PATCH 5/7] [#6220] improve(CLI): Clean up GravitinoCommandLine class now it been refactored rename drop event and operation type. --- .../listener/ModelEventDispatcher.java | 10 +-- ...pModelEvent.java => DeleteModelEvent.java} | 8 +-- ...vent.java => DeleteModelVersionEvent.java} | 8 +-- .../listener/api/event/OperationType.java | 4 +- .../listener/api/event/TestModelEvent.java | 66 +++++++++---------- 5 files changed, 48 insertions(+), 48 deletions(-) rename core/src/main/java/org/apache/gravitino/listener/api/event/{DropModelEvent.java => DeleteModelEvent.java} (88%) rename core/src/main/java/org/apache/gravitino/listener/api/event/{DropModelVersionEvent.java => DeleteModelVersionEvent.java} (87%) 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 7e9b0ca7532..519772e41df 100644 --- a/core/src/main/java/org/apache/gravitino/listener/ModelEventDispatcher.java +++ b/core/src/main/java/org/apache/gravitino/listener/ModelEventDispatcher.java @@ -28,8 +28,8 @@ 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.DropModelEvent; -import org.apache.gravitino.listener.api.event.DropModelVersionEvent; +import org.apache.gravitino.listener.api.event.DeleteModelEvent; +import org.apache.gravitino.listener.api.event.DeleteModelVersionEvent; import org.apache.gravitino.listener.api.event.GetModelEvent; import org.apache.gravitino.listener.api.event.GetModelVersionEvent; import org.apache.gravitino.listener.api.event.LinkModelVersionEvent; @@ -163,7 +163,7 @@ public boolean deleteModel(NameIdentifier ident) { try { boolean isExists = dispatcher.deleteModel(ident); eventBus.dispatchEvent( - new DropModelEvent(PrincipalUtils.getCurrentUserName(), ident, isExists)); + new DeleteModelEvent(PrincipalUtils.getCurrentUserName(), ident, isExists)); return isExists; } catch (Exception e) { // TODO: failureEvent @@ -292,7 +292,7 @@ public boolean deleteModelVersion(NameIdentifier ident, int version) { try { boolean isExists = dispatcher.deleteModelVersion(ident, version); eventBus.dispatchEvent( - new DropModelVersionEvent(PrincipalUtils.getCurrentUserName(), ident, isExists)); + new DeleteModelVersionEvent(PrincipalUtils.getCurrentUserName(), ident, isExists)); return isExists; } catch (Exception e) { // TODO: failureEvent @@ -314,7 +314,7 @@ public boolean deleteModelVersion(NameIdentifier ident, String alias) { try { boolean isExists = dispatcher.deleteModelVersion(ident, alias); eventBus.dispatchEvent( - new DropModelVersionEvent(PrincipalUtils.getCurrentUserName(), ident, isExists)); + new DeleteModelVersionEvent(PrincipalUtils.getCurrentUserName(), ident, isExists)); return isExists; } catch (Exception e) { // TODO: failureEvent diff --git a/core/src/main/java/org/apache/gravitino/listener/api/event/DropModelEvent.java b/core/src/main/java/org/apache/gravitino/listener/api/event/DeleteModelEvent.java similarity index 88% rename from core/src/main/java/org/apache/gravitino/listener/api/event/DropModelEvent.java rename to core/src/main/java/org/apache/gravitino/listener/api/event/DeleteModelEvent.java index 7a8ec3cb95a..b266cba64b0 100644 --- a/core/src/main/java/org/apache/gravitino/listener/api/event/DropModelEvent.java +++ b/core/src/main/java/org/apache/gravitino/listener/api/event/DeleteModelEvent.java @@ -22,11 +22,11 @@ import org.apache.gravitino.NameIdentifier; /** Event representing the successful drop of a model. */ -public class DropModelEvent extends ModelEvent { +public class DeleteModelEvent extends ModelEvent { private final boolean isExists; /** - * Constructs an instance of {@code DropModelEvent}, capturing essential details about the + * Constructs an instance of {@code DeleteModelEvent}, capturing essential details about the * successful drop of a model. * * @param user The username of the individual who initiated the model drop operation. @@ -34,7 +34,7 @@ public class DropModelEvent extends ModelEvent { * @param isExists A boolean flag indicating whether the model existed at the time of the drop * operation. */ - public DropModelEvent(String user, NameIdentifier identifier, boolean isExists) { + public DeleteModelEvent(String user, NameIdentifier identifier, boolean isExists) { super(user, identifier); this.isExists = isExists; } @@ -56,7 +56,7 @@ public boolean isExists() { */ @Override public OperationType operationType() { - return OperationType.DROP_MODEL; + return OperationType.DELETE_MODEL; } /** diff --git a/core/src/main/java/org/apache/gravitino/listener/api/event/DropModelVersionEvent.java b/core/src/main/java/org/apache/gravitino/listener/api/event/DeleteModelVersionEvent.java similarity index 87% rename from core/src/main/java/org/apache/gravitino/listener/api/event/DropModelVersionEvent.java rename to core/src/main/java/org/apache/gravitino/listener/api/event/DeleteModelVersionEvent.java index e74b4416fe8..1ff6c802322 100644 --- a/core/src/main/java/org/apache/gravitino/listener/api/event/DropModelVersionEvent.java +++ b/core/src/main/java/org/apache/gravitino/listener/api/event/DeleteModelVersionEvent.java @@ -25,12 +25,12 @@ * Represents an event that is generated after a model version is successfully dropped from the * model. */ -public class DropModelVersionEvent extends ModelEvent { +public class DeleteModelVersionEvent extends ModelEvent { private final boolean isExists; /** - * Constructs a new {@code DropModelVersionEvent} instance, encapsulating information about the + * Constructs a new {@code DeleteModelVersionEvent} instance, encapsulating information about the * outcome of a model version drop operation. * * @param user The user who initiated the drop model version operation. @@ -38,7 +38,7 @@ public class DropModelVersionEvent extends ModelEvent { * @param isExists A boolean flag indicating whether the model version existed at the time of the * drop operation. */ - public DropModelVersionEvent(String user, NameIdentifier identifier, boolean isExists) { + public DeleteModelVersionEvent(String user, NameIdentifier identifier, boolean isExists) { super(user, identifier); this.isExists = isExists; } @@ -60,7 +60,7 @@ public boolean isExists() { */ @Override public OperationType operationType() { - return OperationType.DROP_MODEL_VERSION; + return OperationType.DELETE_MODEL_VERSION; } @Override 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 0585984665f..a0c66619877 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 @@ -101,13 +101,13 @@ public enum OperationType { // Model event REGISTER_MODEL, - DROP_MODEL, + DELETE_MODEL, GET_MODEL, LIST_MODEL, // Model Version LINK_MODEL_VERSION, - DROP_MODEL_VERSION, + DELETE_MODEL_VERSION, GET_MODEL_VERSION, LIST_MODEL_VERSIONS, 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 05c7b7ba42b..545a6de8d81 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 @@ -115,31 +115,31 @@ void testGetModelEvent() { void testDeleteExistsModelEvent() { boolean isExists = dispatcher.deleteModel(existingIdentA); Event event = dummyEventListener.popPostEvent(); - Assertions.assertEquals(DropModelEvent.class, event.getClass()); - Assertions.assertEquals(OperationType.DROP_MODEL, event.operationType()); + Assertions.assertEquals(DeleteModelEvent.class, event.getClass()); + Assertions.assertEquals(OperationType.DELETE_MODEL, event.operationType()); Assertions.assertEquals(OperationStatus.SUCCESS, event.operationStatus()); Assertions.assertTrue(isExists); - DropModelEvent dropModelEvent = (DropModelEvent) event; - Assertions.assertEquals(existingIdentA, dropModelEvent.identifier()); - Assertions.assertEquals(DropModelEvent.class, dropModelEvent.getClass()); - Assertions.assertEquals(OperationType.DROP_MODEL, dropModelEvent.operationType()); - Assertions.assertEquals(OperationStatus.SUCCESS, dropModelEvent.operationStatus()); + DeleteModelEvent deleteModelEvent = (DeleteModelEvent) event; + Assertions.assertEquals(existingIdentA, deleteModelEvent.identifier()); + Assertions.assertEquals(DeleteModelEvent.class, deleteModelEvent.getClass()); + Assertions.assertEquals(OperationType.DELETE_MODEL, deleteModelEvent.operationType()); + Assertions.assertEquals(OperationStatus.SUCCESS, deleteModelEvent.operationStatus()); } @Test void testDeleteNotExistsModelEvent() { boolean isExists = dispatcher.deleteModel(notExistingIdent); Event event = dummyEventListener.popPostEvent(); - Assertions.assertEquals(DropModelEvent.class, event.getClass()); - Assertions.assertEquals(OperationType.DROP_MODEL, event.operationType()); + Assertions.assertEquals(DeleteModelEvent.class, event.getClass()); + Assertions.assertEquals(OperationType.DELETE_MODEL, event.operationType()); Assertions.assertEquals(OperationStatus.UNPROCESSED, event.operationStatus()); Assertions.assertFalse(isExists); - DropModelEvent dropModelEvent = (DropModelEvent) event; - Assertions.assertEquals(DropModelEvent.class, dropModelEvent.getClass()); - Assertions.assertEquals(OperationType.DROP_MODEL, dropModelEvent.operationType()); - Assertions.assertEquals(OperationStatus.UNPROCESSED, dropModelEvent.operationStatus()); + DeleteModelEvent deleteModelEvent = (DeleteModelEvent) event; + Assertions.assertEquals(DeleteModelEvent.class, deleteModelEvent.getClass()); + Assertions.assertEquals(OperationType.DELETE_MODEL, deleteModelEvent.operationType()); + Assertions.assertEquals(OperationStatus.UNPROCESSED, deleteModelEvent.operationStatus()); } @Test @@ -239,53 +239,53 @@ void testGetModelVersionEventViaAlias() { void testDeleteModelVersionEventViaVersion() { boolean isExists = dispatcher.deleteModelVersion(existingIdentA, 1); Event event = dummyEventListener.popPostEvent(); - Assertions.assertEquals(DropModelVersionEvent.class, event.getClass()); - Assertions.assertEquals(OperationType.DROP_MODEL_VERSION, event.operationType()); + Assertions.assertEquals(DeleteModelVersionEvent.class, event.getClass()); + Assertions.assertEquals(OperationType.DELETE_MODEL_VERSION, event.operationType()); Assertions.assertEquals(OperationStatus.SUCCESS, event.operationStatus()); Assertions.assertTrue(isExists); // validate model info - DropModelVersionEvent dropModelVersionEvent = (DropModelVersionEvent) event; - Assertions.assertEquals(existingIdentA, dropModelVersionEvent.identifier()); - Assertions.assertEquals(DropModelVersionEvent.class, dropModelVersionEvent.getClass()); + DeleteModelVersionEvent deleteModelVersionEvent = (DeleteModelVersionEvent) event; + Assertions.assertEquals(existingIdentA, deleteModelVersionEvent.identifier()); + Assertions.assertEquals(DeleteModelVersionEvent.class, deleteModelVersionEvent.getClass()); Assertions.assertEquals( - OperationType.DROP_MODEL_VERSION, dropModelVersionEvent.operationType()); - Assertions.assertEquals(OperationStatus.SUCCESS, dropModelVersionEvent.operationStatus()); + OperationType.DELETE_MODEL_VERSION, deleteModelVersionEvent.operationType()); + Assertions.assertEquals(OperationStatus.SUCCESS, deleteModelVersionEvent.operationStatus()); } @Test void testDeleteModelVersionEventViaAlias() { boolean isExists = dispatcher.deleteModelVersion(existingIdentB, "aliasTest"); Event event = dummyEventListener.popPostEvent(); - Assertions.assertEquals(DropModelVersionEvent.class, event.getClass()); - Assertions.assertEquals(OperationType.DROP_MODEL_VERSION, event.operationType()); + Assertions.assertEquals(DeleteModelVersionEvent.class, event.getClass()); + Assertions.assertEquals(OperationType.DELETE_MODEL_VERSION, event.operationType()); Assertions.assertEquals(OperationStatus.SUCCESS, event.operationStatus()); Assertions.assertTrue(isExists); // validate model info - DropModelVersionEvent dropModelVersionEvent = (DropModelVersionEvent) event; - Assertions.assertEquals(existingIdentB, dropModelVersionEvent.identifier()); - Assertions.assertEquals(DropModelVersionEvent.class, dropModelVersionEvent.getClass()); + DeleteModelVersionEvent deleteModelVersionEvent = (DeleteModelVersionEvent) event; + Assertions.assertEquals(existingIdentB, deleteModelVersionEvent.identifier()); + Assertions.assertEquals(DeleteModelVersionEvent.class, deleteModelVersionEvent.getClass()); Assertions.assertEquals( - OperationType.DROP_MODEL_VERSION, dropModelVersionEvent.operationType()); - Assertions.assertEquals(OperationStatus.SUCCESS, dropModelVersionEvent.operationStatus()); + OperationType.DELETE_MODEL_VERSION, deleteModelVersionEvent.operationType()); + Assertions.assertEquals(OperationStatus.SUCCESS, deleteModelVersionEvent.operationStatus()); } @Test void testDeleteModelVersionEventViaVersionNotExists() { boolean isExists = dispatcher.deleteModelVersion(existingIdentA, 3); Event event = dummyEventListener.popPostEvent(); - Assertions.assertEquals(DropModelVersionEvent.class, event.getClass()); - Assertions.assertEquals(OperationType.DROP_MODEL_VERSION, event.operationType()); + Assertions.assertEquals(DeleteModelVersionEvent.class, event.getClass()); + Assertions.assertEquals(OperationType.DELETE_MODEL_VERSION, event.operationType()); Assertions.assertEquals(OperationStatus.UNPROCESSED, event.operationStatus()); Assertions.assertFalse(isExists); // validate model info - DropModelVersionEvent dropModelVersionEvent = (DropModelVersionEvent) event; - Assertions.assertEquals(DropModelVersionEvent.class, dropModelVersionEvent.getClass()); + DeleteModelVersionEvent deleteModelVersionEvent = (DeleteModelVersionEvent) event; + Assertions.assertEquals(DeleteModelVersionEvent.class, deleteModelVersionEvent.getClass()); Assertions.assertEquals( - OperationType.DROP_MODEL_VERSION, dropModelVersionEvent.operationType()); - Assertions.assertEquals(OperationStatus.UNPROCESSED, dropModelVersionEvent.operationStatus()); + OperationType.DELETE_MODEL_VERSION, deleteModelVersionEvent.operationType()); + Assertions.assertEquals(OperationStatus.UNPROCESSED, deleteModelVersionEvent.operationStatus()); } @Test From 6b6a1542ecf9999d7016a16086cdc75f964cc0ba Mon Sep 17 00:00:00 2001 From: pancx Date: Wed, 15 Jan 2025 14:29:47 +0800 Subject: [PATCH 6/7] [#6067] improve(CLI): Support model pre event to Gravitino server Support model pre event to Gravitino server. [#6067] improve(CLI): Support model pre event to Gravitino server add model version related pre event to Gravitino server. [#6067] improve(CLI): Support model pre event to Gravitino server add preEvent support for ModelEventDispatcher. [#6067] improve(CLI): Support model pre event to Gravitino server add test cases. --- .../listener/ModelEventDispatcher.java | 50 ++++--- .../api/event/DeleteModelPreEvent.java | 48 +++++++ .../api/event/DeleteModelVersionPreEvent.java | 48 +++++++ .../listener/api/event/GetModelPreEvent.java | 45 ++++++ .../api/event/GetModelVersionPreEvent.java | 48 +++++++ .../api/event/LinkModelVersionPreEvent.java | 61 ++++++++ .../listener/api/event/ListModelPreEvent.java | 60 ++++++++ .../api/event/ListModelVersionsPreEvent.java | 54 +++++++ .../listener/api/event/ModelPreEvent.java | 37 +++++ .../api/event/RegisterModelPreEvent.java | 59 ++++++++ .../listener/api/info/ModelInfo.java | 11 ++ .../listener/api/event/TestModelEvent.java | 136 +++++++++++++++++- 12 files changed, 635 insertions(+), 22 deletions(-) create mode 100644 core/src/main/java/org/apache/gravitino/listener/api/event/DeleteModelPreEvent.java create mode 100644 core/src/main/java/org/apache/gravitino/listener/api/event/DeleteModelVersionPreEvent.java create mode 100644 core/src/main/java/org/apache/gravitino/listener/api/event/GetModelPreEvent.java create mode 100644 core/src/main/java/org/apache/gravitino/listener/api/event/GetModelVersionPreEvent.java create mode 100644 core/src/main/java/org/apache/gravitino/listener/api/event/LinkModelVersionPreEvent.java create mode 100644 core/src/main/java/org/apache/gravitino/listener/api/event/ListModelPreEvent.java create mode 100644 core/src/main/java/org/apache/gravitino/listener/api/event/ListModelVersionsPreEvent.java create mode 100644 core/src/main/java/org/apache/gravitino/listener/api/event/ModelPreEvent.java create mode 100644 core/src/main/java/org/apache/gravitino/listener/api/event/RegisterModelPreEvent.java 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 519772e41df..2b7f396d46f 100644 --- a/core/src/main/java/org/apache/gravitino/listener/ModelEventDispatcher.java +++ b/core/src/main/java/org/apache/gravitino/listener/ModelEventDispatcher.java @@ -29,13 +29,21 @@ import org.apache.gravitino.exceptions.NoSuchModelVersionException; import org.apache.gravitino.exceptions.NoSuchSchemaException; import org.apache.gravitino.listener.api.event.DeleteModelEvent; +import org.apache.gravitino.listener.api.event.DeleteModelPreEvent; import org.apache.gravitino.listener.api.event.DeleteModelVersionEvent; +import org.apache.gravitino.listener.api.event.DeleteModelVersionPreEvent; import org.apache.gravitino.listener.api.event.GetModelEvent; +import org.apache.gravitino.listener.api.event.GetModelPreEvent; import org.apache.gravitino.listener.api.event.GetModelVersionEvent; +import org.apache.gravitino.listener.api.event.GetModelVersionPreEvent; import org.apache.gravitino.listener.api.event.LinkModelVersionEvent; +import org.apache.gravitino.listener.api.event.LinkModelVersionPreEvent; import org.apache.gravitino.listener.api.event.ListModelEvent; +import org.apache.gravitino.listener.api.event.ListModelPreEvent; import org.apache.gravitino.listener.api.event.ListModelVersionsEvent; +import org.apache.gravitino.listener.api.event.ListModelVersionsPreEvent; import org.apache.gravitino.listener.api.event.RegisterModelEvent; +import org.apache.gravitino.listener.api.event.RegisterModelPreEvent; import org.apache.gravitino.listener.api.info.ModelInfo; import org.apache.gravitino.listener.api.info.ModelVersionInfo; import org.apache.gravitino.model.Model; @@ -83,7 +91,9 @@ public ModelEventDispatcher(EventBus eventBus, ModelDispatcher dispatcher) { @Override public Model registerModel(NameIdentifier ident, String comment, Map properties) throws NoSuchSchemaException, ModelAlreadyExistsException { - // TODO: preEvent + ModelInfo registerRequest = new ModelInfo(ident.name(), properties, comment, null); + eventBus.dispatchEvent( + new RegisterModelPreEvent(PrincipalUtils.getCurrentUserName(), ident, registerRequest)); try { Model model = dispatcher.registerModel(ident, comment, properties); ModelInfo modelInfo = new ModelInfo(model); @@ -137,7 +147,7 @@ public Model registerModel( */ @Override public Model getModel(NameIdentifier ident) throws NoSuchModelException { - // TODO: preEvent + eventBus.dispatchEvent(new GetModelPreEvent(PrincipalUtils.getCurrentUserName(), ident)); try { Model model = dispatcher.getModel(ident); ModelInfo modelInfo = new ModelInfo(model); @@ -159,7 +169,7 @@ public Model getModel(NameIdentifier ident) throws NoSuchModelException { */ @Override public boolean deleteModel(NameIdentifier ident) { - // TODO: preEvent + eventBus.dispatchEvent(new DeleteModelPreEvent(PrincipalUtils.getCurrentUserName(), ident)); try { boolean isExists = dispatcher.deleteModel(ident); eventBus.dispatchEvent( @@ -180,7 +190,7 @@ public boolean deleteModel(NameIdentifier ident) { */ @Override public NameIdentifier[] listModels(Namespace namespace) throws NoSuchSchemaException { - // TODO: preEvent + eventBus.dispatchEvent(new ListModelPreEvent(PrincipalUtils.getCurrentUserName(), namespace)); try { NameIdentifier[] models = dispatcher.listModels(namespace); eventBus.dispatchEvent(new ListModelEvent(PrincipalUtils.getCurrentUserName(), namespace)); @@ -216,14 +226,15 @@ public void linkModelVersion( String comment, Map properties) throws NoSuchModelException, ModelVersionAliasesAlreadyExistException { - // TODO: preEvent + Model model = dispatcher.getModel(ident); + ModelVersionInfo modelVersionInfo = new ModelVersionInfo(uri, aliases, comment, properties); + ModelInfo linkRequest = new ModelInfo(model, new ModelVersionInfo[] {modelVersionInfo}); + eventBus.dispatchEvent( + new LinkModelVersionPreEvent(PrincipalUtils.getCurrentUserName(), ident, linkRequest)); try { - Model model = dispatcher.getModel(ident); - ModelVersionInfo modelVersionInfo = new ModelVersionInfo(uri, aliases, comment, properties); - ModelInfo modelInfo = new ModelInfo(model, new ModelVersionInfo[] {modelVersionInfo}); dispatcher.linkModelVersion(ident, uri, aliases, comment, properties); eventBus.dispatchEvent( - new LinkModelVersionEvent(PrincipalUtils.getCurrentUserName(), ident, modelInfo)); + new LinkModelVersionEvent(PrincipalUtils.getCurrentUserName(), ident, linkRequest)); } catch (Exception e) { // TODO: failureEvent throw e; @@ -241,7 +252,7 @@ public void linkModelVersion( @Override public ModelVersion getModelVersion(NameIdentifier ident, int version) throws NoSuchModelVersionException { - // TODO: preEvent + eventBus.dispatchEvent(new GetModelVersionPreEvent(PrincipalUtils.getCurrentUserName(), ident)); try { ModelVersion modelVersion = dispatcher.getModelVersion(ident, version); ModelInfo modelInfo = getModelInfo(ident, version); @@ -265,7 +276,7 @@ public ModelVersion getModelVersion(NameIdentifier ident, int version) @Override public ModelVersion getModelVersion(NameIdentifier ident, String alias) throws NoSuchModelVersionException { - // TODO: preEvent + eventBus.dispatchEvent(new GetModelVersionPreEvent(PrincipalUtils.getCurrentUserName(), ident)); try { ModelVersion modelVersion = dispatcher.getModelVersion(ident, alias); ModelInfo modelInfo = getModelInfo(ident, alias); @@ -288,7 +299,8 @@ public ModelVersion getModelVersion(NameIdentifier ident, String alias) */ @Override public boolean deleteModelVersion(NameIdentifier ident, int version) { - // TODO: preEvent + eventBus.dispatchEvent( + new DeleteModelVersionPreEvent(PrincipalUtils.getCurrentUserName(), ident)); try { boolean isExists = dispatcher.deleteModelVersion(ident, version); eventBus.dispatchEvent( @@ -310,7 +322,8 @@ public boolean deleteModelVersion(NameIdentifier ident, int version) { */ @Override public boolean deleteModelVersion(NameIdentifier ident, String alias) { - // TODO: preEvent + eventBus.dispatchEvent( + new DeleteModelVersionPreEvent(PrincipalUtils.getCurrentUserName(), ident)); try { boolean isExists = dispatcher.deleteModelVersion(ident, alias); eventBus.dispatchEvent( @@ -331,11 +344,12 @@ public boolean deleteModelVersion(NameIdentifier ident, String alias) { */ @Override public int[] listModelVersions(NameIdentifier ident) throws NoSuchModelException { - // TODO: preEvent + Model model = dispatcher.getModel(ident); + ModelInfo modelInfo = new ModelInfo(model); + eventBus.dispatchEvent( + new ListModelVersionsPreEvent(PrincipalUtils.getCurrentUserName(), ident, modelInfo)); try { int[] versions = dispatcher.listModelVersions(ident); - Model model = dispatcher.getModel(ident); - ModelInfo modelInfo = new ModelInfo(model); eventBus.dispatchEvent( new ListModelVersionsEvent(PrincipalUtils.getCurrentUserName(), ident, modelInfo)); return versions; @@ -383,7 +397,7 @@ public boolean modelVersionExists(NameIdentifier ident, String alias) { } private ModelInfo getModelInfo(NameIdentifier modelIdent, int version) { - Model model = getModel(modelIdent); + Model model = dispatcher.getModel(modelIdent); ModelVersion modelVersion = dispatcher.getModelVersion(modelIdent, version); ModelVersionInfo modelVersionInfo = new ModelVersionInfo(modelVersion); @@ -391,7 +405,7 @@ private ModelInfo getModelInfo(NameIdentifier modelIdent, int version) { } private ModelInfo getModelInfo(NameIdentifier modelIdent, String alias) { - Model model = getModel(modelIdent); + Model model = dispatcher.getModel(modelIdent); ModelVersion modelVersion = dispatcher.getModelVersion(modelIdent, alias); ModelVersionInfo modelVersionInfo = new ModelVersionInfo(modelVersion); diff --git a/core/src/main/java/org/apache/gravitino/listener/api/event/DeleteModelPreEvent.java b/core/src/main/java/org/apache/gravitino/listener/api/event/DeleteModelPreEvent.java new file mode 100644 index 00000000000..2e8c452e221 --- /dev/null +++ b/core/src/main/java/org/apache/gravitino/listener/api/event/DeleteModelPreEvent.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; + +import org.apache.gravitino.NameIdentifier; +import org.apache.gravitino.annotation.DeveloperApi; + +/** Represents an event triggered before deleting a model. */ +@DeveloperApi +public class DeleteModelPreEvent extends ModelPreEvent { + + /** + * Create a new {@link DeleteModelPreEvent} instance. + * + * @param user the user who triggered the event. + * @param identifier the identifier of the model being operated on. + */ + public DeleteModelPreEvent(String user, NameIdentifier identifier) { + super(user, identifier); + } + + /** + * 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/DeleteModelVersionPreEvent.java b/core/src/main/java/org/apache/gravitino/listener/api/event/DeleteModelVersionPreEvent.java new file mode 100644 index 00000000000..80c98551076 --- /dev/null +++ b/core/src/main/java/org/apache/gravitino/listener/api/event/DeleteModelVersionPreEvent.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; + +import org.apache.gravitino.NameIdentifier; +import org.apache.gravitino.annotation.DeveloperApi; + +/** Represents an event triggered before deleting a model version. */ +@DeveloperApi +public class DeleteModelVersionPreEvent extends ModelPreEvent { + + /** + * Create a new {@link DeleteModelVersionPreEvent} instance. + * + * @param user The username of the individual who initiated the model version linking. + * @param identifier The unique identifier of the model that was linked. + */ + public DeleteModelVersionPreEvent(String user, NameIdentifier identifier) { + super(user, identifier); + } + + /** + * 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/GetModelPreEvent.java b/core/src/main/java/org/apache/gravitino/listener/api/event/GetModelPreEvent.java new file mode 100644 index 00000000000..0c21e78814b --- /dev/null +++ b/core/src/main/java/org/apache/gravitino/listener/api/event/GetModelPreEvent.java @@ -0,0 +1,45 @@ +/* + * 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; + +/** Represents an event triggered before getting a model. */ +public class GetModelPreEvent extends ModelPreEvent { + /** + * Create a new {@link GetModelPreEvent} instance. + * + * @param user the user who triggered the event. + * @param identifier the identifier of the model being operated on. + */ + public GetModelPreEvent(String user, NameIdentifier identifier) { + super(user, identifier); + } + + /** + * 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/GetModelVersionPreEvent.java b/core/src/main/java/org/apache/gravitino/listener/api/event/GetModelVersionPreEvent.java new file mode 100644 index 00000000000..37ea0a531d4 --- /dev/null +++ b/core/src/main/java/org/apache/gravitino/listener/api/event/GetModelVersionPreEvent.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; + +import org.apache.gravitino.NameIdentifier; +import org.apache.gravitino.annotation.DeveloperApi; + +/** Represents an event triggered before getting the version of a model. */ +@DeveloperApi +public class GetModelVersionPreEvent extends ModelPreEvent { + + /** + * Create a new {@link GetModelVersionPreEvent} instance. + * + * @param user The username of the individual who initiated the model version linking. + * @param identifier The unique identifier of the model that was linked. + */ + public GetModelVersionPreEvent(String user, NameIdentifier identifier) { + super(user, identifier); + } + + /** + * 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/LinkModelVersionPreEvent.java b/core/src/main/java/org/apache/gravitino/listener/api/event/LinkModelVersionPreEvent.java new file mode 100644 index 00000000000..576d7208f1e --- /dev/null +++ b/core/src/main/java/org/apache/gravitino/listener/api/event/LinkModelVersionPreEvent.java @@ -0,0 +1,61 @@ +/* + * 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 triggered before the linking of a model version. */ +@DeveloperApi +public class LinkModelVersionPreEvent extends ModelPreEvent { + private final ModelInfo modelInfo; + + /** + * Create a new {@link LinkModelVersionPreEvent} instance. + * + * @param user The username of the individual who initiated the model version linking. + * @param identifier The unique identifier of the model that was linked. + * @param modelInfo The final state of the model after linking. + */ + public LinkModelVersionPreEvent(String user, NameIdentifier identifier, ModelInfo modelInfo) { + super(user, identifier); + this.modelInfo = modelInfo; + } + + /** + * Retrieves the linked model version information. + * + * @return the model information. + */ + public ModelInfo linkedModelInfo() { + return modelInfo; + } + + /** + * 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/ListModelPreEvent.java b/core/src/main/java/org/apache/gravitino/listener/api/event/ListModelPreEvent.java new file mode 100644 index 00000000000..75b444b3d19 --- /dev/null +++ b/core/src/main/java/org/apache/gravitino/listener/api/event/ListModelPreEvent.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; + +import org.apache.gravitino.NameIdentifier; +import org.apache.gravitino.Namespace; +import org.apache.gravitino.annotation.DeveloperApi; + +/** Represents an event triggered before listing of models within a namespace. */ +@DeveloperApi +public class ListModelPreEvent extends ModelPreEvent { + private final Namespace namespace; + + /** + * Create a new {@link ListModelPreEvent} instance. + * + * @param user the user who triggered the event. + * @param namespace the namespace to list models from. + */ + public ListModelPreEvent(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 models were listed. + */ + 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/ListModelVersionsPreEvent.java b/core/src/main/java/org/apache/gravitino/listener/api/event/ListModelVersionsPreEvent.java new file mode 100644 index 00000000000..6aa83ed38b3 --- /dev/null +++ b/core/src/main/java/org/apache/gravitino/listener/api/event/ListModelVersionsPreEvent.java @@ -0,0 +1,54 @@ +/* + * 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 triggered before listing model versions. */ +@DeveloperApi +public class ListModelVersionsPreEvent extends ModelPreEvent { + private final ModelInfo modelInfo; + + public ListModelVersionsPreEvent(String user, NameIdentifier identifier, ModelInfo modelInfo) { + super(user, identifier); + this.modelInfo = modelInfo; + } + + /** + * Retrieves the model information containing the list of model versions. + * + * @return A {@link ModelInfo} instance containing the list of model versions. + */ + public ModelInfo listModelVersionInfo() { + return modelInfo; + } + + /** + * 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/ModelPreEvent.java b/core/src/main/java/org/apache/gravitino/listener/api/event/ModelPreEvent.java new file mode 100644 index 00000000000..11faf3deeb0 --- /dev/null +++ b/core/src/main/java/org/apache/gravitino/listener/api/event/ModelPreEvent.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; + +import org.apache.gravitino.NameIdentifier; +import org.apache.gravitino.annotation.DeveloperApi; + +/** Represents a pre-event for model operations. */ +@DeveloperApi +public abstract class ModelPreEvent extends PreEvent { + /** + * Create a new {@link ModelPreEvent} instance. + * + * @param user the user who triggered the event. + * @param identifier the identifier of the model being operated on. + */ + protected ModelPreEvent(String user, NameIdentifier identifier) { + super(user, identifier); + } +} diff --git a/core/src/main/java/org/apache/gravitino/listener/api/event/RegisterModelPreEvent.java b/core/src/main/java/org/apache/gravitino/listener/api/event/RegisterModelPreEvent.java new file mode 100644 index 00000000000..76274548348 --- /dev/null +++ b/core/src/main/java/org/apache/gravitino/listener/api/event/RegisterModelPreEvent.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; + +import org.apache.gravitino.NameIdentifier; +import org.apache.gravitino.listener.api.info.ModelInfo; + +/** Represents an event triggered before registering a model. */ +public class RegisterModelPreEvent extends ModelPreEvent { + private ModelInfo modelInfo; + + /** + * Create a new {@link RegisterModelPreEvent} instance. + * + * @param user the user who triggered the event. + * @param identifier the identifier of the model being operated on. + * @param modelInfo the model information. + */ + public RegisterModelPreEvent(String user, NameIdentifier identifier, ModelInfo modelInfo) { + super(user, identifier); + this.modelInfo = modelInfo; + } + + /** + * Retrieves the registered model information. + * + * @return the model information. + */ + public ModelInfo registeredModelInfo() { + return modelInfo; + } + + /** + * 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 c5aeaeb1af5..34a2eaab9fb 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 @@ -19,6 +19,7 @@ package org.apache.gravitino.listener.api.info; +import java.util.Collections; import java.util.Map; import javax.annotation.Nullable; import lombok.Getter; @@ -63,6 +64,16 @@ public ModelInfo(Model model, ModelVersionInfo[] modelVersions) { this.versions = modelVersions; } + public ModelInfo( + String name, Map properties, String comment, ModelVersionInfo[] versions) { + this.name = name; + this.properties = properties == null ? Collections.emptyMap() : properties; + this.comment = comment == null ? "" : comment; + this.audit = null; + this.lastVersion = 0; + this.versions = versions; + } + /** * Returns the comment of the model. * 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 545a6de8d81..1587a426061 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 @@ -79,18 +79,34 @@ void init() { @Test void testRegisterModelEvent() { - dispatcher.registerModel(existingIdentA, "comment", ImmutableMap.of("color", "#FFFFFF")); + dispatcher.registerModel(existingIdentA, "commentA", ImmutableMap.of("color", "#FFFFFF")); + // validate event Event event = dummyEventListener.popPostEvent(); Assertions.assertEquals(RegisterModelEvent.class, event.getClass()); Assertions.assertEquals(OperationType.REGISTER_MODEL, event.operationType()); Assertions.assertEquals(OperationStatus.SUCCESS, event.operationStatus()); + // validate model info RegisterModelEvent registerModelEvent = (RegisterModelEvent) event; ModelInfo modelInfo = registerModelEvent.registeredModelInfo(); Assertions.assertEquals("modelA", modelInfo.getName()); Assertions.assertEquals("commentA", modelInfo.getComment()); Assertions.assertEquals(ImmutableMap.of("color", "#FFFFFF"), modelInfo.getProperties()); Assertions.assertNull(modelInfo.modelVersions()); + + // validate pre-event + PreEvent preEvent = dummyEventListener.popPreEvent(); + Assertions.assertEquals(RegisterModelPreEvent.class, preEvent.getClass()); + Assertions.assertEquals(OperationType.REGISTER_MODEL, preEvent.operationType()); + Assertions.assertEquals(OperationStatus.UNPROCESSED, preEvent.operationStatus()); + + // validate model info + RegisterModelPreEvent registerModelPreEvent = (RegisterModelPreEvent) preEvent; + ModelInfo modelInfoPreEvent = registerModelPreEvent.registeredModelInfo(); + Assertions.assertEquals("modelA", modelInfoPreEvent.getName()); + Assertions.assertEquals("commentA", modelInfoPreEvent.getComment()); + Assertions.assertEquals(ImmutableMap.of("color", "#FFFFFF"), modelInfoPreEvent.getProperties()); + Assertions.assertNull(modelInfoPreEvent.modelVersions()); } @Test @@ -109,10 +125,22 @@ void testGetModelEvent() { Assertions.assertEquals("commentA", modelInfo.getComment()); Assertions.assertEquals(ImmutableMap.of("color", "#FFFFFF"), modelInfo.getProperties()); Assertions.assertNull(modelInfo.modelVersions()); + + // validate pre-event + PreEvent preEvent = dummyEventListener.popPreEvent(); + Assertions.assertEquals(GetModelPreEvent.class, preEvent.getClass()); + Assertions.assertEquals(OperationType.GET_MODEL, preEvent.operationType()); + Assertions.assertEquals(OperationStatus.UNPROCESSED, preEvent.operationStatus()); + + GetModelPreEvent getModelPreEvent = (GetModelPreEvent) preEvent; + Assertions.assertEquals(OperationType.GET_MODEL, getModelPreEvent.operationType()); + Assertions.assertEquals(OperationStatus.UNPROCESSED, getModelPreEvent.operationStatus()); + Assertions.assertEquals(existingIdentA, getModelPreEvent.identifier()); } @Test void testDeleteExistsModelEvent() { + // validate event boolean isExists = dispatcher.deleteModel(existingIdentA); Event event = dummyEventListener.popPostEvent(); Assertions.assertEquals(DeleteModelEvent.class, event.getClass()); @@ -120,15 +148,29 @@ void testDeleteExistsModelEvent() { Assertions.assertEquals(OperationStatus.SUCCESS, event.operationStatus()); Assertions.assertTrue(isExists); + // validate model info DeleteModelEvent deleteModelEvent = (DeleteModelEvent) event; Assertions.assertEquals(existingIdentA, deleteModelEvent.identifier()); Assertions.assertEquals(DeleteModelEvent.class, deleteModelEvent.getClass()); Assertions.assertEquals(OperationType.DELETE_MODEL, deleteModelEvent.operationType()); Assertions.assertEquals(OperationStatus.SUCCESS, deleteModelEvent.operationStatus()); + + // validate pre-event + PreEvent preEvent = dummyEventListener.popPreEvent(); + Assertions.assertEquals(DeleteModelPreEvent.class, preEvent.getClass()); + Assertions.assertEquals(OperationType.DELETE_MODEL, preEvent.operationType()); + Assertions.assertEquals(OperationStatus.UNPROCESSED, preEvent.operationStatus()); + + DeleteModelPreEvent deleteModelPreEvent = (DeleteModelPreEvent) preEvent; + Assertions.assertEquals(DeleteModelPreEvent.class, deleteModelPreEvent.getClass()); + Assertions.assertEquals(OperationType.DELETE_MODEL, deleteModelPreEvent.operationType()); + Assertions.assertEquals(OperationStatus.UNPROCESSED, deleteModelPreEvent.operationStatus()); + Assertions.assertEquals(existingIdentA, deleteModelPreEvent.identifier()); } @Test void testDeleteNotExistsModelEvent() { + // validate event boolean isExists = dispatcher.deleteModel(notExistingIdent); Event event = dummyEventListener.popPostEvent(); Assertions.assertEquals(DeleteModelEvent.class, event.getClass()); @@ -136,14 +178,27 @@ void testDeleteNotExistsModelEvent() { Assertions.assertEquals(OperationStatus.UNPROCESSED, event.operationStatus()); Assertions.assertFalse(isExists); + // validate model info DeleteModelEvent deleteModelEvent = (DeleteModelEvent) event; Assertions.assertEquals(DeleteModelEvent.class, deleteModelEvent.getClass()); Assertions.assertEquals(OperationType.DELETE_MODEL, deleteModelEvent.operationType()); Assertions.assertEquals(OperationStatus.UNPROCESSED, deleteModelEvent.operationStatus()); + + // validate pre-event + PreEvent preEvent = dummyEventListener.popPreEvent(); + Assertions.assertEquals(DeleteModelPreEvent.class, preEvent.getClass()); + Assertions.assertEquals(OperationType.DELETE_MODEL, preEvent.operationType()); + Assertions.assertEquals(OperationStatus.UNPROCESSED, preEvent.operationStatus()); + + DeleteModelPreEvent deleteModelPreEvent = (DeleteModelPreEvent) preEvent; + Assertions.assertEquals(DeleteModelPreEvent.class, deleteModelPreEvent.getClass()); + Assertions.assertEquals(OperationType.DELETE_MODEL, deleteModelPreEvent.operationType()); + Assertions.assertEquals(OperationStatus.UNPROCESSED, deleteModelPreEvent.operationStatus()); } @Test void testListModelEvent() { + // validate event NameIdentifier[] nameIdentifiers = dispatcher.listModels(namespace); Event event = dummyEventListener.popPostEvent(); Assertions.assertEquals(ListModelEvent.class, event.getClass()); @@ -152,10 +207,18 @@ void testListModelEvent() { ListModelEvent listModelEvent = (ListModelEvent) event; Assertions.assertEquals(namespace, listModelEvent.namespace()); - Assertions.assertEquals(2, nameIdentifiers.length); Assertions.assertEquals(existingIdentA, nameIdentifiers[0]); Assertions.assertEquals(existingIdentB, nameIdentifiers[1]); + + // validate pre-event + PreEvent preEvent = dummyEventListener.popPreEvent(); + Assertions.assertEquals(ListModelPreEvent.class, preEvent.getClass()); + Assertions.assertEquals(OperationType.LIST_MODEL, preEvent.operationType()); + Assertions.assertEquals(OperationStatus.UNPROCESSED, preEvent.operationStatus()); + + ListModelPreEvent listModelPreEvent = (ListModelPreEvent) preEvent; + Assertions.assertEquals(namespace, listModelPreEvent.namespace()); } @Test @@ -185,6 +248,27 @@ void testLinkModelVersionEvent() { Assertions.assertEquals("versionInfoA", modelVersionInfos[0].getComment()); Assertions.assertEquals("uriA", modelVersionInfos[0].getUri()); Assertions.assertEquals("aliasProduction", modelVersionInfos[0].getAliases()[0]); + + // validate pre-event + PreEvent preEvent = dummyEventListener.popPreEvent(); + Assertions.assertEquals(LinkModelVersionPreEvent.class, preEvent.getClass()); + Assertions.assertEquals(OperationType.LINK_MODEL_VERSION, preEvent.operationType()); + Assertions.assertEquals(OperationStatus.UNPROCESSED, preEvent.operationStatus()); + + // validate model info + LinkModelVersionPreEvent linkModelVersionPreEvent = (LinkModelVersionPreEvent) preEvent; + ModelInfo modelInfoPreEvent = linkModelVersionPreEvent.linkedModelInfo(); + Assertions.assertEquals("modelA", modelInfoPreEvent.getName()); + Assertions.assertEquals("commentA", modelInfoPreEvent.getComment()); + Assertions.assertEquals(ImmutableMap.of("color", "#FFFFFF"), modelInfoPreEvent.getProperties()); + + // validate model version info + ModelVersionInfo[] modelVersionInfosPreEvent = modelInfoPreEvent.modelVersions(); + Assertions.assertNotNull(modelVersionInfosPreEvent); + Assertions.assertEquals(1, modelVersionInfosPreEvent.length); + Assertions.assertEquals("versionInfoA", modelVersionInfosPreEvent[0].getComment()); + Assertions.assertEquals("uriA", modelVersionInfosPreEvent[0].getUri()); + Assertions.assertEquals("aliasProduction", modelVersionInfosPreEvent[0].getAliases()[0]); } @Test @@ -209,6 +293,12 @@ void testGetModelVersionEventViaVersion() { Assertions.assertEquals("model version versionInfoA", modelVersionInfos[0].getComment()); Assertions.assertEquals("uriA", modelVersionInfos[0].getUri()); Assertions.assertEquals("aliasProduction", modelVersionInfos[0].getAliases()[0]); + + // validate pre-event + PreEvent preEvent = dummyEventListener.popPreEvent(); + Assertions.assertEquals(GetModelVersionPreEvent.class, preEvent.getClass()); + Assertions.assertEquals(OperationType.GET_MODEL_VERSION, preEvent.operationType()); + Assertions.assertEquals(OperationStatus.UNPROCESSED, preEvent.operationStatus()); } @Test @@ -233,6 +323,12 @@ void testGetModelVersionEventViaAlias() { Assertions.assertEquals("model version versionInfoB", modelVersionInfos[0].getComment()); Assertions.assertEquals("uriB", modelVersionInfos[0].getUri()); Assertions.assertEquals("aliasTest", modelVersionInfos[0].getAliases()[0]); + + // validate pre-event + PreEvent preEvent = dummyEventListener.popPreEvent(); + Assertions.assertEquals(GetModelVersionPreEvent.class, preEvent.getClass()); + Assertions.assertEquals(OperationType.GET_MODEL_VERSION, preEvent.operationType()); + Assertions.assertEquals(OperationStatus.UNPROCESSED, preEvent.operationStatus()); } @Test @@ -251,6 +347,12 @@ void testDeleteModelVersionEventViaVersion() { Assertions.assertEquals( OperationType.DELETE_MODEL_VERSION, deleteModelVersionEvent.operationType()); Assertions.assertEquals(OperationStatus.SUCCESS, deleteModelVersionEvent.operationStatus()); + + // validate pre-event + PreEvent preEvent = dummyEventListener.popPreEvent(); + Assertions.assertEquals(DeleteModelVersionPreEvent.class, preEvent.getClass()); + Assertions.assertEquals(OperationType.DELETE_MODEL_VERSION, preEvent.operationType()); + Assertions.assertEquals(OperationStatus.UNPROCESSED, preEvent.operationStatus()); } @Test @@ -269,6 +371,12 @@ void testDeleteModelVersionEventViaAlias() { Assertions.assertEquals( OperationType.DELETE_MODEL_VERSION, deleteModelVersionEvent.operationType()); Assertions.assertEquals(OperationStatus.SUCCESS, deleteModelVersionEvent.operationStatus()); + + // validate pre-event + PreEvent preEvent = dummyEventListener.popPreEvent(); + Assertions.assertEquals(DeleteModelVersionPreEvent.class, preEvent.getClass()); + Assertions.assertEquals(OperationType.DELETE_MODEL_VERSION, preEvent.operationType()); + Assertions.assertEquals(OperationStatus.UNPROCESSED, preEvent.operationStatus()); } @Test @@ -286,6 +394,12 @@ void testDeleteModelVersionEventViaVersionNotExists() { Assertions.assertEquals( OperationType.DELETE_MODEL_VERSION, deleteModelVersionEvent.operationType()); Assertions.assertEquals(OperationStatus.UNPROCESSED, deleteModelVersionEvent.operationStatus()); + + // validate pre-event + PreEvent preEvent = dummyEventListener.popPreEvent(); + Assertions.assertEquals(DeleteModelVersionPreEvent.class, preEvent.getClass()); + Assertions.assertEquals(OperationType.DELETE_MODEL_VERSION, preEvent.operationType()); + Assertions.assertEquals(OperationStatus.UNPROCESSED, preEvent.operationStatus()); } @Test @@ -306,6 +420,20 @@ void testListModelVersionsEvent() { Assertions.assertEquals("commentA", modelInfo.getComment()); Assertions.assertEquals(ImmutableMap.of("color", "#FFFFFF"), modelInfo.getProperties()); Assertions.assertNull(modelInfo.modelVersions()); + + // validate pre-event + PreEvent preEvent = dummyEventListener.popPreEvent(); + Assertions.assertEquals(ListModelVersionsPreEvent.class, preEvent.getClass()); + Assertions.assertEquals(OperationType.LIST_MODEL_VERSIONS, preEvent.operationType()); + Assertions.assertEquals(OperationStatus.UNPROCESSED, preEvent.operationStatus()); + + // validate model info + ListModelVersionsPreEvent listModelVersionsPreEvent = (ListModelVersionsPreEvent) preEvent; + ModelInfo modelInfoPreEvent = listModelVersionsPreEvent.listModelVersionInfo(); + Assertions.assertEquals("modelA", modelInfoPreEvent.getName()); + Assertions.assertEquals("commentA", modelInfoPreEvent.getComment()); + Assertions.assertEquals(ImmutableMap.of("color", "#FFFFFF"), modelInfoPreEvent.getProperties()); + Assertions.assertNull(modelInfoPreEvent.modelVersions()); } private ModelDispatcher mockExceptionModelDispatcher() { @@ -319,9 +447,9 @@ private ModelDispatcher mockExceptionModelDispatcher() { private ModelDispatcher mockTagDispatcher() { ModelDispatcher dispatcher = mock(ModelDispatcher.class); - when(dispatcher.registerModel(existingIdentA, "comment", ImmutableMap.of("color", "#FFFFFF"))) + when(dispatcher.registerModel(existingIdentA, "commentA", ImmutableMap.of("color", "#FFFFFF"))) .thenReturn(modelA); - when(dispatcher.registerModel(existingIdentB, "comment", ImmutableMap.of("color", "#FFFFFF"))) + when(dispatcher.registerModel(existingIdentB, "commentB", ImmutableMap.of("color", "#FFFFFF"))) .thenReturn(modelB); when(dispatcher.getModel(existingIdentA)).thenReturn(modelA); From 416d3b44df481f6219c95b97435d3d9c29e133f8 Mon Sep 17 00:00:00 2001 From: pancx Date: Wed, 15 Jan 2025 16:10:10 +0800 Subject: [PATCH 7/7] [#6067] improvement(core): Support model pre event to Gravitino server fix some issues. --- .../apache/gravitino/listener/api/event/GetModelPreEvent.java | 2 ++ .../gravitino/listener/api/event/RegisterModelPreEvent.java | 2 ++ 2 files changed, 4 insertions(+) diff --git a/core/src/main/java/org/apache/gravitino/listener/api/event/GetModelPreEvent.java b/core/src/main/java/org/apache/gravitino/listener/api/event/GetModelPreEvent.java index 0c21e78814b..1161a156886 100644 --- a/core/src/main/java/org/apache/gravitino/listener/api/event/GetModelPreEvent.java +++ b/core/src/main/java/org/apache/gravitino/listener/api/event/GetModelPreEvent.java @@ -20,8 +20,10 @@ package org.apache.gravitino.listener.api.event; import org.apache.gravitino.NameIdentifier; +import org.apache.gravitino.annotation.DeveloperApi; /** Represents an event triggered before getting a model. */ +@DeveloperApi public class GetModelPreEvent extends ModelPreEvent { /** * Create a new {@link GetModelPreEvent} instance. diff --git a/core/src/main/java/org/apache/gravitino/listener/api/event/RegisterModelPreEvent.java b/core/src/main/java/org/apache/gravitino/listener/api/event/RegisterModelPreEvent.java index 76274548348..0a2315c91f1 100644 --- a/core/src/main/java/org/apache/gravitino/listener/api/event/RegisterModelPreEvent.java +++ b/core/src/main/java/org/apache/gravitino/listener/api/event/RegisterModelPreEvent.java @@ -20,9 +20,11 @@ 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 triggered before registering a model. */ +@DeveloperApi public class RegisterModelPreEvent extends ModelPreEvent { private ModelInfo modelInfo;