first version of new validation algorithm, that is a lot faster

This commit is contained in:
2016-08-07 16:57:55 +02:00
parent 4c4d25f3b5
commit bc59f08bbb
19 changed files with 454 additions and 169 deletions

View File

@@ -0,0 +1,20 @@
package ninja.javafx.smartcsv.validation;
import static org.apache.commons.validator.GenericValidator.matchRegexp;
/**
* Created by abi on 07.08.2016.
*/
public class AlphaNumericValidation implements Validation {
@Override
public void check(int row, String value, ValidationError error) {
if (!matchRegexp(value, "[0-9a-zA-Z]*")) {
error.add("validation.message.alphanumeric");
}
}
@Override
public Type getType() {
return Type.ALPHANUMERIC;
}
}

View File

@@ -0,0 +1,47 @@
package ninja.javafx.smartcsv.validation;
import java.util.HashMap;
import java.util.Map;
/**
* Created by abi on 07.08.2016.
*/
public class ColumnValidations {
private Map<String, Map<Validation.Type, Validation>> columnValidationMap = new HashMap<>();
public void add(String column, Validation validation) {
Map<Validation.Type, Validation> validationMap = columnValidationMap.get(column);
if (validationMap == null) {
validationMap = new HashMap<>();
columnValidationMap.put(column, validationMap);
}
validationMap.put(validation.getType(), validation);
}
public void remove(String column, Validation.Type type) {
Map<Validation.Type, Validation> validationMap = columnValidationMap.get(column);
if (validationMap != null) {
validationMap.remove(type);
}
}
public ValidationError isValid(int row, String column, String value) {
ValidationError error = ValidationError.withLineNumber(row);
Map<Validation.Type, Validation> validationMap = columnValidationMap.get(column);
if (validationMap != null) {
for (Validation validation: validationMap.values()) {
if (validation.getType() == Validation.Type.NOT_EMPTY) {
validation.check(row, value, error);
} else {
if (value != null && !value.isEmpty()) {
validation.check(row, value, error);
}
}
}
}
return error;
}
}

View File

@@ -0,0 +1,16 @@
package ninja.javafx.smartcsv.validation;
/**
* Created by abi on 07.08.2016.
*/
public class ColumnValidationsBuilder {
private ColumnValidationsBuilder() {}
public static ColumnValidationsBuilder columnValidationsBuilder() {
return new ColumnValidationsBuilder();
}
//private
}

View File

@@ -0,0 +1,28 @@
package ninja.javafx.smartcsv.validation;
import static org.apache.commons.validator.GenericValidator.isDate;
/**
* Created by abi on 07.08.2016.
*/
public class DateValidation implements Validation {
private String dateformat;
public DateValidation(String dateformat) {
assert dateformat != null && !dateformat.trim().isEmpty() : "empty date format for date validation";
this.dateformat = dateformat;
}
@Override
public void check(int row, String value, ValidationError error) {
if (!isDate(value, dateformat, true)) {
error.add("validation.message.date.format", dateformat);
}
}
@Override
public Type getType() {
return Type.DATE;
}
}

View File

@@ -0,0 +1,21 @@
package ninja.javafx.smartcsv.validation;
import static org.apache.commons.validator.GenericValidator.isDouble;
/**
* Created by abi on 07.08.2016.
*/
public class DoubleValidation implements Validation {
@Override
public void check(int row, String value, ValidationError error) {
if (!isDouble(value)) {
error.add("validation.message.double");
}
}
@Override
public Type getType() {
return Type.DOUBLE;
}
}

View File

@@ -0,0 +1,53 @@
package ninja.javafx.smartcsv.validation;
import groovy.lang.Binding;
import groovy.lang.GroovyShell;
import groovy.lang.Script;
import org.codehaus.groovy.control.CompilationFailedException;
/**
* Created by abi on 07.08.2016.
*/
public class GroovyValidation implements Validation {
private String groovyScript;
private GroovyShell shell = new GroovyShell();
private Script script;
public GroovyValidation(String groovyScript) {
this.groovyScript = groovyScript;
script = shell.parse(groovyScript);
}
@Override
public void check(int row, String value, ValidationError error) {
Binding binding = new Binding();
binding.setVariable("value", value);
script.setBinding(binding);
Object groovyResult = null;
try {
groovyResult = script.run();
} catch (CompilationFailedException e) {
error.add("validation.message.groovy.exception", groovyScript, e.getMessage());
e.printStackTrace();
}
if (groovyResult == null) {
error.add("validation.message.groovy.return.null", groovyScript);
}
if (!isScriptResultTrue(groovyResult)) {
error.add(groovyResult.toString());
}
}
@Override
public Type getType() {
return Type.GROOVY;
}
private boolean isScriptResultTrue(Object groovyResult) {
return groovyResult.equals(true) || groovyResult.toString().trim().toLowerCase().equals("true");
}
}

