diff --git a/fe/fe-core/src/main/java/org/apache/doris/datasource/property/ParamRules.java b/fe/fe-core/src/main/java/org/apache/doris/datasource/property/ParamRules.java index 4cf1564cd40768..bc364897f6b35b 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/datasource/property/ParamRules.java +++ b/fe/fe-core/src/main/java/org/apache/doris/datasource/property/ParamRules.java @@ -20,6 +20,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Objects; +import java.util.function.BooleanSupplier; public class ParamRules { @@ -218,6 +219,28 @@ public ParamRules requireAtLeastOne(String[] values, String errorMessage) { return this; } + /** + * Add a custom validation rule using a lambda expression. + *

+ * The validation rule will be executed when {@link #validate()} is called. + * If the condition evaluates to true, an {@link IllegalArgumentException} will be thrown + * with the provided error message. + * + * @param condition a BooleanSupplier that returns true if validation should fail + * @param errorMessage the error message to throw if condition evaluates to true + * @return this ParamRules instance for chaining + * + * @see #validate() + */ + public ParamRules check(BooleanSupplier condition, String errorMessage) { + rules.add(() -> { + if (condition.getAsBoolean()) { + throw new IllegalArgumentException(errorMessage); + } + }); + return this; + } + // --------- Utility Methods ---------- diff --git a/fe/fe-core/src/main/java/org/apache/doris/datasource/property/metastore/AWSGlueMetaStoreBaseProperties.java b/fe/fe-core/src/main/java/org/apache/doris/datasource/property/metastore/AWSGlueMetaStoreBaseProperties.java index 032e63ae4c4f37..445b8311f85f67 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/datasource/property/metastore/AWSGlueMetaStoreBaseProperties.java +++ b/fe/fe-core/src/main/java/org/apache/doris/datasource/property/metastore/AWSGlueMetaStoreBaseProperties.java @@ -116,7 +116,9 @@ private ParamRules buildRules() { "glue.access_key and glue.secret_key must be set together") .requireAtLeastOne(new String[]{glueAccessKey, glueIAMRole}, "At least one of glue.access_key or glue.role_arn must be set") - .require(glueEndpoint, "glue.endpoint must be set"); + .require(glueEndpoint, "glue.endpoint must be set") + .check(() -> StringUtils.isNotBlank(glueEndpoint) && !glueEndpoint.startsWith("https://"), + "glue.endpoint must use https protocol,please set glue.endpoint to https://..."); } private void checkAndInit() { diff --git a/fe/fe-core/src/test/java/org/apache/doris/datasource/property/ParamRulesTest.java b/fe/fe-core/src/test/java/org/apache/doris/datasource/property/ParamRulesTest.java index afa0614b453764..24fb075d15e06e 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/datasource/property/ParamRulesTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/datasource/property/ParamRulesTest.java @@ -147,4 +147,45 @@ void testAtLeastOne() { ); Assertions.assertDoesNotThrow(() -> rightRule3.validate()); } + + @Test + void testComplexLambdaValidation() { + String username = "alice"; + String password = ""; + String email = "alice@example.com"; + int age = 17; + int maxAge = 100; + + ParamRules rules = new ParamRules(); + + // Add multiple lambda rules + rules.check(() -> username == null || username.isEmpty(), "Username must not be empty") + .check(() -> password == null || password.length() < 6, "Password must be at least 6 characters") + .check(() -> !email.contains("@"), "Email must be valid") + .check(() -> age < 18 || age > maxAge, "Age must be between 18 and 100") + .check(() -> username.equals(email), "Username and email cannot be the same"); + // Validate with prefix message + IllegalArgumentException ex = Assertions.assertThrows(IllegalArgumentException.class, + () -> rules.validate("Validation Failed")); + // Check that the error message is prefixed + assert ex.getMessage().startsWith("Validation Failed: "); + } + + @Test + void testComplexLambdaValidationSuccess() { + String username = "alice"; + String password = "password123"; + String email = "alice@example.com"; + int age = 25; + int maxAge = 100; + ParamRules rules = new ParamRules(); + // Should pass without exception + Assertions.assertDoesNotThrow(() -> { + rules.check(() -> username == null || username.isEmpty(), "Username must not be empty") + .check(() -> password == null || password.length() < 6, "Password must be at least 6 characters") + .check(() -> !email.contains("@"), "Email must be valid") + .check(() -> age < 18 || age > maxAge, "Age must be between 18 and 100") + .check(() -> username.equals(email), "Username and email cannot be the same"); + }); + } } diff --git a/fe/fe-core/src/test/java/org/apache/doris/datasource/property/metastore/AWSGlueMetaStoreBasePropertiesTest.java b/fe/fe-core/src/test/java/org/apache/doris/datasource/property/metastore/AWSGlueMetaStoreBasePropertiesTest.java index f091ac31784865..f3d9e0490b99dd 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/datasource/property/metastore/AWSGlueMetaStoreBasePropertiesTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/datasource/property/metastore/AWSGlueMetaStoreBasePropertiesTest.java @@ -28,7 +28,7 @@ private Map baseValidProps() { Map props = new HashMap<>(); props.put("glue.access_key", "ak"); props.put("glue.secret_key", "sk"); - props.put("glue.endpoint", "glue.us-east-1.amazonaws.com"); + props.put("glue.endpoint", "https://glue.us-east-1.amazonaws.com"); return props; } @@ -103,15 +103,28 @@ void testMissingEndpointThrows() { void testInvalidEndpoint() { Map props = baseValidProps(); props.put("glue.endpoint", "http://invalid-endpoint.com"); - Assertions.assertDoesNotThrow(() -> AWSGlueMetaStoreBaseProperties.of(props)); + IllegalArgumentException ex = Assertions.assertThrows( + IllegalArgumentException.class, + () -> AWSGlueMetaStoreBaseProperties.of(props) + ); + Assertions.assertTrue(ex.getMessage().contains("glue.endpoint must use https protocol,please set glue.endpoint to https://...")); + props.put("glue.endpoint", "http://glue.us-east-1.amazonaws.com"); + ex = Assertions.assertThrows( + IllegalArgumentException.class, + () -> AWSGlueMetaStoreBaseProperties.of(props) + ); + Assertions.assertTrue(ex.getMessage().contains("glue.endpoint must use https protocol,please set glue.endpoint to https://...")); } @Test void testExtractRegionFailsWhenPatternMatchesButNoRegion() { Map props = baseValidProps(); props.put("glue.endpoint", "glue..amazonaws.com"); // malformed - Assertions.assertDoesNotThrow(() -> AWSGlueMetaStoreBaseProperties.of(props) + IllegalArgumentException ex = Assertions.assertThrows( + IllegalArgumentException.class, + () -> AWSGlueMetaStoreBaseProperties.of(props) ); + Assertions.assertTrue(ex.getMessage().contains("glue.endpoint must use https protocol,please set glue.endpoint to https://...")); } @Test