NIFI-5261: Added JSON_VALIDATOR to StandardValidators

This closes #2758

Signed-off-by: Mike Thomsen <mikerthomsen@gmail.com>
This commit is contained in:
zenfenan 2018-06-04 22:48:38 +05:30 committed by Mike Thomsen
parent cb216b79ec
commit 504152eaa1
8 changed files with 73 additions and 45 deletions

View File

@ -40,5 +40,10 @@
<artifactId>nifi-api</artifactId>
<version>1.7.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.1</version>
</dependency>
</dependencies>
</project>

View File

@ -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

View File

@ -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"));
}
}

View File

@ -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")

View File

@ -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();

View File

@ -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")

View File

@ -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();

View File

@ -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 {