View File

@@ -0,0 +1,21 @@
package ninja.javafx.smartcsv.validation;
import static org.apache.commons.validator.GenericValidator.isInt;
/**
* Created by abi on 07.08.2016.
*/
public class IntegerValidation implements Validation {
@Override
public void check(int row, String value, ValidationError error) {
if (!isInt(value)) {
error.add("validation.message.integer");
}
}
@Override
public Type getType() {
return Type.INTEGER;
}
}

View File

@@ -0,0 +1,27 @@
package ninja.javafx.smartcsv.validation;
import static org.apache.commons.validator.GenericValidator.maxLength;
/**
* Created by abi on 07.08.2016.
*/
public class MaxLengthValidation implements Validation {
private int maxLength;
public MaxLengthValidation(int maxLength) {
this.maxLength = maxLength;
}
@Override
public void check(int row, String value, ValidationError error) {
if (!maxLength(value, maxLength)) {
error.add("validation.message.max.length", Integer.toString(maxLength));
}
}
@Override
public Type getType() {
return Type.MAX_LENGTH;
}
}

View File

@@ -0,0 +1,27 @@
package ninja.javafx.smartcsv.validation;
import static org.apache.commons.validator.GenericValidator.minLength;
/**
* Created by abi on 07.08.2016.
*/
public class MinLengthValidation implements Validation {
private int minLength;
public MinLengthValidation(int minLength) {
this.minLength = minLength;
}
@Override
public void check(int row, String value, ValidationError error) {
if (!minLength(value, minLength)) {
error.add("validation.message.min.length", Integer.toString(minLength));
}
}
@Override
public Type getType() {
return Type.MIN_LENGTH;
}
}

View File

@@ -0,0 +1,21 @@
package ninja.javafx.smartcsv.validation;
import static org.apache.commons.validator.GenericValidator.isBlankOrNull;
/**
* Created by abi on 07.08.2016.
*/
public class NotEmptyValidation implements Validation {
@Override
public void check(int row, String value, ValidationError error) {
if (isBlankOrNull(value)) {
error.add("validation.message.not.empty");
}
}
@Override
public Type getType() {
return Type.NOT_EMPTY;
}
}

View File

@@ -0,0 +1,27 @@
package ninja.javafx.smartcsv.validation;
import static org.apache.commons.validator.GenericValidator.matchRegexp;
/**
* Created by abi on 07.08.2016.
*/
public class RegExpValidation implements Validation {
private String regexp;
public RegExpValidation(String regexp) {
this.regexp = regexp;
}
@Override
public void check(int row, String value, ValidationError error) {
if (!matchRegexp(value, regexp)) {
error.add("validation.message.regexp", regexp);
}
}
@Override
public Type getType() {
return Type.REGEXP;
}
}

View File

@@ -0,0 +1,29 @@
package ninja.javafx.smartcsv.validation;
import java.util.HashMap;
/**
* Created by abi on 07.08.2016.
*/
public class UniqueValidation implements Validation {
private HashMap<String, Integer> columnValueMap = new HashMap<>();
@Override
public void check(int row, String value, ValidationError error) {
Integer valueInLineNumber = columnValueMap.get(value);
if (valueInLineNumber != null) {
if (!valueInLineNumber.equals(row)) {
valueInLineNumber += 1; // show not 0 based line numbers to user
error.add("validation.message.uniqueness", value, valueInLineNumber.toString());
}
} else {
columnValueMap.put(value, row);
}
}
@Override
public Type getType() {
return Type.UNIQUE;
}
}

View File

@@ -0,0 +1,11 @@
package ninja.javafx.smartcsv.validation;
/**
* Created by abi on 07.08.2016.
*/
public interface Validation {
enum Type { NOT_EMPTY, UNIQUE, DOUBLE, INTEGER, MIN_LENGTH, MAX_LENGTH, DATE, ALPHANUMERIC, REGEXP, VALUE_OF, GROOVY }
void check(int row, String value, ValidationError error);
Type getType();
}

View File

