This is an automated email from the ASF dual-hosted git repository.
jshao 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 5de0772668 [#7552] feat(policy): Add policy entity and POConverters
(part-2) (#7361)
5de0772668 is described below
commit 5de07726684b281059b65a4dc486f2cb113d7e0a
Author: mchades <[email protected]>
AuthorDate: Wed Jul 9 16:13:49 2025 +0800
[#7552] feat(policy): Add policy entity and POConverters (part-2) (#7361)
### What changes were proposed in this pull request?
Add policy entity and POConverters
### Why are the changes needed?
Fix: #7552
### Does this PR introduce _any_ user-facing change?
no
### How was this patch tested?
tests added
---
.../java/org/apache/gravitino/policy/Policy.java | 144 +++++++--
.../org/apache/gravitino/policy/PolicyChange.java | 8 +-
.../PolicyContent.java} | 22 +-
.../apache/gravitino/policy/PolicyContents.java | 101 +++++++
.../apache/gravitino/policy/PolicyOperations.java | 4 +-
.../src/main/java/org/apache/gravitino/Entity.java | 4 +
.../org/apache/gravitino/meta/PolicyEntity.java | 328 +++++++++++++++++++++
.../gravitino/storage/relational/JDBCBackend.java | 7 +
.../gravitino/storage/relational/po/PolicyPO.java | 195 ++++++++++++
.../storage/relational/po/PolicyVersionPO.java | 137 +++++++++
.../storage/relational/utils/POConverters.java | 34 +++
.../org/apache/gravitino/utils/NamespaceUtil.java | 10 +
.../apache/gravitino/meta/TestPolicyEntity.java | 125 ++++++++
.../storage/relational/utils/TestPOConverters.java | 122 ++++++++
14 files changed, 1203 insertions(+), 38 deletions(-)
diff --git a/api/src/main/java/org/apache/gravitino/policy/Policy.java
b/api/src/main/java/org/apache/gravitino/policy/Policy.java
index d8c9b6fd38..05faabdbb7 100644
--- a/api/src/main/java/org/apache/gravitino/policy/Policy.java
+++ b/api/src/main/java/org/apache/gravitino/policy/Policy.java
@@ -18,13 +18,14 @@
*/
package org.apache.gravitino.policy;
-import java.util.Map;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableSet;
import java.util.Optional;
import java.util.Set;
+import org.apache.commons.lang3.StringUtils;
import org.apache.gravitino.Auditable;
import org.apache.gravitino.MetadataObject;
import org.apache.gravitino.annotation.Evolving;
-import org.apache.gravitino.exceptions.IllegalPolicyException;
/**
* The interface of the policy. The policy is a set of rules that can be
associated with a metadata
@@ -33,6 +34,125 @@ import
org.apache.gravitino.exceptions.IllegalPolicyException;
@Evolving
public interface Policy extends Auditable {
+ /** The set of metadata object types that the policy can be applied to. */
+ Set<MetadataObject.Type> SUPPORTS_ALL_OBJECT_TYPES =
+ ImmutableSet.of(
+ MetadataObject.Type.CATALOG,
+ MetadataObject.Type.SCHEMA,
+ MetadataObject.Type.FILESET,
+ MetadataObject.Type.TABLE,
+ MetadataObject.Type.TOPIC,
+ MetadataObject.Type.MODEL);
+
+ /**
+ * The prefix for built-in policy types. All built-in policy types should
start with this prefix.
+ */
+ String BUILT_IN_TYPE_PREFIX = "system_";
+
+ /** The built-in policy types. Predefined policy types that are provided by
the system. */
+ enum BuiltInType {
+ // todo: add built-in policies, such as:
+ // DATA_COMPACTION(BUILT_IN_TYPE_PREFIX + "data_compaction", true, true,
+ // SUPPORTS_ALL_OBJECT_TYPES
+ // PolicyContent.DataCompactionContent.class)
+
+ /**
+ * Custom policy type. "custom" is a dummy type for custom policies, all
non-built-in types are
+ * custom types.
+ */
+ CUSTOM("custom", null, null, null, PolicyContents.CustomContent.class);
+
+ private final String policyType;
+ private final Boolean exclusive;
+ private final Boolean inheritable;
+ private final ImmutableSet<MetadataObject.Type> supportedObjectTypes;
+ private final Class<? extends PolicyContent> contentClass;
+
+ BuiltInType(
+ String policyType,
+ Boolean exclusive,
+ Boolean inheritable,
+ Set<MetadataObject.Type> supportedObjectTypes,
+ Class<? extends PolicyContent> contentClass) {
+ this.policyType = policyType;
+ this.exclusive = exclusive;
+ this.inheritable = inheritable;
+ this.supportedObjectTypes =
+ supportedObjectTypes == null
+ ? ImmutableSet.of()
+ : ImmutableSet.copyOf(supportedObjectTypes);
+ this.contentClass = contentClass;
+ }
+
+ /**
+ * Get the built-in policy type from the policy type string.
+ *
+ * @param policyType the policy type string
+ * @return the built-in policy type if it matches, otherwise returns
CUSTOM type
+ */
+ public static BuiltInType fromPolicyType(String policyType) {
+ Preconditions.checkArgument(StringUtils.isNotBlank(policyType),
"policyType cannot be blank");
+ for (BuiltInType type : BuiltInType.values()) {
+ if (type.policyType.equalsIgnoreCase(policyType)) {
+ return type;
+ }
+ }
+
+ if (policyType.startsWith(BUILT_IN_TYPE_PREFIX)) {
+ throw new IllegalArgumentException(
+ String.format("Unknown built-in policy type: %s", policyType));
+ }
+
+ // If the policy type is not a built-in type, it is a custom type.
+ return CUSTOM;
+ }
+
+ /**
+ * Get the policy type string.
+ *
+ * @return the policy type string
+ */
+ public String policyType() {
+ return policyType;
+ }
+
+ /**
+ * Check if the policy is exclusive.
+ *
+ * @return true if the policy is exclusive, false otherwise
+ */
+ public Boolean exclusive() {
+ return exclusive;
+ }
+
+ /**
+ * Check if the policy is inheritable.
+ *
+ * @return true if the policy is inheritable, false otherwise
+ */
+ public Boolean inheritable() {
+ return inheritable;
+ }
+
+ /**
+ * Get the set of metadata object types that the policy can be associated
with.
+ *
+ * @return the set of metadata object types that the policy can be
associated with
+ */
+ public Set<MetadataObject.Type> supportedObjectTypes() {
+ return supportedObjectTypes;
+ }
+
+ /**
+ * Get the content class of the policy.
+ *
+ * @return the content class of the policy
+ */
+ public Class<? extends PolicyContent> contentClass() {
+ return contentClass;
+ }
+ }
+
/**
* Get the name of the policy.
*
@@ -45,7 +165,7 @@ public interface Policy extends Auditable {
*
* @return The type of the policy.
*/
- String type();
+ String policyType();
/**
* Get the comment of the policy.
@@ -91,7 +211,7 @@ public interface Policy extends Auditable {
*
* @return The content of the policy.
*/
- Content content();
+ PolicyContent content();
/**
* Check if the policy is inherited from a parent object or not.
@@ -105,27 +225,11 @@ public interface Policy extends Auditable {
*/
Optional<Boolean> inherited();
- /**
- * Validate the policy. This method should be called when the policy is
created or updated. It
- * will check if the policy is valid or not. If the policy is not valid, it
will throw an
- * IllegalPolicyException.
- *
- * @throws IllegalPolicyException if the policy is not valid.
- */
- void validate() throws IllegalPolicyException;
-
/** @return The associated objects of the policy. */
default AssociatedObjects associatedObjects() {
throw new UnsupportedOperationException("The associatedObjects method is
not supported.");
}
- /** The interface of the content of the policy. */
- interface Content {
-
- /** @return The additional properties of the policy. */
- Map<String, String> properties();
- }
-
/** The interface of the associated objects of the policy. */
interface AssociatedObjects {
diff --git a/api/src/main/java/org/apache/gravitino/policy/PolicyChange.java
b/api/src/main/java/org/apache/gravitino/policy/PolicyChange.java
index db4199aa23..297572b076 100644
--- a/api/src/main/java/org/apache/gravitino/policy/PolicyChange.java
+++ b/api/src/main/java/org/apache/gravitino/policy/PolicyChange.java
@@ -54,7 +54,7 @@ public interface PolicyChange {
* @param content The new content for the policy.
* @return The policy change.
*/
- static PolicyChange updateContent(Policy.Content content) {
+ static PolicyChange updateContent(PolicyContent content) {
return new UpdateContent(content);
}
@@ -160,9 +160,9 @@ public interface PolicyChange {
/** A policy change to update the content of the policy. */
final class UpdateContent implements PolicyChange {
- private final Policy.Content content;
+ private final PolicyContent content;
- private UpdateContent(Policy.Content content) {
+ private UpdateContent(PolicyContent content) {
this.content = content;
}
@@ -171,7 +171,7 @@ public interface PolicyChange {
*
* @return The content of the policy change.
*/
- public Policy.Content getContent() {
+ public PolicyContent getContent() {
return content;
}
diff --git
a/api/src/main/java/org/apache/gravitino/exceptions/IllegalPolicyException.java
b/api/src/main/java/org/apache/gravitino/policy/PolicyContent.java
similarity index 59%
rename from
api/src/main/java/org/apache/gravitino/exceptions/IllegalPolicyException.java
rename to api/src/main/java/org/apache/gravitino/policy/PolicyContent.java
index 027ad4bee9..6f1302687b 100644
---
a/api/src/main/java/org/apache/gravitino/exceptions/IllegalPolicyException.java
+++ b/api/src/main/java/org/apache/gravitino/policy/PolicyContent.java
@@ -16,22 +16,20 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.gravitino.exceptions;
+package org.apache.gravitino.policy;
-import com.google.errorprone.annotations.FormatMethod;
-import com.google.errorprone.annotations.FormatString;
+import java.util.Map;
-/** An exception thrown when a policy is invalid. */
-public class IllegalPolicyException extends IllegalArgumentException {
+/** The interface of the content of the policy. */
+public interface PolicyContent {
+
+ /** @return The additional properties of the policy. */
+ Map<String, String> properties();
/**
- * Constructs a new exception with the specified detail message.
+ * Validates the policy content.
*
- * @param message the detail message.
- * @param args the arguments to the message.
+ * @throws IllegalArgumentException if the content is invalid.
*/
- @FormatMethod
- public IllegalPolicyException(@FormatString String message, Object... args) {
- super(String.format(message, args));
- }
+ void validate() throws IllegalArgumentException;
}
diff --git a/api/src/main/java/org/apache/gravitino/policy/PolicyContents.java
b/api/src/main/java/org/apache/gravitino/policy/PolicyContents.java
new file mode 100644
index 0000000000..f95a186db4
--- /dev/null
+++ b/api/src/main/java/org/apache/gravitino/policy/PolicyContents.java
@@ -0,0 +1,101 @@
+/*
+ * 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.policy;
+
+import java.util.Map;
+import java.util.Objects;
+
+/** Utility class for creating instances of {@link PolicyContent}. */
+public class PolicyContents {
+
+ /**
+ * Creates a custom policy content with the given rules and properties.
+ *
+ * @param rules The custom rules of the policy.
+ * @param properties The additional properties of the policy.
+ * @return A new instance of {@link PolicyContent} with the specified rules
and properties.
+ */
+ public static PolicyContent custom(Map<String, Object> rules, Map<String,
String> properties) {
+ return new CustomContent(rules, properties);
+ }
+
+ private PolicyContents() {}
+
+ /**
+ * A custom content implementation of {@link PolicyContent} that holds
custom rules and
+ * properties.
+ */
+ public static class CustomContent implements PolicyContent {
+ private final Map<String, Object> customRules;
+ private final Map<String, String> properties;
+
+ /** Default constructor for Jackson deserialization only. */
+ private CustomContent() {
+ this(null, null);
+ }
+
+ /**
+ * Constructor for CustomContent.
+ *
+ * @param customRules the custom rules of the policy
+ * @param properties the additional properties of the policy
+ */
+ private CustomContent(Map<String, Object> customRules, Map<String, String>
properties) {
+ this.customRules = customRules;
+ this.properties = properties;
+ }
+
+ /**
+ * Returns the custom rules of the policy.
+ *
+ * @return a map of custom rules
+ */
+ public Map<String, Object> customRules() {
+ return customRules;
+ }
+
+ @Override
+ public Map<String, String> properties() {
+ return properties;
+ }
+
+ @Override
+ public void validate() throws IllegalArgumentException {
+ // nothing to validate for custom content
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof CustomContent)) return false;
+ CustomContent that = (CustomContent) o;
+ return Objects.equals(customRules, that.customRules)
+ && Objects.equals(properties, that.properties);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(customRules, properties);
+ }
+
+ @Override
+ public String toString() {
+ return "CustomContent{" + "customRules=" + customRules + ", properties="
+ properties + '}';
+ }
+ }
+}
diff --git
a/api/src/main/java/org/apache/gravitino/policy/PolicyOperations.java
b/api/src/main/java/org/apache/gravitino/policy/PolicyOperations.java
index 22cc51dab3..440c4860e4 100644
--- a/api/src/main/java/org/apache/gravitino/policy/PolicyOperations.java
+++ b/api/src/main/java/org/apache/gravitino/policy/PolicyOperations.java
@@ -71,7 +71,7 @@ public interface PolicyOperations {
* @throws PolicyAlreadyExistsException If the policy already exists.
*/
Policy createPolicy(
- String name, String type, String comment, boolean enabled,
Policy.Content content)
+ String name, String type, String comment, boolean enabled, PolicyContent
content)
throws PolicyAlreadyExistsException;
/**
@@ -103,7 +103,7 @@ public interface PolicyOperations {
boolean exclusive,
boolean inheritable,
Set<MetadataObject.Type> supportedObjectTypes,
- Policy.Content content)
+ PolicyContent content)
throws PolicyAlreadyExistsException;
/**
diff --git a/core/src/main/java/org/apache/gravitino/Entity.java
b/core/src/main/java/org/apache/gravitino/Entity.java
index 102be50365..ab1ca3bc10 100644
--- a/core/src/main/java/org/apache/gravitino/Entity.java
+++ b/core/src/main/java/org/apache/gravitino/Entity.java
@@ -55,6 +55,9 @@ public interface Entity extends Serializable {
/** The tag schema name in the system catalog. */
String TAG_SCHEMA_NAME = "tag";
+ /** The policy schema name in the system catalog. */
+ String POLICY_SCHEMA_NAME = "policy";
+
/** Enumeration defining the types of entities in the Gravitino framework. */
@Getter
enum EntityType {
@@ -71,6 +74,7 @@ public interface Entity extends Serializable {
TAG("ta", 10),
MODEL("mo", 11),
MODEL_VERSION("mv", 12),
+ POLICY("po", 13),
AUDIT("au", 65534);
diff --git a/core/src/main/java/org/apache/gravitino/meta/PolicyEntity.java
b/core/src/main/java/org/apache/gravitino/meta/PolicyEntity.java
new file mode 100644
index 0000000000..dbfedc5627
--- /dev/null
+++ b/core/src/main/java/org/apache/gravitino/meta/PolicyEntity.java
@@ -0,0 +1,328 @@
+/*
+ * 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.meta;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Maps;
+import java.util.Collections;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
+import lombok.ToString;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.gravitino.Audit;
+import org.apache.gravitino.Auditable;
+import org.apache.gravitino.Entity;
+import org.apache.gravitino.Field;
+import org.apache.gravitino.HasIdentifier;
+import org.apache.gravitino.MetadataObject;
+import org.apache.gravitino.Namespace;
+import org.apache.gravitino.policy.Policy;
+import org.apache.gravitino.policy.PolicyContent;
+import org.apache.gravitino.policy.PolicyContents;
+
+@ToString
+public class PolicyEntity implements Policy, Entity, Auditable, HasIdentifier {
+
+ public static final Field ID =
+ Field.required("id", Long.class, "The unique id of the policy entity.");
+ public static final Field NAME =
+ Field.required("name", String.class, "The name of the policy entity.");
+ public static final Field POLICY_TYPE =
+ Field.required("policyType", String.class, "The type of the policy
entity.");
+ public static final Field COMMENT =
+ Field.optional("comment", String.class, "The comment of the policy
entity.");
+ public static final Field ENABLED =
+ Field.required("enabled", Boolean.class, "The policy entity is
enabled.");
+ public static final Field EXCLUSIVE =
+ Field.required("exclusive", Boolean.class, "The policy entity is
exclusive.");
+ public static final Field INHERITABLE =
+ Field.required("inheritable", Boolean.class, "The policy entity is
inheritable.");
+ public static final Field SUPPORTED_OBJECT_TYPES =
+ Field.required(
+ "supportedObjectTypes", Set.class, "The supported object types of
the policy entity.");
+ public static final Field CONTENT =
+ Field.required("content", PolicyContent.class, "The content of the
policy entity.");
+ public static final Field AUDIT_INFO =
+ Field.required("audit_info", AuditInfo.class, "The audit details of the
policy entity.");
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ private Long id;
+ private String name;
+ private Namespace namespace;
+ private String policyType;
+ private String comment;
+ private boolean enabled;
+ private boolean exclusive;
+ private boolean inheritable;
+ private Set<MetadataObject.Type> supportedObjectTypes;
+ private PolicyContent content;
+ private AuditInfo auditInfo;
+
+ private PolicyEntity() {}
+
+ @Override
+ public Map<Field, Object> fields() {
+ Map<Field, Object> fields = Maps.newHashMap();
+ fields.put(ID, id);
+ fields.put(NAME, name);
+ fields.put(POLICY_TYPE, policyType);
+ fields.put(COMMENT, comment);
+ fields.put(ENABLED, enabled);
+ fields.put(EXCLUSIVE, exclusive);
+ fields.put(INHERITABLE, inheritable);
+ fields.put(SUPPORTED_OBJECT_TYPES, supportedObjectTypes);
+ fields.put(CONTENT, content);
+ fields.put(AUDIT_INFO, auditInfo);
+
+ return Collections.unmodifiableMap(fields);
+ }
+
+ @Override
+ public Long id() {
+ return id;
+ }
+
+ @Override
+ public String name() {
+ return name;
+ }
+
+ @Override
+ public Namespace namespace() {
+ return namespace;
+ }
+
+ @Override
+ public EntityType type() {
+ return EntityType.POLICY;
+ }
+
+ @Override
+ public Audit auditInfo() {
+ return auditInfo;
+ }
+
+ @Override
+ public String policyType() {
+ return policyType;
+ }
+
+ @Override
+ public String comment() {
+ return comment;
+ }
+
+ @Override
+ public boolean enabled() {
+ return enabled;
+ }
+
+ @Override
+ public boolean exclusive() {
+ return exclusive;
+ }
+
+ @Override
+ public boolean inheritable() {
+ return inheritable;
+ }
+
+ @Override
+ public Set<MetadataObject.Type> supportedObjectTypes() {
+ return supportedObjectTypes;
+ }
+
+ @Override
+ public PolicyContent content() {
+ return content;
+ }
+
+ @Override
+ public Optional<Boolean> inherited() {
+ return Optional.empty();
+ }
+
+ @Override
+ public void validate() throws IllegalArgumentException {
+ Entity.super.validate();
+ validatePolicy();
+ content().validate();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof PolicyEntity)) return false;
+ PolicyEntity that = (PolicyEntity) o;
+ return enabled == that.enabled
+ && exclusive == that.exclusive
+ && inheritable == that.inheritable
+ && Objects.equals(id, that.id)
+ && Objects.equals(name, that.name)
+ && Objects.equals(namespace, that.namespace)
+ && Objects.equals(policyType, that.policyType)
+ && Objects.equals(comment, that.comment)
+ && Objects.equals(supportedObjectTypes, that.supportedObjectTypes)
+ && Objects.equals(content, that.content)
+ && Objects.equals(auditInfo, that.auditInfo);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(
+ id,
+ name,
+ namespace,
+ policyType,
+ comment,
+ enabled,
+ exclusive,
+ inheritable,
+ supportedObjectTypes,
+ content,
+ auditInfo);
+ }
+
+ private void validatePolicy() {
+ Preconditions.checkArgument(StringUtils.isNotBlank(name()), "Policy name
cannot be blank");
+ Preconditions.checkArgument(
+ StringUtils.isNotBlank(policyType()), "Policy type cannot be blank");
+ Preconditions.checkArgument(content() != null, "Policy content cannot be
null");
+ Preconditions.checkArgument(
+ supportedObjectTypes() != null && !supportedObjectTypes().isEmpty(),
+ "Policy must support at least one metadata object type");
+
+ BuiltInType builtInType = BuiltInType.fromPolicyType(policyType());
+ Preconditions.checkArgument(
+ builtInType != BuiltInType.CUSTOM || content() instanceof
PolicyContents.CustomContent,
+ "Expected CustomContent for custom policy type, but got %s",
+ content().getClass().getName());
+ if (builtInType != BuiltInType.CUSTOM) {
+ Preconditions.checkArgument(
+ exclusive() == builtInType.exclusive(),
+ "Expected exclusive value %s for built-in policy type %s, but got
%s",
+ builtInType.exclusive(),
+ policyType(),
+ exclusive());
+ Preconditions.checkArgument(
+ inheritable() == builtInType.inheritable(),
+ "Expected inheritable value %s for built-in policy type %s, but got
%s",
+ builtInType.inheritable(),
+ policyType(),
+ inheritable());
+ Preconditions.checkArgument(
+ supportedObjectTypes().equals(builtInType.supportedObjectTypes()),
+ "Expected supported object types %s for built-in policy type %s, but
got %s",
+ builtInType.supportedObjectTypes(),
+ policyType(),
+ supportedObjectTypes());
+ }
+ }
+
+ public static class Builder {
+ private Long id;
+ private String name;
+ private Namespace namespace;
+ private String policyType;
+ private String comment;
+ private boolean enabled = true;
+ private boolean exclusive;
+ private boolean inheritable;
+ private Set<MetadataObject.Type> supportedObjectTypes;
+ private PolicyContent content;
+ private AuditInfo auditInfo;
+
+ public Builder withId(Long id) {
+ this.id = id;
+ return this;
+ }
+
+ public Builder withName(String name) {
+ this.name = name;
+ return this;
+ }
+
+ public Builder withNamespace(Namespace namespace) {
+ this.namespace = namespace;
+ return this;
+ }
+
+ public Builder withPolicyType(String policyType) {
+ this.policyType = policyType;
+ return this;
+ }
+
+ public Builder withComment(String comment) {
+ this.comment = comment;
+ return this;
+ }
+
+ public Builder withEnabled(boolean enabled) {
+ this.enabled = enabled;
+ return this;
+ }
+
+ public Builder withExclusive(boolean exclusive) {
+ this.exclusive = exclusive;
+ return this;
+ }
+
+ public Builder withInheritable(boolean inheritable) {
+ this.inheritable = inheritable;
+ return this;
+ }
+
+ public Builder withSupportedObjectTypes(Set<MetadataObject.Type>
supportedObjectTypes) {
+ this.supportedObjectTypes = supportedObjectTypes;
+ return this;
+ }
+
+ public Builder withContent(PolicyContent content) {
+ this.content = content;
+ return this;
+ }
+
+ public Builder withAuditInfo(AuditInfo auditInfo) {
+ this.auditInfo = auditInfo;
+ return this;
+ }
+
+ public PolicyEntity build() {
+ PolicyEntity policyEntity = new PolicyEntity();
+ policyEntity.id = id;
+ policyEntity.name = name;
+ policyEntity.namespace = namespace;
+ policyEntity.policyType = policyType;
+ policyEntity.comment = comment;
+ policyEntity.enabled = enabled;
+ policyEntity.exclusive = exclusive;
+ policyEntity.inheritable = inheritable;
+ policyEntity.supportedObjectTypes = supportedObjectTypes;
+ policyEntity.content = content;
+ policyEntity.auditInfo = auditInfo;
+ policyEntity.validate();
+
+ return policyEntity;
+ }
+ }
+}
diff --git
a/core/src/main/java/org/apache/gravitino/storage/relational/JDBCBackend.java
b/core/src/main/java/org/apache/gravitino/storage/relational/JDBCBackend.java
index 07965901dd..966265c79f 100644
---
a/core/src/main/java/org/apache/gravitino/storage/relational/JDBCBackend.java
+++
b/core/src/main/java/org/apache/gravitino/storage/relational/JDBCBackend.java
@@ -326,6 +326,9 @@ public class JDBCBackend implements RelationalBackend {
return TagMetaService.getInstance()
.deleteTagMetasByLegacyTimeline(
legacyTimeline, GARBAGE_COLLECTOR_SINGLE_DELETION_LIMIT);
+ case POLICY:
+ // todo: Implement hard delete logic for policies.
+ return 0;
case COLUMN:
return TableColumnMetaService.getInstance()
.deleteColumnsByLegacyTimeline(legacyTimeline,
GARBAGE_COLLECTOR_SINGLE_DELETION_LIMIT);
@@ -372,6 +375,10 @@ public class JDBCBackend implements RelationalBackend {
.deleteFilesetVersionsByRetentionCount(
versionRetentionCount,
GARBAGE_COLLECTOR_SINGLE_DELETION_LIMIT);
+ case POLICY:
+ // todo: Implement delete old version logic for policies.
+ return 0;
+
default:
throw new IllegalArgumentException(
"Unsupported entity type when collectAndRemoveOldVersionData: " +
entityType);
diff --git
a/core/src/main/java/org/apache/gravitino/storage/relational/po/PolicyPO.java
b/core/src/main/java/org/apache/gravitino/storage/relational/po/PolicyPO.java
new file mode 100644
index 0000000000..1241ed1636
--- /dev/null
+++
b/core/src/main/java/org/apache/gravitino/storage/relational/po/PolicyPO.java
@@ -0,0 +1,195 @@
+/*
+ * 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.storage.relational.po;
+
+import com.google.common.base.Objects;
+import com.google.common.base.Preconditions;
+import lombok.Getter;
+
+@Getter
+public class PolicyPO {
+ private Long policyId;
+ private String policyName;
+ private String policyType;
+ private Long metalakeId;
+ private boolean inheritable;
+ private boolean exclusive;
+ private String supportedObjectTypes;
+ private String auditInfo;
+ private Long currentVersion;
+ private Long lastVersion;
+ private Long deletedAt;
+ private PolicyVersionPO policyVersionPO;
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof PolicyPO)) {
+ return false;
+ }
+ PolicyPO policyPO = (PolicyPO) o;
+ return Objects.equal(policyId, policyPO.policyId)
+ && Objects.equal(policyName, policyPO.policyName)
+ && Objects.equal(policyType, policyPO.policyType)
+ && Objects.equal(metalakeId, policyPO.metalakeId)
+ && Objects.equal(inheritable, policyPO.inheritable)
+ && Objects.equal(exclusive, policyPO.exclusive)
+ && Objects.equal(supportedObjectTypes, policyPO.supportedObjectTypes)
+ && Objects.equal(auditInfo, policyPO.auditInfo)
+ && Objects.equal(currentVersion, policyPO.currentVersion)
+ && Objects.equal(lastVersion, policyPO.lastVersion)
+ && Objects.equal(policyVersionPO, policyPO.policyVersionPO)
+ && Objects.equal(deletedAt, policyPO.deletedAt);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(
+ policyId,
+ policyName,
+ policyType,
+ metalakeId,
+ inheritable,
+ exclusive,
+ supportedObjectTypes,
+ auditInfo,
+ currentVersion,
+ lastVersion,
+ policyVersionPO,
+ deletedAt);
+ }
+
+ public static class Builder {
+ private Long policyId;
+ private String policyName;
+ private String policyType;
+ private Long metalakeId;
+ private boolean inheritable;
+ private boolean exclusive;
+ private String supportedObjectTypes;
+ private String auditInfo;
+ private Long currentVersion;
+ private Long lastVersion;
+ private Long deletedAt;
+ private PolicyVersionPO policyVersionPO;
+
+ public Builder withPolicyId(Long policyId) {
+ this.policyId = policyId;
+ return this;
+ }
+
+ public Builder withPolicyName(String policyName) {
+ this.policyName = policyName;
+ return this;
+ }
+
+ public Builder withMetalakeId(Long metalakeId) {
+ this.metalakeId = metalakeId;
+ return this;
+ }
+
+ public Builder withPolicyType(String policyType) {
+ this.policyType = policyType;
+ return this;
+ }
+
+ public Builder withInheritable(boolean inheritable) {
+ this.inheritable = inheritable;
+ return this;
+ }
+
+ public Builder withExclusive(boolean exclusive) {
+ this.exclusive = exclusive;
+ return this;
+ }
+
+ public Builder withSupportedObjectTypes(String supportedObjectTypes) {
+ this.supportedObjectTypes = supportedObjectTypes;
+ return this;
+ }
+
+ public Builder withAuditInfo(String auditInfo) {
+ this.auditInfo = auditInfo;
+ return this;
+ }
+
+ public Builder withCurrentVersion(Long currentVersion) {
+ this.currentVersion = currentVersion;
+ return this;
+ }
+
+ public Builder withLastVersion(Long lastVersion) {
+ this.lastVersion = lastVersion;
+ return this;
+ }
+
+ public Builder withDeletedAt(Long deletedAt) {
+ this.deletedAt = deletedAt;
+ return this;
+ }
+
+ public Builder withPolicyVersionPO(PolicyVersionPO policyVersionPO) {
+ this.policyVersionPO = policyVersionPO;
+ return this;
+ }
+
+ public Long getMetalakeId() {
+ Preconditions.checkArgument(metalakeId != null, "Metalake id is
required");
+ return metalakeId;
+ }
+
+ public PolicyPO build() {
+ validate();
+ PolicyPO policyPO = new PolicyPO();
+ policyPO.policyId = policyId;
+ policyPO.policyName = policyName;
+ policyPO.metalakeId = metalakeId;
+ policyPO.policyType = policyType;
+ policyPO.inheritable = inheritable;
+ policyPO.exclusive = exclusive;
+ policyPO.supportedObjectTypes = supportedObjectTypes;
+ policyPO.auditInfo = auditInfo;
+ policyPO.currentVersion = currentVersion;
+ policyPO.lastVersion = lastVersion;
+ policyPO.deletedAt = deletedAt;
+ policyPO.policyVersionPO = policyVersionPO;
+ return policyPO;
+ }
+
+ private void validate() {
+ Preconditions.checkArgument(policyId != null, "Policy id is required");
+ Preconditions.checkArgument(policyName != null, "Policy name is
required");
+ Preconditions.checkArgument(metalakeId != null, "Metalake id is
required");
+ Preconditions.checkArgument(policyType != null, "Policy type is
required");
+ Preconditions.checkArgument(
+ supportedObjectTypes != null, "Supported object types is required");
+ Preconditions.checkArgument(currentVersion != null, "Current version is
required");
+ Preconditions.checkArgument(lastVersion != null, "Last version is
required");
+ Preconditions.checkArgument(deletedAt != null, "Deleted at is required");
+ Preconditions.checkArgument(auditInfo != null, "Audit info is required");
+ Preconditions.checkArgument(policyVersionPO != null, "Policy version is
required");
+ }
+ }
+}
diff --git
a/core/src/main/java/org/apache/gravitino/storage/relational/po/PolicyVersionPO.java
b/core/src/main/java/org/apache/gravitino/storage/relational/po/PolicyVersionPO.java
new file mode 100644
index 0000000000..620d8f75af
--- /dev/null
+++
b/core/src/main/java/org/apache/gravitino/storage/relational/po/PolicyVersionPO.java
@@ -0,0 +1,137 @@
+/*
+ * 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.storage.relational.po;
+
+import com.google.common.base.Objects;
+import com.google.common.base.Preconditions;
+import lombok.Getter;
+
+@Getter
+public class PolicyVersionPO {
+ private Long id;
+ private Long metalakeId;
+ private Long policyId;
+ private Long version;
+ private String policyComment;
+ private boolean enabled;
+ private String content;
+ private Long deletedAt;
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof PolicyVersionPO)) {
+ return false;
+ }
+ PolicyVersionPO that = (PolicyVersionPO) o;
+ return Objects.equal(id, that.id)
+ && Objects.equal(metalakeId, that.metalakeId)
+ && Objects.equal(policyId, that.policyId)
+ && Objects.equal(version, that.version)
+ && Objects.equal(policyComment, that.policyComment)
+ && Objects.equal(enabled, that.enabled)
+ && Objects.equal(content, that.content)
+ && Objects.equal(deletedAt, that.deletedAt);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(
+ id, metalakeId, policyId, version, policyComment, enabled, content,
deletedAt);
+ }
+
+ public static class Builder {
+ private Long id;
+ private Long metalakeId;
+ private Long policyId;
+ private Long version;
+ private String policyComment;
+ private boolean enabled;
+ private String content;
+ private Long deletedAt;
+
+ public Builder withId(Long id) {
+ this.id = id;
+ return this;
+ }
+
+ public Builder withMetalakeId(Long metalakeId) {
+ this.metalakeId = metalakeId;
+ return this;
+ }
+
+ public Builder withPolicyId(Long policyId) {
+ this.policyId = policyId;
+ return this;
+ }
+
+ public Builder withVersion(Long version) {
+ this.version = version;
+ return this;
+ }
+
+ public Builder withPolicyComment(String policyComment) {
+ this.policyComment = policyComment;
+ return this;
+ }
+
+ public Builder withEnabled(boolean enabled) {
+ this.enabled = enabled;
+ return this;
+ }
+
+ public Builder withContent(String content) {
+ this.content = content;
+ return this;
+ }
+
+ public Builder withDeletedAt(Long deletedAt) {
+ this.deletedAt = deletedAt;
+ return this;
+ }
+
+ public PolicyVersionPO build() {
+ validate();
+ PolicyVersionPO policyVersionPO = new PolicyVersionPO();
+ policyVersionPO.id = this.id;
+ policyVersionPO.metalakeId = this.metalakeId;
+ policyVersionPO.policyId = this.policyId;
+ policyVersionPO.version = this.version;
+ policyVersionPO.policyComment = this.policyComment;
+ policyVersionPO.enabled = this.enabled;
+ policyVersionPO.content = this.content;
+ policyVersionPO.deletedAt = this.deletedAt;
+ return policyVersionPO;
+ }
+
+ private void validate() {
+ Preconditions.checkArgument(metalakeId != null, "metalakeId is
required");
+ Preconditions.checkArgument(policyId != null, "policyId is required");
+ Preconditions.checkArgument(version != null, "version is required");
+ Preconditions.checkArgument(content != null, "content is required");
+ Preconditions.checkArgument(deletedAt != null, "deletedAt is required");
+ }
+ }
+}
diff --git
a/core/src/main/java/org/apache/gravitino/storage/relational/utils/POConverters.java
b/core/src/main/java/org/apache/gravitino/storage/relational/utils/POConverters.java
index fc447a06d0..2b299886ee 100644
---
a/core/src/main/java/org/apache/gravitino/storage/relational/utils/POConverters.java
+++
b/core/src/main/java/org/apache/gravitino/storage/relational/utils/POConverters.java
@@ -20,12 +20,14 @@
package org.apache.gravitino.storage.relational.utils;
import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.core.type.TypeReference;
import com.google.common.collect.Lists;
import java.time.Instant;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
+import java.util.Set;
import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils;
import org.apache.gravitino.Catalog;
@@ -48,6 +50,7 @@ import org.apache.gravitino.meta.FilesetEntity;
import org.apache.gravitino.meta.GroupEntity;
import org.apache.gravitino.meta.ModelEntity;
import org.apache.gravitino.meta.ModelVersionEntity;
+import org.apache.gravitino.meta.PolicyEntity;
import org.apache.gravitino.meta.RoleEntity;
import org.apache.gravitino.meta.SchemaEntity;
import org.apache.gravitino.meta.SchemaVersion;
@@ -55,6 +58,7 @@ import org.apache.gravitino.meta.TableEntity;
import org.apache.gravitino.meta.TagEntity;
import org.apache.gravitino.meta.TopicEntity;
import org.apache.gravitino.meta.UserEntity;
+import org.apache.gravitino.policy.Policy;
import org.apache.gravitino.rel.Column;
import org.apache.gravitino.rel.expressions.Expression;
import org.apache.gravitino.rel.types.Type;
@@ -71,6 +75,7 @@ import org.apache.gravitino.storage.relational.po.ModelPO;
import org.apache.gravitino.storage.relational.po.ModelVersionAliasRelPO;
import org.apache.gravitino.storage.relational.po.ModelVersionPO;
import org.apache.gravitino.storage.relational.po.OwnerRelPO;
+import org.apache.gravitino.storage.relational.po.PolicyPO;
import org.apache.gravitino.storage.relational.po.RolePO;
import org.apache.gravitino.storage.relational.po.SchemaPO;
import org.apache.gravitino.storage.relational.po.SecurableObjectPO;
@@ -1305,6 +1310,35 @@ public class POConverters {
}
}
+ public static PolicyEntity fromPolicyPO(PolicyPO policyPO, Namespace
namespace) {
+ try {
+ return PolicyEntity.builder()
+ .withId(policyPO.getPolicyId())
+ .withName(policyPO.getPolicyName())
+ .withNamespace(namespace)
+ .withPolicyType(policyPO.getPolicyType())
+ .withComment(policyPO.getPolicyVersionPO().getPolicyComment())
+ .withEnabled(policyPO.getPolicyVersionPO().isEnabled())
+ .withExclusive(policyPO.isExclusive())
+ .withInheritable(policyPO.isInheritable())
+ .withSupportedObjectTypes(
+ JsonUtils.anyFieldMapper()
+ .readValue(
+ policyPO.getSupportedObjectTypes(),
+ new TypeReference<Set<MetadataObject.Type>>() {}))
+ .withContent(
+ JsonUtils.anyFieldMapper()
+ .readValue(
+ policyPO.getPolicyVersionPO().getContent(),
+
Policy.BuiltInType.fromPolicyType(policyPO.getPolicyType()).contentClass()))
+ .withAuditInfo(
+ JsonUtils.anyFieldMapper().readValue(policyPO.getAuditInfo(),
AuditInfo.class))
+ .build();
+ } catch (JsonProcessingException e) {
+ throw new RuntimeException("Failed to deserialize json object:", e);
+ }
+ }
+
public static OwnerRelPO initializeOwnerRelPOsWithVersion(
Long metalakeId,
String ownerType,
diff --git a/core/src/main/java/org/apache/gravitino/utils/NamespaceUtil.java
b/core/src/main/java/org/apache/gravitino/utils/NamespaceUtil.java
index f904592789..63743c635b 100644
--- a/core/src/main/java/org/apache/gravitino/utils/NamespaceUtil.java
+++ b/core/src/main/java/org/apache/gravitino/utils/NamespaceUtil.java
@@ -82,6 +82,16 @@ public class NamespaceUtil {
return Namespace.of(metalake, Entity.SYSTEM_CATALOG_RESERVED_NAME,
Entity.TAG_SCHEMA_NAME);
}
+ /**
+ * Create a namespace for policy.
+ *
+ * @param metalake The metalake name
+ * @return A namespace for policy
+ */
+ public static Namespace ofPolicy(String metalake) {
+ return Namespace.of(metalake, Entity.SYSTEM_CATALOG_RESERVED_NAME,
Entity.POLICY_SCHEMA_NAME);
+ }
+
/**
* Create a namespace for user.
*
diff --git a/core/src/test/java/org/apache/gravitino/meta/TestPolicyEntity.java
b/core/src/test/java/org/apache/gravitino/meta/TestPolicyEntity.java
new file mode 100644
index 0000000000..dfbd33a85e
--- /dev/null
+++ b/core/src/test/java/org/apache/gravitino/meta/TestPolicyEntity.java
@@ -0,0 +1,125 @@
+/*
+ * 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.meta;
+
+import static org.apache.gravitino.policy.Policy.SUPPORTS_ALL_OBJECT_TYPES;
+
+import com.google.common.collect.ImmutableMap;
+import java.time.Instant;
+import java.util.Map;
+import org.apache.gravitino.Namespace;
+import org.apache.gravitino.policy.PolicyContent;
+import org.apache.gravitino.policy.PolicyContents;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+public class TestPolicyEntity {
+
+ @Test
+ public void testPolicyEntityFields() {
+ AuditInfo auditInfo =
+
AuditInfo.builder().withCreator("test").withCreateTime(Instant.now()).build();
+ Map<String, String> properties = ImmutableMap.of("k1", "v1");
+
+ ImmutableMap<String, Object> contentFields =
ImmutableMap.of("target_file_size_bytes", 1000);
+ Namespace namespace = Namespace.of("m1", "c1", "s1");
+ PolicyContent content = PolicyContents.custom(contentFields, properties);
+ PolicyEntity policyEntity =
+ PolicyEntity.builder()
+ .withId(1L)
+ .withName("test")
+ .withNamespace(namespace)
+ .withComment("test comment")
+ .withPolicyType("my_compaction")
+ .withEnabled(false)
+ .withExclusive(true)
+ .withInheritable(true)
+ .withSupportedObjectTypes(SUPPORTS_ALL_OBJECT_TYPES)
+ .withContent(content)
+ .withAuditInfo(auditInfo)
+ .build();
+
+ Assertions.assertEquals(1L, policyEntity.id());
+ Assertions.assertEquals("test", policyEntity.name());
+ Assertions.assertEquals(namespace, policyEntity.namespace());
+ Assertions.assertEquals("test comment", policyEntity.comment());
+ Assertions.assertEquals("my_compaction", policyEntity.policyType());
+ Assertions.assertFalse(policyEntity.enabled());
+ Assertions.assertTrue(policyEntity.exclusive());
+ Assertions.assertTrue(policyEntity.inheritable());
+ Assertions.assertEquals(SUPPORTS_ALL_OBJECT_TYPES,
policyEntity.supportedObjectTypes());
+ Assertions.assertEquals(content, policyEntity.content());
+ Assertions.assertEquals(auditInfo, policyEntity.auditInfo());
+
+ PolicyEntity policyEntity2 =
+ PolicyEntity.builder()
+ .withId(1L)
+ .withName("test")
+ .withNamespace(namespace)
+ .withPolicyType("my_compaction")
+ .withEnabled(false)
+ .withExclusive(true)
+ .withInheritable(true)
+ .withSupportedObjectTypes(SUPPORTS_ALL_OBJECT_TYPES)
+ .withContent(content)
+ .withAuditInfo(auditInfo)
+ .build();
+ Assertions.assertNull(policyEntity2.comment());
+ }
+
+ @Test
+ public void testWithoutRequiredFields() {
+ Assertions.assertThrows(IllegalArgumentException.class, () ->
PolicyEntity.builder().build());
+
+ Assertions.assertThrows(
+ IllegalArgumentException.class,
+ () ->
+ PolicyEntity.builder()
+ .withId(1L)
+ .withNamespace(Namespace.of("m1", "c1", "s1"))
+ .withAuditInfo(
+
AuditInfo.builder().withCreator("test").withCreateTime(Instant.now()).build())
+ .build());
+
+ Assertions.assertThrows(
+ IllegalArgumentException.class,
+ () ->
+ PolicyEntity.builder()
+ .withId(1L)
+ .withName("test")
+ .withNamespace(Namespace.of("m1", "c1", "s1"))
+ .withPolicyType("my_compaction")
+ .withAuditInfo(
+
AuditInfo.builder().withCreator("test").withCreateTime(Instant.now()).build())
+ .build());
+
+ Assertions.assertThrows(
+ IllegalArgumentException.class,
+ () ->
+ PolicyEntity.builder()
+ .withId(1L)
+ .withName("test")
+ .withNamespace(Namespace.of("m1", "c1", "s1"))
+ .withPolicyType("my_compaction")
+ .withSupportedObjectTypes(SUPPORTS_ALL_OBJECT_TYPES)
+ .withAuditInfo(
+
AuditInfo.builder().withCreator("test").withCreateTime(Instant.now()).build())
+ .build());
+ }
+}
diff --git
a/core/src/test/java/org/apache/gravitino/storage/relational/utils/TestPOConverters.java
b/core/src/test/java/org/apache/gravitino/storage/relational/utils/TestPOConverters.java
index 858b1a8dd7..2397ca99e5 100644
---
a/core/src/test/java/org/apache/gravitino/storage/relational/utils/TestPOConverters.java
+++
b/core/src/test/java/org/apache/gravitino/storage/relational/utils/TestPOConverters.java
@@ -20,6 +20,7 @@
package org.apache.gravitino.storage.relational.utils;
import static org.apache.gravitino.file.Fileset.LOCATION_NAME_UNKNOWN;
+import static org.apache.gravitino.policy.Policy.SUPPORTS_ALL_OBJECT_TYPES;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
@@ -36,6 +37,7 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import java.util.stream.Collectors;
import org.apache.gravitino.Catalog;
import org.apache.gravitino.Entity;
@@ -52,11 +54,14 @@ import org.apache.gravitino.meta.ColumnEntity;
import org.apache.gravitino.meta.FilesetEntity;
import org.apache.gravitino.meta.ModelEntity;
import org.apache.gravitino.meta.ModelVersionEntity;
+import org.apache.gravitino.meta.PolicyEntity;
import org.apache.gravitino.meta.SchemaEntity;
import org.apache.gravitino.meta.SchemaVersion;
import org.apache.gravitino.meta.TableEntity;
import org.apache.gravitino.meta.TagEntity;
import org.apache.gravitino.meta.TopicEntity;
+import org.apache.gravitino.policy.PolicyContent;
+import org.apache.gravitino.policy.PolicyContents;
import org.apache.gravitino.rel.expressions.Expression;
import org.apache.gravitino.rel.expressions.literals.Literals;
import org.apache.gravitino.rel.types.Type;
@@ -70,6 +75,8 @@ import org.apache.gravitino.storage.relational.po.ModelPO;
import org.apache.gravitino.storage.relational.po.ModelVersionAliasRelPO;
import org.apache.gravitino.storage.relational.po.ModelVersionPO;
import org.apache.gravitino.storage.relational.po.OwnerRelPO;
+import org.apache.gravitino.storage.relational.po.PolicyPO;
+import org.apache.gravitino.storage.relational.po.PolicyVersionPO;
import org.apache.gravitino.storage.relational.po.SchemaPO;
import org.apache.gravitino.storage.relational.po.TablePO;
import org.apache.gravitino.storage.relational.po.TagMetadataObjectRelPO;
@@ -768,6 +775,44 @@ public class TestPOConverters {
assertEquals("test1", updatePO2.getFilesetName());
}
+ @Test
+ public void testFromPolicyPO() throws JsonProcessingException {
+ PolicyContent content = PolicyContents.custom(null, null);
+ PolicyVersionPO policyVersionPO =
+ createPolicyVersionPO(1L, 1L, 1L, "test comment", true, content);
+ PolicyPO policyPO =
+ createPolicyPO(
+ 1L, "test", "my_type", 1L, true, true, SUPPORTS_ALL_OBJECT_TYPES,
policyVersionPO);
+
+ PolicyEntity expectedPolicy =
+ createPolicy(
+ 1L,
+ "test",
+ NamespaceUtil.ofPolicy("test_metalake"),
+ "my_type",
+ "test comment",
+ true,
+ true,
+ true,
+ SUPPORTS_ALL_OBJECT_TYPES,
+ content);
+
+ PolicyEntity convertedPolicy =
+ POConverters.fromPolicyPO(policyPO,
NamespaceUtil.ofPolicy("test_metalake"));
+
+ assertEquals(expectedPolicy.id(), convertedPolicy.id());
+ assertEquals(expectedPolicy.name(), convertedPolicy.name());
+ assertEquals(expectedPolicy.namespace(), convertedPolicy.namespace());
+ assertEquals(expectedPolicy.auditInfo().creator(),
convertedPolicy.auditInfo().creator());
+ assertEquals(expectedPolicy.policyType(), convertedPolicy.policyType());
+ assertEquals(expectedPolicy.comment(), convertedPolicy.comment());
+ assertEquals(expectedPolicy.enabled(), convertedPolicy.enabled());
+ assertEquals(expectedPolicy.inheritable(), convertedPolicy.inheritable());
+ assertEquals(expectedPolicy.exclusive(), convertedPolicy.exclusive());
+ assertEquals(expectedPolicy.supportedObjectTypes(),
convertedPolicy.supportedObjectTypes());
+ assertEquals(expectedPolicy.content(), convertedPolicy.content());
+ }
+
@Test
public void testFromTagPO() throws JsonProcessingException {
TagPO tagPO = createTagPO(1L, "test", 1L, "this is test");
@@ -1487,6 +1532,83 @@ public class TestPOConverters {
.build();
}
+ private static PolicyEntity createPolicy(
+ Long id,
+ String name,
+ Namespace namespace,
+ String type,
+ String comment,
+ boolean enabled,
+ boolean exclusive,
+ boolean inheritable,
+ Set<MetadataObject.Type> supportedObjectTypes,
+ PolicyContent content) {
+ AuditInfo auditInfo =
+
AuditInfo.builder().withCreator("creator").withCreateTime(FIX_INSTANT).build();
+ return PolicyEntity.builder()
+ .withId(id)
+ .withName(name)
+ .withNamespace(namespace)
+ .withPolicyType(type)
+ .withComment(comment)
+ .withEnabled(enabled)
+ .withExclusive(exclusive)
+ .withInheritable(inheritable)
+ .withSupportedObjectTypes(supportedObjectTypes)
+ .withContent(content)
+ .withAuditInfo(auditInfo)
+ .build();
+ }
+
+ private static PolicyPO createPolicyPO(
+ Long id,
+ String name,
+ String policyType,
+ Long metalakeId,
+ boolean inheritable,
+ boolean exclusive,
+ Set<MetadataObject.Type> supportedObjectTypes,
+ PolicyVersionPO policyVersionPO)
+ throws JsonProcessingException {
+ AuditInfo auditInfo =
+
AuditInfo.builder().withCreator("creator").withCreateTime(FIX_INSTANT).build();
+ return PolicyPO.builder()
+ .withPolicyId(id)
+ .withPolicyName(name)
+ .withPolicyType(policyType)
+ .withMetalakeId(metalakeId)
+ .withInheritable(inheritable)
+ .withExclusive(exclusive)
+ .withSupportedObjectTypes(
+
JsonUtils.anyFieldMapper().writeValueAsString(supportedObjectTypes))
+
.withAuditInfo(JsonUtils.anyFieldMapper().writeValueAsString(auditInfo))
+ .withCurrentVersion(1L)
+ .withLastVersion(1L)
+ .withDeletedAt(0L)
+ .withPolicyVersionPO(policyVersionPO)
+ .build();
+ }
+
+ private static PolicyVersionPO createPolicyVersionPO(
+ Long id,
+ Long metalakeId,
+ Long policyId,
+ String comment,
+ boolean enabled,
+ PolicyContent content)
+ throws JsonProcessingException {
+ return PolicyVersionPO.builder()
+ .withId(id)
+ .withMetalakeId(metalakeId)
+ .withPolicyId(policyId)
+ .withVersion(1L)
+ .withPolicyComment(comment)
+ .withEnabled(enabled)
+ .withContent(JsonUtils.anyFieldMapper().writeValueAsString(content))
+ .withDeletedAt(0L)
+ .build();
+ }
+
private static TagPO createTagPO(Long id, String name, Long metalakeId,
String comment)
throws JsonProcessingException {
AuditInfo auditInfo =