diff --git a/polaris-core/build.gradle.kts b/polaris-core/build.gradle.kts index b611509f84..4ae7df3e1a 100644 --- a/polaris-core/build.gradle.kts +++ b/polaris-core/build.gradle.kts @@ -78,6 +78,8 @@ dependencies { implementation("software.amazon.awssdk:iam-policy-builder") implementation("software.amazon.awssdk:s3") + implementation("org.everit.json:org.everit.json.schema:1.5.1") + implementation("org.apache.iceberg:iceberg-azure") implementation(platform(libs.azuresdk.bom)) implementation("com.azure:azure-storage-blob") diff --git a/polaris-core/src/main/java/org/apache/polaris/core/policy/BasePolicyValidator.java b/polaris-core/src/main/java/org/apache/polaris/core/policy/BasePolicyValidator.java new file mode 100644 index 0000000000..be9d276e4f --- /dev/null +++ b/polaris-core/src/main/java/org/apache/polaris/core/policy/BasePolicyValidator.java @@ -0,0 +1,52 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.polaris.core.policy; + +import java.io.InputStream; +import org.everit.json.schema.Schema; +import org.everit.json.schema.ValidationException; +import org.everit.json.schema.loader.SchemaLoader; +import org.json.JSONObject; +import org.json.JSONTokener; + +public class BasePolicyValidator implements PolicyValidator { + @Override + public boolean validate(Policy policy) { + try { + InputStream schemaStream = + getResourceAsStream("schemas/policies/system/data-compaction/2025-02-03.json"); + JSONObject rawSchema = new JSONObject(new JSONTokener(schemaStream)); + Schema schema = SchemaLoader.load(rawSchema); + + var jsonData = new JSONObject(new JSONTokener(policy.content)); + + schema.validate(jsonData); + return true; + } catch (ValidationException e) { + // The JSON failed validation; handle error information + System.out.println("JSON validation failed: " + e.getMessage()); + // You can also inspect e.getCausingExceptions() for detail on multiple errors + return false; + } + } + + private static InputStream getResourceAsStream(String fileName) { + return Thread.currentThread().getContextClassLoader().getResourceAsStream(fileName); + } +} diff --git a/polaris-core/src/main/java/org/apache/polaris/core/policy/Policy.java b/polaris-core/src/main/java/org/apache/polaris/core/policy/Policy.java new file mode 100644 index 0000000000..e981ad6dcc --- /dev/null +++ b/polaris-core/src/main/java/org/apache/polaris/core/policy/Policy.java @@ -0,0 +1,31 @@ +/* + * 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.polaris.core.policy; + +public class Policy { + String content; + + public Policy(String content) { + this.content = content; + } + + public String getContent() { + return content; + } +} diff --git a/polaris-core/src/main/java/org/apache/polaris/core/policy/PolicyValidator.java b/polaris-core/src/main/java/org/apache/polaris/core/policy/PolicyValidator.java new file mode 100644 index 0000000000..fb18eb61e8 --- /dev/null +++ b/polaris-core/src/main/java/org/apache/polaris/core/policy/PolicyValidator.java @@ -0,0 +1,23 @@ +/* + * 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.polaris.core.policy; + +public interface PolicyValidator { + boolean validate(Policy policy); +} diff --git a/polaris-core/src/main/resources/schemas/policies/system/data-compaction/2025-02-03.json b/polaris-core/src/main/resources/schemas/policies/system/data-compaction/2025-02-03.json new file mode 100644 index 0000000000..dbeab9db66 --- /dev/null +++ b/polaris-core/src/main/resources/schemas/policies/system/data-compaction/2025-02-03.json @@ -0,0 +1,40 @@ +{ + "$id": "https://polaris.apache.org/schemas/policies/system/data-compaction/2025-02-03.json", + "title": "Data Compaction Policy", + "description": "Inheritable Polaris policy schema for Iceberg table data compaction.", + "type": "object", + "properties": { + "version": { + "type": "string", + "const": "2025-02-03", + "description": "Schema version." + }, + "enable": { + "type": "boolean", + "description": "Enable or disable data compaction." + }, + "target_file_size_bytes": { + "type": "number", + "description": "Target data file size in bytes." + }, + "config": { + "type": "object", + "description": "A map containing custom configuration properties. Please note that interoperability is not guaranteed.", + "additionalProperties": {} + } + }, + "required": ["enable"], + "additionalProperties": false, + "examples": [ + { + "version": "2025-02-03", + "enable": true, + "target_file_size_bytes": 134217728, + "config": { + "compaction_strategy": "bin-pack", + "max-concurrent-file-group-rewrites": 5, + "my-key": "my-value" + } + } + ] +} diff --git a/polaris-core/src/test/java/org/apache/polaris/core/policy/BasePolicyValidatorTest.java b/polaris-core/src/test/java/org/apache/polaris/core/policy/BasePolicyValidatorTest.java new file mode 100644 index 0000000000..d5cb8b6f2d --- /dev/null +++ b/polaris-core/src/test/java/org/apache/polaris/core/policy/BasePolicyValidatorTest.java @@ -0,0 +1,65 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.polaris.core.policy; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +public class BasePolicyValidatorTest { + private BasePolicyValidator validator; + + @BeforeEach + public void setUp() { + validator = new BasePolicyValidator(); + } + + @Test + public void testValidateValidPolicy() { + var validJson = "{\"enable\": False}"; + var result = validator.validate(new Policy(validJson)); + assertThat(result).isTrue(); + + validJson = "{\"enable\": true, \"target_file_size_bytes\": 12342}"; + result = validator.validate(new Policy(validJson)); + assertThat(result).isTrue(); + + validJson = "{\"version\":\"2025-02-03\", \"enable\": true, \"target_file_size_bytes\": 12342}"; + result = validator.validate(new Policy(validJson)); + assertThat(result).isTrue(); + + validJson = "{\"enable\": true, \"config\": {\"key1\": \"value1\", \"key2\": true}}"; + result = validator.validate(new Policy(validJson)); + assertThat(result).isTrue(); + } + + @Test + public void testInValidateValidPolicy() { + // missing required key + var inValidJson = "{}"; + var result = validator.validate(new Policy(inValidJson)); + assertThat(result).isFalse(); + + // invalid keys + inValidJson = "{\"enable\": true, \"invalid_key\": 12342}"; + result = validator.validate(new Policy(inValidJson)); + assertThat(result).isFalse(); + } +}