From 504152eaa1cd377e4e9c94d2e5670855c8d2f7b0 Mon Sep 17 00:00:00 2001 From: zenfenan Date: Mon, 4 Jun 2018 22:48:38 +0530 Subject: [PATCH] NIFI-5261: Added JSON_VALIDATOR to StandardValidators This closes #2758 Signed-off-by: Mike Thomsen --- nifi-commons/nifi-utils/pom.xml | 5 +++ .../processor/util/StandardValidators.java | 22 +++++++++++ .../validator/TestStandardValidators.java | 38 +++++++++++++++++++ .../ElasticSearchRestProcessor.java | 2 +- .../CredentialPropertyDescriptors.java | 2 +- .../nifi/processors/mongodb/GetMongo.java | 24 ++---------- .../nifi/processors/mongodb/PutMongo.java | 2 +- .../mongodb/RunMongoAggregation.java | 23 +---------- 8 files changed, 73 insertions(+), 45 deletions(-) diff --git a/nifi-commons/nifi-utils/pom.xml b/nifi-commons/nifi-utils/pom.xml index 5a023b6eb1..26d64aeb79 100644 --- a/nifi-commons/nifi-utils/pom.xml +++ b/nifi-commons/nifi-utils/pom.xml @@ -40,5 +40,10 @@ nifi-api 1.7.0-SNAPSHOT + + com.google.code.gson + gson + 2.8.1 + diff --git a/nifi-commons/nifi-utils/src/main/java/org/apache/nifi/processor/util/StandardValidators.java b/nifi-commons/nifi-utils/src/main/java/org/apache/nifi/processor/util/StandardValidators.java index adf499a78a..b1e39fa655 100644 --- a/nifi-commons/nifi-utils/src/main/java/org/apache/nifi/processor/util/StandardValidators.java +++ b/nifi-commons/nifi-utils/src/main/java/org/apache/nifi/processor/util/StandardValidators.java @@ -30,6 +30,9 @@ import java.util.List; import java.util.concurrent.TimeUnit; import java.util.regex.Pattern; +import com.google.gson.Gson; +import com.google.gson.JsonElement; +import com.google.gson.JsonSyntaxException; import org.apache.nifi.components.PropertyValue; import org.apache.nifi.components.ValidationContext; import org.apache.nifi.components.ValidationResult; @@ -480,6 +483,25 @@ public class StandardValidators { public static final Validator FILE_EXISTS_VALIDATOR = new FileExistsValidator(true); + /** + * {@link Validator} that ensures the value is a valid JSON + */ + public static final Validator JSON_VALIDATOR = (subject, input, context) -> { + if (context.isExpressionLanguageSupported(subject) && context.isExpressionLanguagePresent(input)) { + return new ValidationResult.Builder().subject(subject).input(input).explanation("Expression Language Present").valid(true).build(); + } + + try { + new Gson().fromJson(input, JsonElement.class); + } catch (JsonSyntaxException e) { + return new ValidationResult.Builder().subject(subject).input(input).valid(false) + .explanation(subject + " is not a valid JSON representation due to " + e.getLocalizedMessage()) + .build(); + } + + return new ValidationResult.Builder().subject(subject).input(input).valid(true).build(); + }; + // // // FACTORY METHODS FOR VALIDATORS diff --git a/nifi-commons/nifi-utils/src/test/java/org/apache/nifi/util/validator/TestStandardValidators.java b/nifi-commons/nifi-utils/src/test/java/org/apache/nifi/util/validator/TestStandardValidators.java index 81888caa32..147ed13c25 100644 --- a/nifi-commons/nifi-utils/src/test/java/org/apache/nifi/util/validator/TestStandardValidators.java +++ b/nifi-commons/nifi-utils/src/test/java/org/apache/nifi/util/validator/TestStandardValidators.java @@ -288,4 +288,42 @@ public class TestStandardValidators { vr = val.validate("foo", "2016-01-01T01:01:01.000Z", vc); assertTrue(vr.isValid()); } + + @Test + public void testJSONObjectValidator() { + final Validator validator = StandardValidators.JSON_VALIDATOR; + final ValidationContext context = mock(ValidationContext.class); + final String DUMMY_JSON_PROPERTY = "JSONProperty"; + ValidationResult validationResult; + + // Flat JSON + validationResult = validator.validate(DUMMY_JSON_PROPERTY,"{\"Name\" : \"Crockford, Douglas\"}", context); + assertTrue(validationResult.isValid()); + + // Nested JSON + validationResult = validator.validate(DUMMY_JSON_PROPERTY, "{ \"Name\" : \"Crockford, Douglas\", \"ContactInfo\": { \"Mobile\" : 0987654321, \"Email\" : \"mrx@xyz.zyx\" } }", context); + assertTrue(validationResult.isValid()); + + // JSON object with JSON array + validationResult = validator.validate(DUMMY_JSON_PROPERTY, "{ \"name\":\"Smith, John\", \"age\":30, \"cars\":[ \"Ford\", \"BMW\", \"Fiat\" ] } ", context); + assertTrue(validationResult.isValid()); + + // JSON array + validationResult = validator.validate(DUMMY_JSON_PROPERTY, "[\"one\", \"two\", \"three\"]", context); + assertTrue(validationResult.isValid()); + + // JSON Primitives + validationResult = validator.validate(DUMMY_JSON_PROPERTY, "bncjbhjfjhj", context); + assertTrue(validationResult.isValid()); + + // Empty JSON + validationResult = validator.validate(DUMMY_JSON_PROPERTY, "{}", context); + assertTrue(validationResult.isValid()); + + // Invalid JSON + validationResult = validator.validate(DUMMY_JSON_PROPERTY, "\"Name\" : \"Smith, John\"", context); + assertFalse(validationResult.isValid()); + assertTrue(validationResult.getExplanation().contains("not a valid JSON representation")); + + } } diff --git a/nifi-nar-bundles/nifi-elasticsearch-bundle/nifi-elasticsearch-restapi-processors/src/main/java/org/apache/nifi/processors/elasticsearch/ElasticSearchRestProcessor.java b/nifi-nar-bundles/nifi-elasticsearch-bundle/nifi-elasticsearch-restapi-processors/src/main/java/org/apache/nifi/processors/elasticsearch/ElasticSearchRestProcessor.java index e94a1cc161..43df99126e 100644 --- a/nifi-nar-bundles/nifi-elasticsearch-bundle/nifi-elasticsearch-restapi-processors/src/main/java/org/apache/nifi/processors/elasticsearch/ElasticSearchRestProcessor.java +++ b/nifi-nar-bundles/nifi-elasticsearch-bundle/nifi-elasticsearch-restapi-processors/src/main/java/org/apache/nifi/processors/elasticsearch/ElasticSearchRestProcessor.java @@ -55,7 +55,7 @@ public interface ElasticSearchRestProcessor { "If this parameter is not set, the query will be read from the flowfile content.") .required(false) .expressionLanguageSupported(ExpressionLanguageScope.FLOWFILE_ATTRIBUTES) - .addValidator(StandardValidators.NON_EMPTY_VALIDATOR) + .addValidator(StandardValidators.JSON_VALIDATOR) .build(); PropertyDescriptor QUERY_ATTRIBUTE = new PropertyDescriptor.Builder() .name("el-query-attribute") diff --git a/nifi-nar-bundles/nifi-gcp-bundle/nifi-gcp-processors/src/main/java/org/apache/nifi/processors/gcp/credentials/factory/CredentialPropertyDescriptors.java b/nifi-nar-bundles/nifi-gcp-bundle/nifi-gcp-processors/src/main/java/org/apache/nifi/processors/gcp/credentials/factory/CredentialPropertyDescriptors.java index 0728eb0f11..2531ab072b 100644 --- a/nifi-nar-bundles/nifi-gcp-bundle/nifi-gcp-processors/src/main/java/org/apache/nifi/processors/gcp/credentials/factory/CredentialPropertyDescriptors.java +++ b/nifi-nar-bundles/nifi-gcp-bundle/nifi-gcp-processors/src/main/java/org/apache/nifi/processors/gcp/credentials/factory/CredentialPropertyDescriptors.java @@ -83,7 +83,7 @@ public final class CredentialPropertyDescriptors { .displayName("Service Account JSON") .expressionLanguageSupported(ExpressionLanguageScope.VARIABLE_REGISTRY) .required(false) - .addValidator(StandardValidators.NON_EMPTY_VALIDATOR) + .addValidator(StandardValidators.JSON_VALIDATOR) .description("The raw JSON containing a Service Account keyfile.") .sensitive(true) .build(); diff --git a/nifi-nar-bundles/nifi-mongodb-bundle/nifi-mongodb-processors/src/main/java/org/apache/nifi/processors/mongodb/GetMongo.java b/nifi-nar-bundles/nifi-mongodb-bundle/nifi-mongodb-processors/src/main/java/org/apache/nifi/processors/mongodb/GetMongo.java index 2840262b8d..3cf80ad9fa 100644 --- a/nifi-nar-bundles/nifi-mongodb-bundle/nifi-mongodb-processors/src/main/java/org/apache/nifi/processors/mongodb/GetMongo.java +++ b/nifi-nar-bundles/nifi-mongodb-bundle/nifi-mongodb-processors/src/main/java/org/apache/nifi/processors/mongodb/GetMongo.java @@ -29,7 +29,6 @@ import org.apache.nifi.annotation.documentation.CapabilityDescription; import org.apache.nifi.annotation.documentation.Tags; import org.apache.nifi.components.AllowableValue; import org.apache.nifi.components.PropertyDescriptor; -import org.apache.nifi.components.ValidationResult; import org.apache.nifi.components.Validator; import org.apache.nifi.expression.ExpressionLanguageScope; import org.apache.nifi.flowfile.FlowFile; @@ -60,23 +59,6 @@ import java.util.Set; @InputRequirement(Requirement.INPUT_ALLOWED) @CapabilityDescription("Creates FlowFiles from documents in MongoDB") public class GetMongo extends AbstractMongoProcessor { - public static final Validator DOCUMENT_VALIDATOR = (subject, value, context) -> { - final ValidationResult.Builder builder = new ValidationResult.Builder(); - builder.subject(subject).input(value); - - if (context.isExpressionLanguageSupported(subject) && context.isExpressionLanguagePresent(value)) { - return builder.valid(true).explanation("Contains Expression Language").build(); - } - - String reason = null; - try { - Document.parse(value); - } catch (final RuntimeException e) { - reason = e.getLocalizedMessage(); - } - - return builder.explanation(reason).valid(reason == null).build(); - }; static final Relationship REL_SUCCESS = new Relationship.Builder().name("success").description("All files are routed to success").build(); static final Relationship REL_FAILURE = new Relationship.Builder() @@ -97,7 +79,7 @@ public class GetMongo extends AbstractMongoProcessor { "that will result in a full collection fetch using a \"{}\" query.") .required(false) .expressionLanguageSupported(ExpressionLanguageScope.FLOWFILE_ATTRIBUTES) - .addValidator(DOCUMENT_VALIDATOR) + .addValidator(StandardValidators.JSON_VALIDATOR) .build(); static final PropertyDescriptor PROJECTION = new PropertyDescriptor.Builder() @@ -105,14 +87,14 @@ public class GetMongo extends AbstractMongoProcessor { .description("The fields to be returned from the documents in the result set; must be a valid BSON document") .required(false) .expressionLanguageSupported(ExpressionLanguageScope.FLOWFILE_ATTRIBUTES) - .addValidator(DOCUMENT_VALIDATOR) + .addValidator(StandardValidators.JSON_VALIDATOR) .build(); static final PropertyDescriptor SORT = new PropertyDescriptor.Builder() .name("Sort") .description("The fields by which to sort; must be a valid BSON document") .required(false) .expressionLanguageSupported(ExpressionLanguageScope.FLOWFILE_ATTRIBUTES) - .addValidator(DOCUMENT_VALIDATOR) + .addValidator(StandardValidators.JSON_VALIDATOR) .build(); static final PropertyDescriptor LIMIT = new PropertyDescriptor.Builder() .name("Limit") diff --git a/nifi-nar-bundles/nifi-mongodb-bundle/nifi-mongodb-processors/src/main/java/org/apache/nifi/processors/mongodb/PutMongo.java b/nifi-nar-bundles/nifi-mongodb-bundle/nifi-mongodb-processors/src/main/java/org/apache/nifi/processors/mongodb/PutMongo.java index f9a0b2b0de..839ad9e599 100644 --- a/nifi-nar-bundles/nifi-mongodb-bundle/nifi-mongodb-processors/src/main/java/org/apache/nifi/processors/mongodb/PutMongo.java +++ b/nifi-nar-bundles/nifi-mongodb-bundle/nifi-mongodb-processors/src/main/java/org/apache/nifi/processors/mongodb/PutMongo.java @@ -100,7 +100,7 @@ public class PutMongo extends AbstractMongoProcessor { .displayName("Update Query") .description("Specify a full MongoDB query to be used for the lookup query to do an update/upsert.") .required(false) - .addValidator(StandardValidators.NON_BLANK_VALIDATOR) + .addValidator(StandardValidators.JSON_VALIDATOR) .expressionLanguageSupported(ExpressionLanguageScope.FLOWFILE_ATTRIBUTES) .build(); diff --git a/nifi-nar-bundles/nifi-mongodb-bundle/nifi-mongodb-processors/src/main/java/org/apache/nifi/processors/mongodb/RunMongoAggregation.java b/nifi-nar-bundles/nifi-mongodb-bundle/nifi-mongodb-processors/src/main/java/org/apache/nifi/processors/mongodb/RunMongoAggregation.java index 01cf96a774..ff32039605 100644 --- a/nifi-nar-bundles/nifi-mongodb-bundle/nifi-mongodb-processors/src/main/java/org/apache/nifi/processors/mongodb/RunMongoAggregation.java +++ b/nifi-nar-bundles/nifi-mongodb-bundle/nifi-mongodb-processors/src/main/java/org/apache/nifi/processors/mongodb/RunMongoAggregation.java @@ -28,14 +28,13 @@ import org.apache.nifi.annotation.behavior.InputRequirement; import org.apache.nifi.annotation.documentation.CapabilityDescription; import org.apache.nifi.annotation.documentation.Tags; import org.apache.nifi.components.PropertyDescriptor; -import org.apache.nifi.components.ValidationResult; -import org.apache.nifi.components.Validator; import org.apache.nifi.expression.ExpressionLanguageScope; import org.apache.nifi.flowfile.FlowFile; import org.apache.nifi.processor.ProcessContext; import org.apache.nifi.processor.ProcessSession; import org.apache.nifi.processor.Relationship; import org.apache.nifi.processor.exception.ProcessException; +import org.apache.nifi.processor.util.StandardValidators; import org.bson.Document; import org.bson.conversions.Bson; import com.fasterxml.jackson.databind.ObjectMapper; @@ -83,31 +82,13 @@ public class RunMongoAggregation extends AbstractMongoProcessor { return result; } - public static final Validator AGG_VALIDATOR = (subject, value, context) -> { - final ValidationResult.Builder builder = new ValidationResult.Builder(); - builder.subject(subject).input(value); - - if (context.isExpressionLanguageSupported(subject) && context.isExpressionLanguagePresent(value)) { - return builder.valid(true).explanation("Contains Expression Language").build(); - } - - String reason = null; - try { - buildAggregationQuery(value); - } catch (final RuntimeException | IOException e) { - reason = e.getLocalizedMessage(); - } - - return builder.explanation(reason).valid(reason == null).build(); - }; - static final PropertyDescriptor QUERY = new PropertyDescriptor.Builder() .name("mongo-agg-query") .displayName("Query") .expressionLanguageSupported(ExpressionLanguageScope.FLOWFILE_ATTRIBUTES) .description("The aggregation query to be executed.") .required(true) - .addValidator(AGG_VALIDATOR) + .addValidator(StandardValidators.JSON_VALIDATOR) .build(); static {