@@ -49,9 +49,7 @@ public class Validator {
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
private ValidationConfiguration validationConfig;
private GroovyShell shell = new GroovyShell();
private Map<String, Script> scriptCache = new HashMap<>();
private Map<String, HashMap<String, Integer>> uniquenessLookupTable = new HashMap<>();
private ColumnValidations columnValidations = new ColumnValidations();
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// constructors
@@ -63,6 +61,7 @@ public class Validator {
*/
public Validator(ValidationConfiguration validationConfig) {
this.validationConfig = validationConfig;
initColumnValidations();
}
@@ -76,25 +75,10 @@ public class Validator {
* @param value the value to check
* @return ValidationError with information if valid and if not which getMessage happened
*/
public ValidationError isValid(String column, String value, Integer lineNumber) {
public ValidationError isValid(Integer lineNumber, String column, String value) {
ValidationError result = null;
if (hasConfig()) {
ValidationError error = ValidationError.withLineNumber(lineNumber);
checkBlankOrNull(column, value, error);
if (value != null && !value.isEmpty()) {
checkRegularExpression(column, value, error);
checkAlphaNumeric(column, value, error);
checkDate(column, value, error);
checkMaxLength(column, value, error);
checkMinLength(column, value, error);
checkInteger(column, value, error);
checkGroovy(column, value, error);
checkValueOf(column, value, error);
checkDouble(column, value, error);
checkUniqueness(column, value, lineNumber, error);
}
ValidationError error = columnValidations.isValid(lineNumber, column, value);
if (!error.isEmpty()) {
result = error;
}
@@ -102,6 +86,7 @@ public class Validator {
return result;
}
public boolean hasConfig() {
return validationConfig != null;
}
@@ -110,147 +95,67 @@ public class Validator {
// private methods
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
private void checkUniqueness(String column, String value, Integer lineNumber, ValidationError error) {
Boolean uniqueRule = validationConfig.getUniqueRuleFor(column);
if (uniqueRule != null && uniqueRule) {
HashMap<String, Integer> columnValueMap = uniquenessLookupTable.get(column);
columnValueMap = getColumnValueMap(column, columnValueMap);
Integer valueInLineNumber = columnValueMap.get(value);
if (valueInLineNumber != null) {
if (!valueInLineNumber.equals(lineNumber)) {
error.add("validation.message.uniqueness", value, valueInLineNumber.toString());
}
} else {
columnValueMap.put(value, lineNumber);
private void initColumnValidations() {
if (hasConfig()) {
String[] columns = validationConfig.headerNames();
for(String column: columns) {
Boolean alphaNumeric = validationConfig.getAlphanumericRuleFor(column);
if (alphaNumeric != null && alphaNumeric) {
columnValidations.add(column, new AlphaNumericValidation());
}
Boolean doubleRule = validationConfig.getDoubleRuleFor(column);
if (doubleRule != null && doubleRule) {
columnValidations.add(column, new DoubleValidation());
}
Boolean integerRule = validationConfig.getIntegerRuleFor(column);
if (integerRule != null && integerRule) {
columnValidations.add(column, new IntegerValidation());
}
Boolean notEmptyRule = validationConfig.getNotEmptyRuleFor(column);
if (notEmptyRule != null && notEmptyRule) {
columnValidations.add(column, new NotEmptyValidation());
}
Boolean uniqueRule = validationConfig.getUniqueRuleFor(column);
if (uniqueRule != null && uniqueRule) {
columnValidations.add(column, new UniqueValidation());
}
String dateRule = validationConfig.getDateRuleFor(column);
if (dateRule != null && !dateRule.trim().isEmpty()) {
columnValidations.add(column, new DateValidation(dateRule));
}
Integer minLength = validationConfig.getMinLengthRuleFor(column);
if (minLength != null) {
columnValidations.add(column, new MinLengthValidation(minLength));
}
Integer maxLength = validationConfig.getMaxLengthRuleFor(column);
if (maxLength != null) {
columnValidations.add(column, new MaxLengthValidation(maxLength));
}
String regexp = validationConfig.getRegexpRuleFor(column);
if (regexp != null && !regexp.trim().isEmpty()) {
columnValidations.add(column, new RegExpValidation(regexp));
}
String groovy = validationConfig.getGroovyRuleFor(column);
if (groovy != null && !groovy.trim().isEmpty()) {
columnValidations.add(column, new GroovyValidation(groovy));
}
List<String> valueOfRule = validationConfig.getValueOfRuleFor(column);
if (valueOfRule != null && !valueOfRule.isEmpty()) {
columnValidations.add(column, new ValueOfValidation(valueOfRule));
}
}
}
}
private HashMap<String, Integer> getColumnValueMap(String column, HashMap<String, Integer> valueLineNumber) {
if (valueLineNumber == null) {
valueLineNumber = new HashMap<>();
uniquenessLookupTable.put(column, valueLineNumber);
}
return valueLineNumber;
}
private void checkGroovy(String column, String value, ValidationError error) {
String groovyScript = validationConfig.getGroovyRuleFor(column);
if (groovyScript != null) {
Script script = scriptCache.get(column);
if (script == null) {
script = shell.parse(groovyScript);
scriptCache.put(column, script);
}
Binding binding = new Binding();
binding.setVariable("value", value);
script.setBinding(binding);
Object groovyResult = null;
try {
groovyResult = script.run();
} catch (CompilationFailedException e) {
error.add("validation.message.groovy.exception", groovyScript, e.getMessage());
e.printStackTrace();
}
if (groovyResult == null) {
error.add("validation.message.groovy.return.null", groovyScript);
}
if (!isScriptResultTrue(groovyResult)) {
error.add(groovyResult.toString());
}
}
}
private boolean isScriptResultTrue(Object groovyResult) {
return groovyResult.equals(true) || groovyResult.toString().trim().toLowerCase().equals("true");
}
private void checkValueOf(String column, String value, ValidationError error) {
List<String> values = validationConfig.getValueOfRuleFor(column);
if (values != null) {
if (!values.contains(value)) {
String commaSeparated = values.stream().collect(joining(", "));
error.add("validation.message.value.of", value, commaSeparated);
}
}
}
private void checkBlankOrNull(String column, String value, ValidationError error) {
Boolean notEmptyRule = validationConfig.getNotEmptyRuleFor(column);
if (notEmptyRule != null && notEmptyRule) {
if (isBlankOrNull(value)) {
error.add("validation.message.not.empty");
}
}
}
private void checkInteger(String column, String value, ValidationError error) {
Boolean integerRule = validationConfig.getIntegerRuleFor(column);
if (integerRule != null && integerRule) {
if (!isInt(value)) {
error.add("validation.message.integer");
}
}
}
private void checkDouble(String column, String value, ValidationError error) {
Boolean doubleRule = validationConfig.getDoubleRuleFor(column);
if (doubleRule != null && doubleRule) {
if (!isDouble(value)) {
error.add("validation.message.double");
}
}
}
private void checkMinLength(String column, String value, ValidationError error) {
Integer minLength = validationConfig.getMinLengthRuleFor(column);
if (minLength != null) {
if (!minLength(value, minLength)) {
error.add("validation.message.min.length", minLength.toString());
}
}
}
private void checkMaxLength(String column, String value, ValidationError error) {
Integer maxLength = validationConfig.getMaxLengthRuleFor(column);
if (maxLength != null) {
if (!maxLength(value, maxLength)) {
error.add("validation.message.max.length", maxLength.toString());
}
}
}
private void checkDate(String column, String value, ValidationError error) {
String dateformat = validationConfig.getDateRuleFor(column);
if (dateformat != null && !dateformat.trim().isEmpty()) {
if (!isDate(value, dateformat, true)) {
error.add("validation.message.date.format", dateformat);
}
}
}
private void checkAlphaNumeric(String column, String value, ValidationError error) {
Boolean alphaNumericRule = validationConfig.getAlphanumericRuleFor(column);
if (alphaNumericRule != null && alphaNumericRule) {
if (!matchRegexp(value, "[0-9a-zA-Z]*")) {
error.add("validation.message.alphanumeric");
}
}
}
private void checkRegularExpression(String column, String value, ValidationError error) {
String regexp = validationConfig.getRegexpRuleFor(column);
if (regexp != null && !regexp.trim().isEmpty()) {
if (!matchRegexp(value, regexp)) {
error.add("validation.message.regexp", regexp);
}
}
}
public ValidationError isHeaderValid(String[] headerNames) {
ValidationError result = null;
@@ -281,8 +186,4 @@ public class Validator {
}
return result;
}
public void clearScriptCache() {
scriptCache.clear();
}
}

View File

@@ -0,0 +1,30 @@
package ninja.javafx.smartcsv.validation;
import java.util.List;
import static java.util.stream.Collectors.joining;
/**
* Created by abi on 07.08.2016.
*/
public class ValueOfValidation implements Validation {
private List<String> values;
public ValueOfValidation(List<String> values) {
this.values = values;
}
@Override
public void check(int row, String value, ValidationError error) {
if (!values.contains(value)) {
String commaSeparated = values.stream().collect(joining(", "));
error.add("validation.message.value.of", value, commaSeparated);
}
}
@Override
public Type getType() {
return Type.VALUE_OF;
}
}