This is an automated email from the ASF dual-hosted git repository.
liuxun pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/gravitino.git
The following commit(s) were added to refs/heads/main by this push:
new f3b4c3a40 [#4374] feat(client): Add owner operations for client (#4397)
f3b4c3a40 is described below
commit f3b4c3a405fc9229806bcb520fc9c6bba0ab9440
Author: roryqi <[email protected]>
AuthorDate: Wed Aug 7 18:17:08 2024 +0800
[#4374] feat(client): Add owner operations for client (#4397)
### What changes were proposed in this pull request?
Add owner operations for client
### Why are the changes needed?
Fix: #4374
### Does this PR introduce _any_ user-facing change?
I will add the document later.
### How was this patch tested?
Add UTS.
---
.../exceptions/NoSuchMetadataObjectException.java | 48 ++++++++
.../org/apache/gravitino/client/ErrorHandlers.java | 40 ++++++
.../apache/gravitino/client/GravitinoClient.java | 30 +++++
.../apache/gravitino/client/GravitinoMetalake.java | 59 +++++++++
.../org/apache/gravitino/client/TestOwner.java | 135 +++++++++++++++++++++
.../gravitino/authorization/OwnerManager.java | 3 +-
.../storage/relational/mapper/GroupMetaMapper.java | 12 --
.../storage/relational/mapper/OwnerMetaMapper.java | 59 +++++++--
.../storage/relational/mapper/UserMetaMapper.java | 12 --
.../relational/service/GroupMetaService.java | 24 ++--
.../relational/service/OwnerMetaService.java | 41 ++++---
.../relational/service/UserMetaService.java | 24 ++--
.../gravitino/authorization/TestOwnerManager.java | 13 ++
.../relational/service/TestGroupMetaService.java | 17 +++
.../relational/service/TestUserMetaService.java | 15 +++
15 files changed, 447 insertions(+), 85 deletions(-)
diff --git
a/api/src/main/java/org/apache/gravitino/exceptions/NoSuchMetadataObjectException.java
b/api/src/main/java/org/apache/gravitino/exceptions/NoSuchMetadataObjectException.java
new file mode 100644
index 000000000..97330f1a7
--- /dev/null
+++
b/api/src/main/java/org/apache/gravitino/exceptions/NoSuchMetadataObjectException.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.exceptions;
+
+import com.google.errorprone.annotations.FormatMethod;
+import com.google.errorprone.annotations.FormatString;
+
+/** Exception thrown when a metadata object with specified name doesn't exist.
*/
+public class NoSuchMetadataObjectException extends NotFoundException {
+ /**
+ * Constructs a new exception with the specified detail message.
+ *
+ * @param message the detail message.
+ * @param args the arguments to the message.
+ */
+ @FormatMethod
+ public NoSuchMetadataObjectException(@FormatString String message, Object...
args) {
+ super(message, args);
+ }
+
+ /**
+ * Constructs a new exception with the specified detail message and cause.
+ *
+ * @param cause the cause.
+ * @param message the detail message.
+ * @param args the arguments to the message.
+ */
+ @FormatMethod
+ public NoSuchMetadataObjectException(Throwable cause, String message,
Object... args) {
+ super(cause, message, args);
+ }
+}
diff --git
a/clients/client-java/src/main/java/org/apache/gravitino/client/ErrorHandlers.java
b/clients/client-java/src/main/java/org/apache/gravitino/client/ErrorHandlers.java
index f98ee7708..4741e8462 100644
---
a/clients/client-java/src/main/java/org/apache/gravitino/client/ErrorHandlers.java
+++
b/clients/client-java/src/main/java/org/apache/gravitino/client/ErrorHandlers.java
@@ -35,6 +35,7 @@ import
org.apache.gravitino.exceptions.MetalakeAlreadyExistsException;
import org.apache.gravitino.exceptions.NoSuchCatalogException;
import org.apache.gravitino.exceptions.NoSuchFilesetException;
import org.apache.gravitino.exceptions.NoSuchGroupException;
+import org.apache.gravitino.exceptions.NoSuchMetadataObjectException;
import org.apache.gravitino.exceptions.NoSuchMetalakeException;
import org.apache.gravitino.exceptions.NoSuchPartitionException;
import org.apache.gravitino.exceptions.NoSuchRoleException;
@@ -188,6 +189,15 @@ public class ErrorHandlers {
return TagErrorHandler.INSTANCE;
}
+ /**
+ * Creates an error handler specific to Owner operations.
+ *
+ * @return A Consumer representing the Owner error handler.
+ */
+ public static Consumer<ErrorResponse> ownerErrorHandler() {
+ return OwnerErrorHandler.INSTANCE;
+ }
+
private ErrorHandlers() {}
/**
@@ -713,6 +723,36 @@ public class ErrorHandlers {
}
}
+ /** Error handler specific to Owner operations. */
+ @SuppressWarnings("FormatStringAnnotation")
+ private static class OwnerErrorHandler extends RestErrorHandler {
+
+ private static final OwnerErrorHandler INSTANCE = new OwnerErrorHandler();
+
+ @Override
+ public void accept(ErrorResponse errorResponse) {
+ String errorMessage = formatErrorMessage(errorResponse);
+
+ switch (errorResponse.getCode()) {
+ case ErrorConstants.ILLEGAL_ARGUMENTS_CODE:
+ throw new IllegalArgumentException(errorMessage);
+
+ case ErrorConstants.NOT_FOUND_CODE:
+ if
(errorResponse.getType().equals(NoSuchMetadataObjectException.class.getSimpleName()))
{
+ throw new NoSuchMetadataObjectException(errorMessage);
+ } else {
+ throw new NotFoundException(errorMessage);
+ }
+
+ case ErrorConstants.INTERNAL_ERROR_CODE:
+ throw new RuntimeException(errorMessage);
+
+ default:
+ super.accept(errorResponse);
+ }
+ }
+ }
+
/** Generic error handler for REST requests. */
private static class RestErrorHandler extends ErrorHandler {
private static final ErrorHandler INSTANCE = new RestErrorHandler();
diff --git
a/clients/client-java/src/main/java/org/apache/gravitino/client/GravitinoClient.java
b/clients/client-java/src/main/java/org/apache/gravitino/client/GravitinoClient.java
index 335117cac..962bb09e1 100644
---
a/clients/client-java/src/main/java/org/apache/gravitino/client/GravitinoClient.java
+++
b/clients/client-java/src/main/java/org/apache/gravitino/client/GravitinoClient.java
@@ -22,10 +22,13 @@ package org.apache.gravitino.client;
import com.google.common.base.Preconditions;
import java.util.List;
import java.util.Map;
+import java.util.Optional;
import org.apache.gravitino.Catalog;
import org.apache.gravitino.CatalogChange;
+import org.apache.gravitino.MetadataObject;
import org.apache.gravitino.SupportsCatalogs;
import org.apache.gravitino.authorization.Group;
+import org.apache.gravitino.authorization.Owner;
import org.apache.gravitino.authorization.Role;
import org.apache.gravitino.authorization.SecurableObject;
import org.apache.gravitino.authorization.User;
@@ -33,10 +36,12 @@ import
org.apache.gravitino.exceptions.CatalogAlreadyExistsException;
import org.apache.gravitino.exceptions.GroupAlreadyExistsException;
import org.apache.gravitino.exceptions.NoSuchCatalogException;
import org.apache.gravitino.exceptions.NoSuchGroupException;
+import org.apache.gravitino.exceptions.NoSuchMetadataObjectException;
import org.apache.gravitino.exceptions.NoSuchMetalakeException;
import org.apache.gravitino.exceptions.NoSuchRoleException;
import org.apache.gravitino.exceptions.NoSuchTagException;
import org.apache.gravitino.exceptions.NoSuchUserException;
+import org.apache.gravitino.exceptions.NotFoundException;
import org.apache.gravitino.exceptions.RoleAlreadyExistsException;
import org.apache.gravitino.exceptions.TagAlreadyExistsException;
import org.apache.gravitino.exceptions.UserAlreadyExistsException;
@@ -308,6 +313,31 @@ public class GravitinoClient extends GravitinoClientBase
return getMetalake().revokeRolesFromGroup(roles, group);
}
+ /**
+ * Get the owner of a metadata object.
+ *
+ * @param object The metadata object
+ * @return The owner of the metadata object. If the metadata object doesn't
set the owner, it will
+ * return Optional.empty().
+ * @throws NoSuchMetadataObjectException If the metadata object is not found.
+ */
+ public Optional<Owner> getOwner(MetadataObject object) throws
NoSuchMetadataObjectException {
+ return getMetalake().getOwner(object);
+ }
+
+ /**
+ * Set the owner of a metadata object.
+ *
+ * @param object The metadata object.
+ * @param ownerName The name of the owner
+ * @param ownerType The type of the owner, The owner can be a user or a
group.
+ * @throws NotFoundException If the metadata object isn't found or the owner
doesn't exist.
+ */
+ public void setOwner(MetadataObject object, String ownerName, Owner.Type
ownerType)
+ throws NotFoundException {
+ getMetalake().setOwner(object, ownerName, ownerType);
+ }
+
/**
* Creates a new builder for constructing a GravitinoClient.
*
diff --git
a/clients/client-java/src/main/java/org/apache/gravitino/client/GravitinoMetalake.java
b/clients/client-java/src/main/java/org/apache/gravitino/client/GravitinoMetalake.java
index 7d527b1ec..b7fd5d943 100644
---
a/clients/client-java/src/main/java/org/apache/gravitino/client/GravitinoMetalake.java
+++
b/clients/client-java/src/main/java/org/apache/gravitino/client/GravitinoMetalake.java
@@ -24,14 +24,18 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
+import java.util.Locale;
import java.util.Map;
+import java.util.Optional;
import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils;
import org.apache.gravitino.Catalog;
import org.apache.gravitino.CatalogChange;
+import org.apache.gravitino.MetadataObject;
import org.apache.gravitino.NameIdentifier;
import org.apache.gravitino.SupportsCatalogs;
import org.apache.gravitino.authorization.Group;
+import org.apache.gravitino.authorization.Owner;
import org.apache.gravitino.authorization.Role;
import org.apache.gravitino.authorization.SecurableObject;
import org.apache.gravitino.authorization.User;
@@ -42,6 +46,7 @@ import org.apache.gravitino.dto.requests.CatalogCreateRequest;
import org.apache.gravitino.dto.requests.CatalogUpdateRequest;
import org.apache.gravitino.dto.requests.CatalogUpdatesRequest;
import org.apache.gravitino.dto.requests.GroupAddRequest;
+import org.apache.gravitino.dto.requests.OwnerSetRequest;
import org.apache.gravitino.dto.requests.RoleCreateRequest;
import org.apache.gravitino.dto.requests.RoleGrantRequest;
import org.apache.gravitino.dto.requests.RoleRevokeRequest;
@@ -57,8 +62,10 @@ import org.apache.gravitino.dto.responses.EntityListResponse;
import org.apache.gravitino.dto.responses.ErrorResponse;
import org.apache.gravitino.dto.responses.GroupResponse;
import org.apache.gravitino.dto.responses.NameListResponse;
+import org.apache.gravitino.dto.responses.OwnerResponse;
import org.apache.gravitino.dto.responses.RemoveResponse;
import org.apache.gravitino.dto.responses.RoleResponse;
+import org.apache.gravitino.dto.responses.SetResponse;
import org.apache.gravitino.dto.responses.TagListResponse;
import org.apache.gravitino.dto.responses.TagResponse;
import org.apache.gravitino.dto.responses.UserResponse;
@@ -66,10 +73,12 @@ import
org.apache.gravitino.exceptions.CatalogAlreadyExistsException;
import org.apache.gravitino.exceptions.GroupAlreadyExistsException;
import org.apache.gravitino.exceptions.NoSuchCatalogException;
import org.apache.gravitino.exceptions.NoSuchGroupException;
+import org.apache.gravitino.exceptions.NoSuchMetadataObjectException;
import org.apache.gravitino.exceptions.NoSuchMetalakeException;
import org.apache.gravitino.exceptions.NoSuchRoleException;
import org.apache.gravitino.exceptions.NoSuchTagException;
import org.apache.gravitino.exceptions.NoSuchUserException;
+import org.apache.gravitino.exceptions.NotFoundException;
import org.apache.gravitino.exceptions.RoleAlreadyExistsException;
import org.apache.gravitino.exceptions.TagAlreadyExistsException;
import org.apache.gravitino.exceptions.UserAlreadyExistsException;
@@ -88,6 +97,7 @@ public class GravitinoMetalake extends MetalakeDTO implements
SupportsCatalogs,
private static final String API_METALAKES_USERS_PATH =
"api/metalakes/%s/users/%s";
private static final String API_METALAKES_GROUPS_PATH =
"api/metalakes/%s/groups/%s";
private static final String API_METALAKES_ROLES_PATH =
"api/metalakes/%s/roles/%s";
+ private static final String API_METALAKES_OWNERS_PATH =
"api/metalakes/%s/owners/%s";
private static final String BLANK_PLACE_HOLDER = "";
private static final String API_METALAKES_TAGS_PATH =
"api/metalakes/%s/tags";
@@ -762,6 +772,55 @@ public class GravitinoMetalake extends MetalakeDTO
implements SupportsCatalogs,
return resp.getGroup();
}
+ /**
+ * Get the owner of a metadata object.
+ *
+ * @param object The metadata object
+ * @return The owner of the metadata object. If the metadata object doesn't
set the owner, it will
+ * return Optional.empty().
+ * @throws NoSuchMetadataObjectException If the metadata object is not found.
+ */
+ public Optional<Owner> getOwner(MetadataObject object) throws
NoSuchMetadataObjectException {
+ OwnerResponse resp =
+ restClient.get(
+ String.format(
+ API_METALAKES_OWNERS_PATH,
+ this.name(),
+ String.format(
+ "%s/%s", object.type().name().toLowerCase(Locale.ROOT),
object.fullName())),
+ OwnerResponse.class,
+ Collections.emptyMap(),
+ ErrorHandlers.ownerErrorHandler());
+ resp.validate();
+ return Optional.ofNullable(resp.getOwner());
+ }
+
+ /**
+ * Set the owner of a metadata object.
+ *
+ * @param object The metadata object.
+ * @param ownerName The name of the owner
+ * @param ownerType The type of the owner, The owner can be a user or a
group.
+ * @throws NotFoundException If the metadata object isn't found or the owner
doesn't exist.
+ */
+ public void setOwner(MetadataObject object, String ownerName, Owner.Type
ownerType)
+ throws NotFoundException {
+ OwnerSetRequest request = new OwnerSetRequest(ownerName, ownerType);
+ request.validate();
+ SetResponse resp =
+ restClient.put(
+ String.format(
+ API_METALAKES_OWNERS_PATH,
+ this.name(),
+ String.format(
+ "%s/%s", object.type().name().toLowerCase(Locale.ROOT),
object.fullName())),
+ request,
+ SetResponse.class,
+ Collections.emptyMap(),
+ ErrorHandlers.ownerErrorHandler());
+ resp.validate();
+ }
+
static class Builder extends MetalakeDTO.Builder<Builder> {
private RESTClient restClient;
diff --git
a/clients/client-java/src/test/java/org/apache/gravitino/client/TestOwner.java
b/clients/client-java/src/test/java/org/apache/gravitino/client/TestOwner.java
new file mode 100644
index 000000000..dc9d801b2
--- /dev/null
+++
b/clients/client-java/src/test/java/org/apache/gravitino/client/TestOwner.java
@@ -0,0 +1,135 @@
+/*
+ * 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.client;
+
+import static org.apache.hc.core5.http.HttpStatus.SC_NOT_FOUND;
+import static org.apache.hc.core5.http.HttpStatus.SC_OK;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import java.time.Instant;
+import java.util.Locale;
+import java.util.Optional;
+import org.apache.gravitino.MetadataObject;
+import org.apache.gravitino.MetadataObjects;
+import org.apache.gravitino.authorization.Owner;
+import org.apache.gravitino.dto.AuditDTO;
+import org.apache.gravitino.dto.MetalakeDTO;
+import org.apache.gravitino.dto.authorization.OwnerDTO;
+import org.apache.gravitino.dto.requests.OwnerSetRequest;
+import org.apache.gravitino.dto.responses.ErrorResponse;
+import org.apache.gravitino.dto.responses.MetalakeResponse;
+import org.apache.gravitino.dto.responses.OwnerResponse;
+import org.apache.gravitino.dto.responses.SetResponse;
+import org.apache.gravitino.exceptions.NoSuchMetadataObjectException;
+import org.apache.gravitino.exceptions.NotFoundException;
+import org.apache.hc.core5.http.HttpStatus;
+import org.apache.hc.core5.http.Method;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+
+public class TestOwner extends TestBase {
+
+ private static final String metalakeName = "testMetalake";
+ private static final String API_OWNER_PATH = "api/metalakes/%s/owners/%s";
+ private static GravitinoClient gravitinoClient;
+
+ @BeforeAll
+ public static void setUp() throws Exception {
+ TestBase.setUp();
+
+ TestGravitinoMetalake.createMetalake(client, metalakeName);
+
+ MetalakeDTO mockMetalake =
+ MetalakeDTO.builder()
+ .withName(metalakeName)
+ .withComment("comment")
+ .withAudit(
+
AuditDTO.builder().withCreator("creator").withCreateTime(Instant.now()).build())
+ .build();
+ MetalakeResponse resp = new MetalakeResponse(mockMetalake);
+ buildMockResource(Method.GET, "/api/metalakes/" + metalakeName, null,
resp, HttpStatus.SC_OK);
+
+ gravitinoClient =
+ GravitinoClient.builder("http://127.0.0.1:" +
mockServer.getLocalPort())
+ .withMetalake(metalakeName)
+ .withVersionCheckDisabled()
+ .build();
+ }
+
+ @Test
+ public void testGetOwner() throws JsonProcessingException {
+ MetadataObject object = MetadataObjects.of(null, metalakeName,
MetadataObject.Type.METALAKE);
+ String ownerPath =
+ withSlash(
+ String.format(
+ API_OWNER_PATH,
+ metalakeName,
+ String.format(
+ "%s/%s", object.type().name().toLowerCase(Locale.ROOT),
object.fullName())));
+ OwnerDTO ownerDTO =
OwnerDTO.builder().withName("test").withType(Owner.Type.USER).build();
+ OwnerResponse resp = new OwnerResponse(ownerDTO);
+ buildMockResource(Method.GET, ownerPath, null, resp, SC_OK);
+ Optional<Owner> owner = gravitinoClient.getOwner(object);
+ Assertions.assertTrue(owner.isPresent());
+ Assertions.assertEquals("test", owner.get().name());
+ Assertions.assertEquals(Owner.Type.USER, owner.get().type());
+
+ // no owner case
+ OwnerResponse noOwnerResp = new OwnerResponse(null);
+ buildMockResource(Method.GET, ownerPath, null, noOwnerResp, SC_OK);
+ Assertions.assertFalse(gravitinoClient.getOwner(object).isPresent());
+
+ // no such metadata object exception
+ ErrorResponse errorResp1 =
+
ErrorResponse.notFound(NoSuchMetadataObjectException.class.getSimpleName(),
"not found");
+ buildMockResource(Method.GET, ownerPath, null, errorResp1, SC_NOT_FOUND);
+ Throwable ex1 =
+ Assertions.assertThrows(
+ NoSuchMetadataObjectException.class, () ->
gravitinoClient.getOwner(object));
+ Assertions.assertTrue(ex1.getMessage().contains("not found"));
+ }
+
+ @Test
+ public void testSetOwner() throws JsonProcessingException {
+ MetadataObject object = MetadataObjects.of(null, metalakeName,
MetadataObject.Type.METALAKE);
+ String ownerPath =
+ withSlash(
+ String.format(
+ API_OWNER_PATH,
+ metalakeName,
+ String.format(
+ "%s/%s", object.type().name().toLowerCase(Locale.ROOT),
object.fullName())));
+ OwnerSetRequest request = new OwnerSetRequest("test", Owner.Type.USER);
+ SetResponse response = new SetResponse(true);
+ buildMockResource(Method.PUT, ownerPath, request, response, SC_OK);
+
+ Assertions.assertDoesNotThrow(() -> gravitinoClient.setOwner(object,
"test", Owner.Type.USER));
+
+ // not found exception
+ ErrorResponse errorResp1 =
+ ErrorResponse.notFound(NotFoundException.class.getSimpleName(), "not
found");
+ buildMockResource(Method.PUT, ownerPath, request, errorResp1,
SC_NOT_FOUND);
+ Throwable ex1 =
+ Assertions.assertThrows(
+ NotFoundException.class,
+ () -> gravitinoClient.setOwner(object, "test", Owner.Type.USER));
+ Assertions.assertTrue(ex1.getMessage().contains("not found"));
+ }
+}
diff --git
a/core/src/main/java/org/apache/gravitino/authorization/OwnerManager.java
b/core/src/main/java/org/apache/gravitino/authorization/OwnerManager.java
index 9fa1694e9..f79164285 100644
--- a/core/src/main/java/org/apache/gravitino/authorization/OwnerManager.java
+++ b/core/src/main/java/org/apache/gravitino/authorization/OwnerManager.java
@@ -27,6 +27,7 @@ import org.apache.gravitino.MetadataObject;
import org.apache.gravitino.NameIdentifier;
import org.apache.gravitino.SupportsRelationOperations;
import org.apache.gravitino.exceptions.NoSuchEntityException;
+import org.apache.gravitino.exceptions.NoSuchMetadataObjectException;
import org.apache.gravitino.exceptions.NotFoundException;
import org.apache.gravitino.lock.LockType;
import org.apache.gravitino.lock.TreeLockUtils;
@@ -168,7 +169,7 @@ public class OwnerManager {
}
return Optional.of(owner);
} catch (NoSuchEntityException nse) {
- throw new NotFoundException(
+ throw new NoSuchMetadataObjectException(
"The metadata object of %s isn't found", metadataObject.fullName());
} catch (IOException ioe) {
LOG.info("Fail to get the owner of entity {}",
metadataObject.fullName(), ioe);
diff --git
a/core/src/main/java/org/apache/gravitino/storage/relational/mapper/GroupMetaMapper.java
b/core/src/main/java/org/apache/gravitino/storage/relational/mapper/GroupMetaMapper.java
index ca29a0c5c..6250c2a9a 100644
---
a/core/src/main/java/org/apache/gravitino/storage/relational/mapper/GroupMetaMapper.java
+++
b/core/src/main/java/org/apache/gravitino/storage/relational/mapper/GroupMetaMapper.java
@@ -60,18 +60,6 @@ public interface GroupMetaMapper {
GroupPO selectGroupMetaByMetalakeIdAndName(
@Param("metalakeId") Long metalakeId, @Param("groupName") String name);
- @Select(
- "SELECT group_id as groupId, group_name as groupName,"
- + " metalake_id as metalakeId,"
- + " audit_info as auditInfo,"
- + " current_version as currentVersion, last_version as lastVersion,"
- + " deleted_at as deletedAt"
- + " FROM "
- + GROUP_TABLE_NAME
- + " WHERE group_id = #{groupId}"
- + " AND deleted_at = 0")
- GroupPO selectGroupMetaById(@Param("groupId") Long groupId);
-
@Insert(
"INSERT INTO "
+ GROUP_TABLE_NAME
diff --git
a/core/src/main/java/org/apache/gravitino/storage/relational/mapper/OwnerMetaMapper.java
b/core/src/main/java/org/apache/gravitino/storage/relational/mapper/OwnerMetaMapper.java
index a3dacf486..11c288324 100644
---
a/core/src/main/java/org/apache/gravitino/storage/relational/mapper/OwnerMetaMapper.java
+++
b/core/src/main/java/org/apache/gravitino/storage/relational/mapper/OwnerMetaMapper.java
@@ -18,7 +18,9 @@
*/
package org.apache.gravitino.storage.relational.mapper;
+import org.apache.gravitino.storage.relational.po.GroupPO;
import org.apache.gravitino.storage.relational.po.OwnerRelPO;
+import org.apache.gravitino.storage.relational.po.UserPO;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Param;
@@ -38,20 +40,44 @@ public interface OwnerMetaMapper {
String OWNER_TABLE_NAME = "owner_meta";
@Select(
- "SELECT metalake_id as metalakeId,"
- + " owner_id as ownerId,"
- + " owner_type as ownerType,"
- + " metadata_object_id as metadataObjectId,"
- + " metadata_object_type as metadataObjectType,"
- + " audit_info as auditInfo,"
- + " current_version as currentVersion, last_version as lastVersion,"
- + " deleted_at as deletedAt"
+ "SELECT ut.user_id as userId,"
+ + " ut.user_name as userName,"
+ + " ut.metalake_id as metalakeId,"
+ + " ut.audit_info as auditInfo,"
+ + " ut.current_version as currentVersion,"
+ + " ut.last_version as lastVersion,"
+ + " ut.deleted_at as deletedAt"
+ " FROM "
+ OWNER_TABLE_NAME
- + " WHERE metadata_object_id = #{metadataObjectId} AND"
- + " metadata_object_type = #{metadataObjectType}"
- + " AND deleted_at = 0")
- OwnerRelPO selectOwnerMetaByMetadataObjectIdAndType(
+ + " ot JOIN "
+ + UserMetaMapper.USER_TABLE_NAME
+ + " ut ON ut.user_id = ot.owner_id"
+ + " WHERE ot.metadata_object_id = #{metadataObjectId} AND"
+ + " ot.metadata_object_type = #{metadataObjectType} AND"
+ + " ot.owner_type = 'USER' AND"
+ + " ot.deleted_at = 0 AND ut.deleted_at = 0")
+ UserPO selectUserOwnerMetaByMetadataObjectIdAndType(
+ @Param("metadataObjectId") Long metadataObjectId,
+ @Param("metadataObjectType") String metadataObjectType);
+
+ @Select(
+ "SELECT gt.group_id as groupId,"
+ + " gt.group_name as groupName,"
+ + " gt.metalake_id as metalakeId,"
+ + " gt.audit_info as auditInfo,"
+ + " gt.current_version as currentVersion,"
+ + " gt.last_version as lastVersion,"
+ + " gt.deleted_at as deletedAt"
+ + " FROM "
+ + OWNER_TABLE_NAME
+ + " ot JOIN "
+ + GroupMetaMapper.GROUP_TABLE_NAME
+ + " gt ON gt.group_id = ot.owner_id"
+ + " WHERE ot.metadata_object_id = #{metadataObjectId} AND"
+ + " ot.metadata_object_type = #{metadataObjectType} AND"
+ + " ot.owner_type = 'GROUP' AND"
+ + " ot.deleted_at = 0 AND gt.deleted_at = 0")
+ GroupPO selectGroupOwnerMetaByMetadataObjectIdAndType(
@Param("metadataObjectId") Long metadataObjectId,
@Param("metadataObjectType") String metadataObjectType);
@@ -83,6 +109,15 @@ public interface OwnerMetaMapper {
@Param("metadataObjectId") Long metadataObjectId,
@Param("metadataObjectType") String metadataObjectType);
+ @Update(
+ "UPDATE "
+ + OWNER_TABLE_NAME
+ + " SET deleted_at = (UNIX_TIMESTAMP() * 1000.0)"
+ + " + EXTRACT(MICROSECOND FROM CURRENT_TIMESTAMP(3)) / 1000"
+ + " WHERE owner_id = #{ownerId} AND owner_type = #{ownerType} AND
deleted_at = 0")
+ void softDeleteOwnerRelByOwnerIdAndType(
+ @Param("ownerId") Long ownerId, @Param("ownerType") String ownerType);
+
@Update(
"UPDATE "
+ OWNER_TABLE_NAME
diff --git
a/core/src/main/java/org/apache/gravitino/storage/relational/mapper/UserMetaMapper.java
b/core/src/main/java/org/apache/gravitino/storage/relational/mapper/UserMetaMapper.java
index e7c24aee6..e7b442c09 100644
---
a/core/src/main/java/org/apache/gravitino/storage/relational/mapper/UserMetaMapper.java
+++
b/core/src/main/java/org/apache/gravitino/storage/relational/mapper/UserMetaMapper.java
@@ -60,18 +60,6 @@ public interface UserMetaMapper {
UserPO selectUserMetaByMetalakeIdAndName(
@Param("metalakeId") Long metalakeId, @Param("userName") String name);
- @Select(
- "SELECT user_id as userId, user_name as userName,"
- + " metalake_id as metalakeId,"
- + " audit_info as auditInfo,"
- + " current_version as currentVersion, last_version as lastVersion,"
- + " deleted_at as deletedAt"
- + " FROM "
- + USER_TABLE_NAME
- + " WHERE user_id = #{userId}"
- + " AND deleted_at = 0")
- UserPO selectUserMetaById(@Param("userId") Long userId);
-
@Insert(
"INSERT INTO "
+ USER_TABLE_NAME
diff --git
a/core/src/main/java/org/apache/gravitino/storage/relational/service/GroupMetaService.java
b/core/src/main/java/org/apache/gravitino/storage/relational/service/GroupMetaService.java
index a1dc6283d..81dbda4f8 100644
---
a/core/src/main/java/org/apache/gravitino/storage/relational/service/GroupMetaService.java
+++
b/core/src/main/java/org/apache/gravitino/storage/relational/service/GroupMetaService.java
@@ -22,7 +22,6 @@ import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import java.io.IOException;
-import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
@@ -36,6 +35,7 @@ import org.apache.gravitino.exceptions.NoSuchEntityException;
import org.apache.gravitino.meta.GroupEntity;
import org.apache.gravitino.storage.relational.mapper.GroupMetaMapper;
import org.apache.gravitino.storage.relational.mapper.GroupRoleRelMapper;
+import org.apache.gravitino.storage.relational.mapper.OwnerMetaMapper;
import org.apache.gravitino.storage.relational.po.GroupPO;
import org.apache.gravitino.storage.relational.po.GroupRoleRelPO;
import org.apache.gravitino.storage.relational.po.RolePO;
@@ -94,20 +94,6 @@ public class GroupMetaService {
return POConverters.fromGroupPO(groupPO, rolePOs, identifier.namespace());
}
- public GroupEntity getGroupById(String metalake, Long groupId) {
- GroupPO groupPO =
- SessionUtils.getWithoutCommit(
- GroupMetaMapper.class, mapper ->
mapper.selectGroupMetaById(groupId));
- if (groupPO == null) {
- throw new NoSuchEntityException(
- NoSuchEntityException.NO_SUCH_ENTITY_MESSAGE,
- Entity.EntityType.GROUP.name().toLowerCase(),
- String.valueOf(groupId));
- }
- return POConverters.fromGroupPO(
- groupPO, Collections.emptyList(),
AuthorizationUtils.ofGroupNamespace(metalake));
- }
-
public void insertGroup(GroupEntity groupEntity, boolean overwritten) throws
IOException {
try {
AuthorizationUtils.checkGroup(groupEntity.nameIdentifier());
@@ -165,7 +151,13 @@ public class GroupMetaService {
() ->
SessionUtils.doWithoutCommit(
GroupRoleRelMapper.class,
- mapper -> mapper.softDeleteGroupRoleRelByGroupId(groupId)));
+ mapper -> mapper.softDeleteGroupRoleRelByGroupId(groupId)),
+ () ->
+ SessionUtils.doWithoutCommit(
+ OwnerMetaMapper.class,
+ mapper ->
+ mapper.softDeleteOwnerRelByOwnerIdAndType(
+ groupId, Entity.EntityType.GROUP.name())));
return true;
}
diff --git
a/core/src/main/java/org/apache/gravitino/storage/relational/service/OwnerMetaService.java
b/core/src/main/java/org/apache/gravitino/storage/relational/service/OwnerMetaService.java
index 3354e7a95..c25c9997c 100644
---
a/core/src/main/java/org/apache/gravitino/storage/relational/service/OwnerMetaService.java
+++
b/core/src/main/java/org/apache/gravitino/storage/relational/service/OwnerMetaService.java
@@ -18,12 +18,16 @@
*/
package org.apache.gravitino.storage.relational.service;
+import java.util.Collections;
import java.util.Optional;
import org.apache.gravitino.Entity;
import org.apache.gravitino.MetadataObject;
import org.apache.gravitino.NameIdentifier;
+import org.apache.gravitino.authorization.AuthorizationUtils;
import org.apache.gravitino.storage.relational.mapper.OwnerMetaMapper;
+import org.apache.gravitino.storage.relational.po.GroupPO;
import org.apache.gravitino.storage.relational.po.OwnerRelPO;
+import org.apache.gravitino.storage.relational.po.UserPO;
import org.apache.gravitino.storage.relational.utils.POConverters;
import org.apache.gravitino.storage.relational.utils.SessionUtils;
import org.apache.gravitino.utils.NameIdentifierUtil;
@@ -44,28 +48,33 @@ public class OwnerMetaService {
MetalakeMetaService.getInstance().getMetalakeIdByName(getMetalake(identifier));
Long entityId = getEntityId(metalakeId, identifier, type);
- OwnerRelPO ownerRelPO =
+ UserPO userPO =
SessionUtils.getWithoutCommit(
OwnerMetaMapper.class,
- mapper ->
mapper.selectOwnerMetaByMetadataObjectIdAndType(entityId, type.name()));
+ mapper ->
mapper.selectUserOwnerMetaByMetadataObjectIdAndType(entityId, type.name()));
- if (ownerRelPO == null) {
- return Optional.empty();
+ if (userPO != null) {
+ return Optional.of(
+ POConverters.fromUserPO(
+ userPO,
+ Collections.emptyList(),
+ AuthorizationUtils.ofUserNamespace(getMetalake(identifier))));
}
- switch (Entity.EntityType.valueOf(ownerRelPO.getOwnerType())) {
- case USER:
- return Optional.of(
- UserMetaService.getInstance()
- .getUserById(getMetalake(identifier),
ownerRelPO.getOwnerId()));
- case GROUP:
- return Optional.of(
- GroupMetaService.getInstance()
- .getGroupById(getMetalake(identifier),
ownerRelPO.getOwnerId()));
- default:
- throw new IllegalArgumentException(
- String.format("Owner type doesn't support %s",
ownerRelPO.getOwnerType()));
+ GroupPO groupPO =
+ SessionUtils.getWithoutCommit(
+ OwnerMetaMapper.class,
+ mapper ->
mapper.selectGroupOwnerMetaByMetadataObjectIdAndType(entityId, type.name()));
+
+ if (groupPO != null) {
+ return Optional.of(
+ POConverters.fromGroupPO(
+ groupPO,
+ Collections.emptyList(),
+ AuthorizationUtils.ofGroupNamespace(getMetalake(identifier))));
}
+
+ return Optional.empty();
}
public void setOwner(
diff --git
a/core/src/main/java/org/apache/gravitino/storage/relational/service/UserMetaService.java
b/core/src/main/java/org/apache/gravitino/storage/relational/service/UserMetaService.java
index 935ed87b9..f39386175 100644
---
a/core/src/main/java/org/apache/gravitino/storage/relational/service/UserMetaService.java
+++
b/core/src/main/java/org/apache/gravitino/storage/relational/service/UserMetaService.java
@@ -22,7 +22,6 @@ import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import java.io.IOException;
-import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
@@ -34,6 +33,7 @@ import org.apache.gravitino.NameIdentifier;
import org.apache.gravitino.authorization.AuthorizationUtils;
import org.apache.gravitino.exceptions.NoSuchEntityException;
import org.apache.gravitino.meta.UserEntity;
+import org.apache.gravitino.storage.relational.mapper.OwnerMetaMapper;
import org.apache.gravitino.storage.relational.mapper.UserMetaMapper;
import org.apache.gravitino.storage.relational.mapper.UserRoleRelMapper;
import org.apache.gravitino.storage.relational.po.RolePO;
@@ -150,24 +150,16 @@ public class UserMetaService {
UserMetaMapper.class, mapper ->
mapper.softDeleteUserMetaByUserId(userId)),
() ->
SessionUtils.doWithoutCommit(
- UserRoleRelMapper.class, mapper ->
mapper.softDeleteUserRoleRelByUserId(userId)));
+ UserRoleRelMapper.class, mapper ->
mapper.softDeleteUserRoleRelByUserId(userId)),
+ () ->
+ SessionUtils.doWithoutCommit(
+ OwnerMetaMapper.class,
+ mapper ->
+ mapper.softDeleteOwnerRelByOwnerIdAndType(
+ userId, Entity.EntityType.USER.name())));
return true;
}
- public UserEntity getUserById(String metalake, Long userId) {
- UserPO userPO =
- SessionUtils.getWithoutCommit(
- UserMetaMapper.class, mapper -> mapper.selectUserMetaById(userId));
- if (userPO == null) {
- throw new NoSuchEntityException(
- NoSuchEntityException.NO_SUCH_ENTITY_MESSAGE,
- Entity.EntityType.USER.name().toLowerCase(),
- String.valueOf(userId));
- }
- return POConverters.fromUserPO(
- userPO, Collections.emptyList(),
AuthorizationUtils.ofUserNamespace(metalake));
- }
-
public <E extends Entity & HasIdentifier> UserEntity updateUser(
NameIdentifier identifier, Function<E, E> updater) throws IOException {
AuthorizationUtils.checkUser(identifier);
diff --git
a/core/src/test/java/org/apache/gravitino/authorization/TestOwnerManager.java
b/core/src/test/java/org/apache/gravitino/authorization/TestOwnerManager.java
index 57623ea89..bf8c57580 100644
---
a/core/src/test/java/org/apache/gravitino/authorization/TestOwnerManager.java
+++
b/core/src/test/java/org/apache/gravitino/authorization/TestOwnerManager.java
@@ -46,6 +46,8 @@ import org.apache.gravitino.EntityStoreFactory;
import org.apache.gravitino.GravitinoEnv;
import org.apache.gravitino.MetadataObject;
import org.apache.gravitino.MetadataObjects;
+import org.apache.gravitino.exceptions.NoSuchMetadataObjectException;
+import org.apache.gravitino.exceptions.NotFoundException;
import org.apache.gravitino.lock.LockManager;
import org.apache.gravitino.meta.AuditInfo;
import org.apache.gravitino.meta.BaseMetalake;
@@ -154,6 +156,12 @@ public class TestOwnerManager {
MetadataObjects.of(Lists.newArrayList(METALAKE),
MetadataObject.Type.METALAKE);
Assertions.assertFalse(ownerManager.getOwner(METALAKE,
metalakeObject).isPresent());
+ // Test not-existed metadata object
+ MetadataObject notExistObject =
+ MetadataObjects.of(Lists.newArrayList("not-exist"),
MetadataObject.Type.CATALOG);
+ Assertions.assertThrows(
+ NoSuchMetadataObjectException.class, () ->
ownerManager.getOwner(METALAKE, notExistObject));
+
// Test to set the user as the owner
ownerManager.setOwner(METALAKE, metalakeObject, USER, Owner.Type.USER);
@@ -164,6 +172,11 @@ public class TestOwnerManager {
// Test to set the group as the owner
ownerManager.setOwner(METALAKE, metalakeObject, GROUP, Owner.Type.GROUP);
+ // Test not-existed metadata object
+ Assertions.assertThrows(
+ NotFoundException.class,
+ () -> ownerManager.setOwner(METALAKE, notExistObject, GROUP,
Owner.Type.GROUP));
+
owner = ownerManager.getOwner(METALAKE, metalakeObject).get();
Assertions.assertEquals(GROUP, owner.name());
Assertions.assertEquals(Owner.Type.GROUP, owner.type());
diff --git
a/core/src/test/java/org/apache/gravitino/storage/relational/service/TestGroupMetaService.java
b/core/src/test/java/org/apache/gravitino/storage/relational/service/TestGroupMetaService.java
index 240f6298e..22246ba0c 100644
---
a/core/src/test/java/org/apache/gravitino/storage/relational/service/TestGroupMetaService.java
+++
b/core/src/test/java/org/apache/gravitino/storage/relational/service/TestGroupMetaService.java
@@ -28,7 +28,9 @@ import java.sql.SQLException;
import java.sql.Statement;
import java.time.Instant;
import java.util.List;
+import java.util.Optional;
import java.util.function.Function;
+import org.apache.gravitino.Entity;
import org.apache.gravitino.EntityAlreadyExistsException;
import org.apache.gravitino.Namespace;
import org.apache.gravitino.authorization.AuthorizationUtils;
@@ -283,6 +285,7 @@ class TestGroupMetaService extends TestJDBCBackend {
GroupMetaService groupMetaService = GroupMetaService.getInstance();
RoleMetaService roleMetaService = RoleMetaService.getInstance();
+ OwnerMetaService ownerMetaService = OwnerMetaService.getInstance();
// delete group
GroupEntity group1 =
@@ -296,11 +299,25 @@ class TestGroupMetaService extends TestJDBCBackend {
() -> groupMetaService.getGroupByIdentifier(group1.nameIdentifier()));
Assertions.assertDoesNotThrow(() -> groupMetaService.insertGroup(group1,
false));
Assertions.assertEquals(group1,
groupMetaService.getGroupByIdentifier(group1.nameIdentifier()));
+
+ // Set the owner of the metalake
+ ownerMetaService.setOwner(
+ metalake.nameIdentifier(), metalake.type(), group1.nameIdentifier(),
group1.type());
+ Optional<Entity> entity =
ownerMetaService.getOwner(metalake.nameIdentifier(), metalake.type());
+ Assertions.assertTrue(entity.isPresent());
+ Assertions.assertEquals(group1, entity.get());
+
+ // Delete the group
Assertions.assertTrue(groupMetaService.deleteGroup(group1.nameIdentifier()));
+
Assertions.assertThrows(
NoSuchEntityException.class,
() -> groupMetaService.getGroupByIdentifier(group1.nameIdentifier()));
+ // Test owner deletion
+ entity = ownerMetaService.getOwner(metalake.nameIdentifier(),
metalake.type());
+ Assertions.assertFalse(entity.isPresent());
+
// delete group with roles
RoleEntity role1 =
createRoleEntity(
diff --git
a/core/src/test/java/org/apache/gravitino/storage/relational/service/TestUserMetaService.java
b/core/src/test/java/org/apache/gravitino/storage/relational/service/TestUserMetaService.java
index 1834ed16f..326ccfc2d 100644
---
a/core/src/test/java/org/apache/gravitino/storage/relational/service/TestUserMetaService.java
+++
b/core/src/test/java/org/apache/gravitino/storage/relational/service/TestUserMetaService.java
@@ -28,7 +28,9 @@ import java.sql.SQLException;
import java.sql.Statement;
import java.time.Instant;
import java.util.List;
+import java.util.Optional;
import java.util.function.Function;
+import org.apache.gravitino.Entity;
import org.apache.gravitino.EntityAlreadyExistsException;
import org.apache.gravitino.Namespace;
import org.apache.gravitino.authorization.AuthorizationUtils;
@@ -282,6 +284,7 @@ class TestUserMetaService extends TestJDBCBackend {
UserMetaService userMetaService = UserMetaService.getInstance();
RoleMetaService roleMetaService = RoleMetaService.getInstance();
+ OwnerMetaService ownerMetaService = OwnerMetaService.getInstance();
// delete user
UserEntity user1 =
@@ -295,11 +298,23 @@ class TestUserMetaService extends TestJDBCBackend {
() -> userMetaService.getUserByIdentifier(user1.nameIdentifier()));
Assertions.assertDoesNotThrow(() -> userMetaService.insertUser(user1,
false));
Assertions.assertEquals(user1,
userMetaService.getUserByIdentifier(user1.nameIdentifier()));
+
+ // Set the owner of the metalake
+ ownerMetaService.setOwner(
+ metalake.nameIdentifier(), metalake.type(), user1.nameIdentifier(),
user1.type());
+ Optional<Entity> entity =
ownerMetaService.getOwner(metalake.nameIdentifier(), metalake.type());
+ Assertions.assertTrue(entity.isPresent());
+ Assertions.assertEquals(user1, entity.get());
+
Assertions.assertTrue(userMetaService.deleteUser(user1.nameIdentifier()));
Assertions.assertThrows(
NoSuchEntityException.class,
() -> userMetaService.getUserByIdentifier(user1.nameIdentifier()));
+ // Test owner deletion
+ entity = ownerMetaService.getOwner(metalake.nameIdentifier(),
metalake.type());
+ Assertions.assertFalse(entity.isPresent());
+
// delete user with roles
RoleEntity role1 =
createRoleEntity(