9 Commits
0.5 ... 0.6

46 changed files with 932 additions and 443 deletions

View File

@@ -1,5 +1,5 @@
group 'ninja.javafx'
version '0.5-SNAPSHOT'
version '0.6-SNAPSHOT'
apply plugin: 'java'
apply plugin: 'groovy'

View File

@@ -29,7 +29,6 @@ package ninja.javafx.smartcsv.csv;
import ninja.javafx.smartcsv.FileReader;
import ninja.javafx.smartcsv.fx.table.model.CSVModel;
import ninja.javafx.smartcsv.fx.table.model.CSVRow;
import org.springframework.stereotype.Service;
import org.supercsv.io.CsvMapReader;
import org.supercsv.io.ICsvMapReader;
@@ -60,7 +59,7 @@ public class CSVFileReader extends CSVConfigurable implements FileReader<CSVMode
while ((customerMap = mapReader.read(header)) != null) {
CSVRow row = model.addRow();
for (String column : header) {
row.addValue(column, customerMap.get(column));
model.addValue(row, column, customerMap.get(column));
}
}

View File

@@ -28,7 +28,6 @@ package ninja.javafx.smartcsv.csv;
import ninja.javafx.smartcsv.fx.table.model.CSVModel;
import ninja.javafx.smartcsv.fx.table.model.CSVRow;
import org.springframework.stereotype.Service;
import org.supercsv.io.CsvMapWriter;
import org.supercsv.io.ICsvMapWriter;

View File

@@ -28,11 +28,9 @@ package ninja.javafx.smartcsv.fx;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.event.EventHandler;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
import javafx.stage.WindowEvent;
import ninja.javafx.smartcsv.fx.about.AboutController;
import org.springframework.context.annotation.*;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;

View File

@@ -26,10 +26,6 @@
package ninja.javafx.smartcsv.fx;
import javafx.beans.InvalidationListener;
import javafx.beans.Observable;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.ListChangeListener;
import javafx.collections.WeakListChangeListener;
import javafx.concurrent.WorkerStateEvent;
@@ -41,7 +37,6 @@ import javafx.scene.control.*;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.BorderPane;
import javafx.stage.FileChooser;
import javafx.util.converter.NumberStringConverter;
import ninja.javafx.smartcsv.csv.CSVFileReader;
import ninja.javafx.smartcsv.csv.CSVFileWriter;
import ninja.javafx.smartcsv.files.FileStorage;
@@ -71,11 +66,9 @@ import org.supercsv.prefs.CsvPreference;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.text.MessageFormat;
import java.util.Optional;
import java.util.ResourceBundle;
import static java.lang.Integer.parseInt;
import static java.lang.Math.max;
import static java.text.MessageFormat.format;
import static javafx.application.Platform.exit;
@@ -352,7 +345,7 @@ public class SmartCSVController extends FXMLController {
public void addRow(ActionEvent actionEvent) {
CSVRow row = currentCsvFile.getContent().addRow();
for (String column : currentCsvFile.getContent().getHeader()) {
row.addValue(column, "");
currentCsvFile.getContent().addValue(row, column, "");
}
currentCsvFile.setFileChanged(true);
resetContent();
@@ -408,7 +401,7 @@ public class SmartCSVController extends FXMLController {
runLater(() -> {
validationEditorController.updateConfiguration();
currentCsvFile.setFileChanged(true);
currentCsvFile.getContent().revalidate();
currentCsvFile.getContent().revalidate(column);
});
}
}
@@ -590,7 +583,7 @@ public class SmartCSVController extends FXMLController {
* @param header name of the column header
* @param tableView the tableview
*/
private void addColumn(String header, TableView tableView) {
private void addColumn(final String header, TableView tableView) {
TableColumn column = new TableColumn(header);
column.setCellValueFactory(new ObservableMapValueFactory(header));
column.setCellFactory(cellFactory);
@@ -607,7 +600,6 @@ public class SmartCSVController extends FXMLController {
getColumns().get(header).setValue(event.getNewValue());
runLater(() -> {
currentCsvFile.setFileChanged(true);
currentCsvFile.getContent().revalidate();
});
}
});

View File

@@ -36,7 +36,6 @@ import javafx.scene.layout.Region;
import javafx.scene.layout.VBox;
import javafx.scene.text.Text;
import ninja.javafx.smartcsv.fx.table.model.CSVModel;
import ninja.javafx.smartcsv.fx.util.ColorConstants;
import ninja.javafx.smartcsv.validation.ValidationError;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

View File

@@ -1,6 +1,5 @@
package ninja.javafx.smartcsv.fx.list;
import com.sun.javafx.scene.control.skin.resources.ControlResources;
import javafx.application.Platform;
import javafx.geometry.Pos;
import javafx.scene.control.*;

View File

@@ -33,7 +33,6 @@ import javafx.scene.control.Tooltip;
import javafx.scene.input.KeyCode;
import ninja.javafx.smartcsv.fx.table.model.CSVRow;
import ninja.javafx.smartcsv.fx.table.model.CSVValue;
import ninja.javafx.smartcsv.fx.util.ColorConstants;
import java.util.ResourceBundle;

View File

@@ -28,22 +28,18 @@ package ninja.javafx.smartcsv.fx.table.model;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.concurrent.Service;
import javafx.concurrent.Task;
import ninja.javafx.smartcsv.validation.RevalidationService;
import ninja.javafx.smartcsv.validation.ValidationConfiguration;
import ninja.javafx.smartcsv.validation.ValidationError;
import ninja.javafx.smartcsv.validation.Validator;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.util.ArrayList;
import java.util.List;
/**
* The CSVModel is the client representation for the csv filepath.
* It holds the data in rows, stores the header and manages the validator.
*/
public class CSVModel {
public final class CSVModel {
private static final Logger logger = LogManager.getLogger(CSVModel.class);
@@ -55,6 +51,7 @@ public class CSVModel {
/**
* sets the validator configuration for the data revalidates
*
* @param validationConfiguration the validator configuration for this data
*/
public void setValidationConfiguration(ValidationConfiguration validationConfiguration) {
@@ -64,6 +61,7 @@ public class CSVModel {
/**
* returns the data as a list of rows of the
*
* @return list of rows
*/
public ObservableList<CSVRow> getRows() {
@@ -76,18 +74,30 @@ public class CSVModel {
/**
* adds a new and empty row
*
* @return the new row
*/
public CSVRow addRow() {
CSVRow row = new CSVRow();
row.setValidator(validator);
row.setRowNumber(rows.size());
rows.add(row);
return row;
}
public void addValue(final CSVRow row, final String column, final String value) {
final CSVValue csvValue = row.addValue(column, value);
csvValue.valueProperty().addListener(observable -> {
if (validator.needsColumnValidation(column)) {
revalidate();
} else {
csvValue.setValidationError(validator.isValid(row.getRowNumber(), column, csvValue.getValue()));
}
});
}
/**
* sets the column headers as string array
*
* @param header the headers of the columns
*/
public void setHeader(String[] header) {
@@ -97,6 +107,7 @@ public class CSVModel {
/**
* returns the column headers
*
* @return the column headers
*/
public String[] getHeader() {
@@ -104,6 +115,12 @@ public class CSVModel {
}
public void revalidate(String column) {
if (!hasValidator()) return;
validator.reinitializeColumn(column);
revalidate();
}
/**
* walks through the data and validates each value
*/
@@ -113,8 +130,6 @@ public class CSVModel {
logger.info("revalidate: hasValidator -> {}", hasValidator());
if (!hasValidator()) return;
validator.clearScriptCache();
revalidationService.setHeader(header);
revalidationService.setRows(rows);
revalidationService.setValidator(validator);
@@ -135,66 +150,6 @@ public class CSVModel {
return newValidationConfiguration;
}
private static class RevalidationService extends Service<List<ValidationError>> {
private Validator validator;
private List<CSVRow> rows;
private String[] header;
public void setValidator(Validator validator) {
this.validator = validator;
}
public void setRows(List<CSVRow> rows) {
this.rows = rows;
}
public void setHeader(String[] header) {
this.header = header;
}
@Override
protected Task<List<ValidationError>> createTask() {
return new Task<List<ValidationError>>() {
@Override
protected List<ValidationError> call() throws Exception {
List<ValidationError> errors = new ArrayList<>();
try {
if (header != null) {
ValidationError headerError = validator.isHeaderValid(header);
if (headerError != null) {
logger.info("revalidate: header error found");
errors.add(headerError);
}
}
for (int lineNumber = 0; lineNumber < rows.size(); lineNumber++) {
CSVRow row = rows.get(lineNumber);
row.setValidator(validator);
for (String column : row.getColumns().keySet()) {
CSVValue value = row.getColumns().get(column).getValue();
value.setValidator(validator);
if (validator != null) {
ValidationError validationError = validator.isValid(column, value.getValue(), lineNumber);
if (validationError != null) {
logger.info("revalidate: {} errors found in line {}", validationError.getMessages().size(), lineNumber);
errors.add(validationError);
value.setValidationError(validationError);
} else {
value.setValidationError(null);
}
} else {
value.setValidationError(null);
}
}
}
} catch (Throwable t) {
logger.error("validation error", t);
}
return errors;
}
};
}
}
}

View File

@@ -30,24 +30,14 @@ import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableMap;
import ninja.javafx.smartcsv.validation.Validator;
/**
* This class represents a single row in the csv file.
*/
public class CSVRow {
private Validator validator;
private ObservableMap<String, ObjectProperty<CSVValue>> columns = FXCollections.observableHashMap();
private int rowNumber;
/**
* single row
* @param validator the reference to the validator
*/
public void setValidator(Validator validator) {
this.validator = validator;
}
/**
* sets the row number
* @param rowNumber
@@ -78,13 +68,11 @@ public class CSVRow {
* @param column column name
* @param value the value to store
*/
public void addValue(String column, String value) {
CSVValue addValue(String column, String value) {
CSVValue v = new CSVValue();
v.setValidator(validator);
v.setColumn(column);
v.setRowNumber(rowNumber);
v.setValue(value);
columns.put(column, new SimpleObjectProperty<>(v));
return v;
}
}

View File

@@ -29,7 +29,6 @@ package ninja.javafx.smartcsv.fx.table.model;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import ninja.javafx.smartcsv.validation.ValidationError;
import ninja.javafx.smartcsv.validation.Validator;
/**
* The csv value represents the value of a single cell.
@@ -37,36 +36,9 @@ import ninja.javafx.smartcsv.validation.Validator;
* and if the value is valid based on the validator.
*/
public class CSVValue {
private Validator validator;
private int rowNumber;
private String column;
private StringProperty value = new SimpleStringProperty();
private ValidationError valid;
/**
* single value of a cell
* @param validator the reference to the validator
*/
public void setValidator(Validator validator) {
this.validator = validator;
}
/**
* the row number this value is stored in
* @param row row number
*/
public void setRowNumber(int row) {
this.rowNumber = row;
}
/**
* the column this value is stored in
* @param column header name of the column
*/
public void setColumn(String column) {
this.column = column;
}
/**
* returns the real value
* @return the real value
@@ -88,9 +60,6 @@ public class CSVValue {
* @param value the real value
*/
public void setValue(String value) {
if (validator != null) {
valid = validator.isValid(column, value, rowNumber);
}
this.value.set(value);
}
@@ -106,7 +75,7 @@ public class CSVValue {
* sets the state if a value is valid or not
* @param valid the validation state
*/
protected void setValidationError(ValidationError valid) {
public void setValidationError(ValidationError valid) {
this.valid = valid;
}
}

View File

@@ -31,5 +31,5 @@ package ninja.javafx.smartcsv.fx.util;
*/
public class ColorConstants {
public static final String OK_COLOR = "#22aa22";
public static final String ERROR_COLOR = "#ff6622";
public static final String ERROR_COLOR = "#ff3333";
}

View File

@@ -62,7 +62,7 @@ public class I18nValidationUtil {
if (resourceBundle.containsKey(validationMessage.getKey())) {
String resourceText = resourceBundle.getString(validationMessage.getKey());
if (validationMessage.getParameters().length > 0) {
message.append(format(resourceText, validationMessage.getParameters())).append("\n");
message.append(format(resourceText, (Object[]) validationMessage.getParameters())).append("\n");
} else {
message.append(resourceText).append("\n");
}

View File

@@ -28,11 +28,8 @@ package ninja.javafx.smartcsv.fx.util;
import javafx.concurrent.Service;
import javafx.concurrent.Task;
import ninja.javafx.smartcsv.FileReader;
import ninja.javafx.smartcsv.files.FileStorage;
import java.io.File;
/**
* Service class for async load of a csv file
*/

View File

@@ -28,14 +28,8 @@ package ninja.javafx.smartcsv.fx.util;
import javafx.concurrent.Service;
import javafx.concurrent.Task;
import ninja.javafx.smartcsv.FileWriter;
import ninja.javafx.smartcsv.csv.CSVFileWriter;
import ninja.javafx.smartcsv.files.FileStorage;
import java.io.File;
import static javafx.application.Platform.runLater;
/**
* Service class for async load of a csv file
*/

View File

@@ -107,6 +107,9 @@ public class ValidationEditorController extends FXMLController {
@FXML
private CheckBox alphanumericRuleCheckBox;
@FXML
private CheckBox uniqueRuleCheckBox;
@FXML
private Spinner<Integer> minLengthSpinner;
@@ -155,6 +158,9 @@ public class ValidationEditorController extends FXMLController {
@FXML
private CheckBox enableGroovyRule;
@FXML
private CheckBox enableUniqueRule;
@Value("${fxml.smartcvs.validation.editor.view}")
@Override
@@ -172,6 +178,7 @@ public class ValidationEditorController extends FXMLController {
initCheckBox(integerRuleCheckBox, enableIntegerRule);
initCheckBox(doublerRuleCheckBox, enableDoubleRule);
initCheckBox(alphanumericRuleCheckBox, enableAlphanumericRule);
initCheckBox(uniqueRuleCheckBox, enableUniqueRule);
initSpinner(minLengthSpinner, enableMinLengthRule);
initSpinner(maxLengthSpinner, enableMaxLengthRule);
initTextInputControl(dateformatRuleTextField, enableDateRule);
@@ -214,6 +221,12 @@ public class ValidationEditorController extends FXMLController {
validationConfiguration.setNotEmptyRuleFor(selectedColumn.getValue(), null);
}
if (enableUniqueRule.isSelected()) {
validationConfiguration.setUniqueRuleFor(selectedColumn.getValue(), uniqueRuleCheckBox.isSelected());
} else {
validationConfiguration.setUniqueRuleFor(selectedColumn.getValue(), null);
}
if (enableDoubleRule.isSelected()) {
validationConfiguration.setDoubleRuleFor(selectedColumn.getValue(), doublerRuleCheckBox.isSelected());
} else {
@@ -261,6 +274,8 @@ public class ValidationEditorController extends FXMLController {
} else {
validationConfiguration.setValueOfRuleFor(selectedColumn.getValue(), null);
}
}
private void updateForm() {
@@ -289,6 +304,12 @@ public class ValidationEditorController extends FXMLController {
enableAlphanumericRule
);
updateCheckBox(
uniqueRuleCheckBox,
validationConfiguration.getUniqueRuleFor(getSelectedColumn()),
enableUniqueRule
);
updateSpinner(
minLengthSpinner,
validationConfiguration.getMinLengthRuleFor(getSelectedColumn()),

View File

@@ -28,7 +28,6 @@ package ninja.javafx.smartcsv.preferences;
import com.google.gson.GsonBuilder;
import ninja.javafx.smartcsv.FileReader;
import org.springframework.stereotype.Service;
import org.supercsv.prefs.CsvPreference;
import org.supercsv.quote.AlwaysQuoteMode;

View File

@@ -29,7 +29,6 @@ package ninja.javafx.smartcsv.preferences;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import ninja.javafx.smartcsv.FileWriter;
import org.springframework.stereotype.Service;
import org.supercsv.prefs.CsvPreference;
import java.io.File;

View File

@@ -0,0 +1,45 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015 javafx.ninja <info@javafx.ninja>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package ninja.javafx.smartcsv.validation;
import static org.apache.commons.validator.GenericValidator.matchRegexp;
/**
* Checks if the value is alpha numeric
*/
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,53 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015 javafx.ninja <info@javafx.ninja>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package ninja.javafx.smartcsv.validation;
import static org.apache.commons.validator.GenericValidator.isDate;
/**
* Checks if the date has the right format
*/
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,46 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015 javafx.ninja <info@javafx.ninja>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package ninja.javafx.smartcsv.validation;
import static org.apache.commons.validator.GenericValidator.isDouble;
/**
* Checks if the value is a double
*/
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,78 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015 javafx.ninja <info@javafx.ninja>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package ninja.javafx.smartcsv.validation;
import groovy.lang.Binding;
import groovy.lang.GroovyShell;
import groovy.lang.Script;
import org.codehaus.groovy.control.CompilationFailedException;
/**
* Executes the given groovy as check
*/
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,46 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015 javafx.ninja <info@javafx.ninja>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package ninja.javafx.smartcsv.validation;
import static org.apache.commons.validator.GenericValidator.isInt;
/**
* Checks if the value is an integer
*/
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,52 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015 javafx.ninja <info@javafx.ninja>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package ninja.javafx.smartcsv.validation;
import static org.apache.commons.validator.GenericValidator.maxLength;
/**
* Checks if the value is shorter or exactly as long as the given max length
*/
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,52 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015 javafx.ninja <info@javafx.ninja>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package ninja.javafx.smartcsv.validation;
import static org.apache.commons.validator.GenericValidator.minLength;
/**
* Checks if the value is at minimum long as the given min length
*/
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,46 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015 javafx.ninja <info@javafx.ninja>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package ninja.javafx.smartcsv.validation;
import static org.apache.commons.validator.GenericValidator.isBlankOrNull;
/**
* Checks if the value is not empty
*/
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,52 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015 javafx.ninja <info@javafx.ninja>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package ninja.javafx.smartcsv.validation;
import static org.apache.commons.validator.GenericValidator.matchRegexp;
/**
* Checks the value against the given reg exp
*/
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,110 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015 javafx.ninja <info@javafx.ninja>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package ninja.javafx.smartcsv.validation;
import javafx.beans.property.ObjectProperty;
import javafx.concurrent.Service;
import javafx.concurrent.Task;
import ninja.javafx.smartcsv.fx.table.model.CSVRow;
import ninja.javafx.smartcsv.fx.table.model.CSVValue;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Service for running the validation async of the ui thread
*/
public class RevalidationService extends Service<List<ValidationError>> {
private static final Logger logger = LogManager.getLogger(RevalidationService.class);
private Validator validator;
private List<CSVRow> rows;
private String[] header;
public void setValidator(Validator validator) {
this.validator = validator;
}
public void setRows(List<CSVRow> rows) {
this.rows = rows;
}
public void setHeader(String[] header) {
this.header = header;
}
@Override
protected Task<List<ValidationError>> createTask() {
return new Task<List<ValidationError>>() {
@Override
protected List<ValidationError> call() throws Exception {
List<ValidationError> errors = new ArrayList<>();
try {
if (header != null) {
ValidationError headerError = validator.isHeaderValid(header);
if (headerError != null) {
logger.info("revalidate: header error found");
errors.add(headerError);
}
}
int maxRows = rows.size();
for (int lineNumber = 0; lineNumber < maxRows; lineNumber++) {
CSVRow row = rows.get(lineNumber);
Map<String, ObjectProperty<CSVValue>> table = row.getColumns();
Set<String> columns = table.keySet();
for (String column : columns) {
CSVValue value = table.get(column).getValue();
if (validator != null) {
ValidationError validationError = validator.isValid(lineNumber, column, value.getValue());
if (validationError != null) {
logger.info("revalidate: {} errors found in line {}", validationError.getMessages().size(), lineNumber);
errors.add(validationError);
value.setValidationError(validationError);
} else {
value.setValidationError(null);
}
} else {
value.setValidationError(null);
}
}
}
} catch (Throwable t) {
logger.error("validation error", t);
}
return errors;
}
};
}
}

View File

@@ -0,0 +1,54 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015 javafx.ninja <info@javafx.ninja>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package ninja.javafx.smartcsv.validation;
import java.util.HashMap;
/**
* Checks if the value is unique in the column
*/
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,36 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015 javafx.ninja <info@javafx.ninja>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package ninja.javafx.smartcsv.validation;
/**
* Interface for all validations
*/
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

@@ -52,7 +52,7 @@ public class ValidationConfiguration {
headerConfiguration.setNames(headerNames);
}
public Boolean getUniquenessRuleFor(String column) {
public Boolean getUniqueRuleFor(String column) {
return (Boolean)getValue(column, "unique");
}
@@ -73,32 +73,27 @@ public class ValidationConfiguration {
}
public Integer getMaxLengthRuleFor(String column) {
if (noRulesFor(column)) return null;
return doubleToInteger((Double)getValue(column, "maxlength"));
Double value = (Double)getValue(column, "maxlength");
return value != null ? doubleToInteger(value) : null;
}
public String getDateRuleFor(String column) {
if (noRulesFor(column)) return null;
return (String)getValue(column, "date");
}
public Boolean getAlphanumericRuleFor(String column) {
if (noRulesFor(column)) return null;
return (Boolean)getValue(column, "alphanumeric");
}
public String getRegexpRuleFor(String column) {
if (noRulesFor(column)) return null;
return (String)getValue(column, "regexp");
}
public List<String> getValueOfRuleFor(String column) {
if (noRulesFor(column)) return null;
return (List<String>)getValue(column, "value of");
}
public String getGroovyRuleFor(String column) {
if (noRulesFor(column)) return null;
return (String)getValue(column, "groovy");
}
@@ -114,6 +109,11 @@ public class ValidationConfiguration {
setValue(column, value, "not empty");
}
public void setUniqueRuleFor(String column, Boolean value) {
setValue(column, value, "unique");
}
public void setMinLengthRuleFor(String column, Integer value) {
setValue(column, value == null ? null : value.doubleValue(), "minlength");
}
@@ -155,18 +155,19 @@ public class ValidationConfiguration {
}
private Object getValue(String column, String key) {
if (noRulesFor(column)) return null;
if (columnConfigurations != null) {
Map rulesForColumn = columnConfigurations.get(column);
if (rulesForColumn != null) {
return columnConfigurations.get(column).get(key);
}
}
return null;
}
private boolean noHeader() {
return headerConfiguration == null;
}
private boolean noRulesFor(String column) {
return columnConfigurations == null || columnConfigurations.get(column) == null;
}
private Integer doubleToInteger(Double value) {
if (value == null) return null;
return (int)Math.round(value);

View File

@@ -28,7 +28,6 @@ package ninja.javafx.smartcsv.validation;
import com.google.gson.GsonBuilder;
import ninja.javafx.smartcsv.FileReader;
import org.springframework.stereotype.Service;
import java.io.File;
import java.io.IOException;

View File

@@ -29,7 +29,6 @@ package ninja.javafx.smartcsv.validation;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import ninja.javafx.smartcsv.FileWriter;
import org.springframework.stereotype.Service;
import java.io.File;
import java.io.IOException;

View File

@@ -26,19 +26,10 @@
package ninja.javafx.smartcsv.validation;
import groovy.lang.Binding;
import groovy.lang.GroovyShell;
import groovy.lang.Script;
import org.codehaus.groovy.control.CompilationFailedException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import static java.util.stream.Collectors.joining;
import static org.apache.commons.validator.GenericValidator.*;
/**
* This class checks all the validations defined in the
* Config against a given value
@@ -50,9 +41,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 Map<String, Map<Validation.Type, Validation>> columnValidationMap = new HashMap<>();
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// constructors
@@ -60,10 +49,12 @@ public class Validator {
/**
* JSON configuration for this validator
*
* @param validationConfig
*/
public Validator(ValidationConfiguration validationConfig) {
this.validationConfig = validationConfig;
initColumnValidations();
}
@@ -71,31 +62,40 @@ public class Validator {
// public methods
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public boolean needsColumnValidation(String column) {
Map<Validation.Type, Validation> validationMap = columnValidationMap.get(column);
if (validationMap != null) {
return validationMap.containsKey(Validation.Type.UNIQUE);
}
return false;
}
/**
* checks if the value is valid for the column configuration
*
* @param column the column name
* @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 row, String column, String value) {
ValidationError result = null;
if (hasConfig()) {
ValidationError error = ValidationError.withLineNumber(row);
Map<Validation.Type, Validation> validationMap = columnValidationMap.get(column);
if (validationMap != null) {
for (Validation validation: validationMap.values()) {
ValidationError error = ValidationError.withLineNumber(lineNumber);
checkBlankOrNull(column, value, error);
if (validation.getType() == Validation.Type.NOT_EMPTY) {
validation.check(row, value, error);
} else {
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);
validation.check(row, value, error);
}
}
}
}
if (!error.isEmpty()) {
result = error;
}
@@ -103,151 +103,102 @@ public class Validator {
return result;
}
public boolean hasConfig() {
return validationConfig != null;
}
public void reinitializeColumn(String column) {
clear(column);
initializeColumnWithRules(column);
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// private methods
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
private void checkUniqueness(String column, String value, Integer lineNumber, ValidationError error) {
if (validationConfig.getUniquenessRuleFor(column) != null && validationConfig.getUniquenessRuleFor(column)) {
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());
private void add(String column, Validation validation) {
Map<Validation.Type, Validation> validationMap = columnValidationMap.get(column);
if (validationMap == null) {
validationMap = new HashMap<>();
columnValidationMap.put(column, validationMap);
}
} else {
columnValueMap.put(value, lineNumber);
validationMap.put(validation.getType(), validation);
}
private void clear(String column) {
Map<Validation.Type, Validation> validationMap = columnValidationMap.get(column);
if (validationMap != null) {
validationMap.clear();
}
}
private void initColumnValidations() {
if (hasConfig()) {
String[] columns = validationConfig.headerNames();
for (String column : columns) {
initializeColumnWithRules(column);
}
}
}
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 initializeColumnWithRules(String column) {
Boolean alphaNumeric = validationConfig.getAlphanumericRuleFor(column);
if (alphaNumeric != null && alphaNumeric) {
add(column, new AlphaNumericValidation());
}
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);
Boolean doubleRule = validationConfig.getDoubleRuleFor(column);
if (doubleRule != null && doubleRule) {
add(column, new DoubleValidation());
}
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);
Boolean integerRule = validationConfig.getIntegerRuleFor(column);
if (integerRule != null && integerRule) {
add(column, new IntegerValidation());
}
if (!isScriptResultTrue(groovyResult)) {
error.add(groovyResult.toString());
Boolean notEmptyRule = validationConfig.getNotEmptyRuleFor(column);
if (notEmptyRule != null && notEmptyRule) {
add(column, new NotEmptyValidation());
}
}
Boolean uniqueRule = validationConfig.getUniqueRuleFor(column);
if (uniqueRule != null && uniqueRule) {
add(column, new UniqueValidation());
}
private boolean isScriptResultTrue(Object groovyResult) {
return groovyResult.equals(true) || groovyResult.toString().trim().toLowerCase().equals("true");
String dateRule = validationConfig.getDateRuleFor(column);
if (dateRule != null && !dateRule.trim().isEmpty()) {
add(column, new DateValidation(dateRule));
}
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) {
if (validationConfig.getNotEmptyRuleFor(column) != null && validationConfig.getNotEmptyRuleFor(column)) {
if (isBlankOrNull(value)) {
error.add("validation.message.not.empty");
}
}
}
private void checkInteger(String column, String value, ValidationError error) {
if (validationConfig.getIntegerRuleFor(column) != null && validationConfig.getIntegerRuleFor(column)) {
if (!isInt(value)) {
error.add("validation.message.integer");
}
}
}
private void checkDouble(String column, String value, ValidationError error) {
if (validationConfig.getDoubleRuleFor(column) != null && validationConfig.getDoubleRuleFor(column)) {
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());
}
}
add(column, new MinLengthValidation(minLength));
}
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());
}
}
add(column, new MaxLengthValidation(maxLength));
}
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) {
if (validationConfig.getAlphanumericRuleFor(column) != null && validationConfig.getAlphanumericRuleFor(column)) {
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);
}
add(column, new RegExpValidation(regexp));
}
String groovy = validationConfig.getGroovyRuleFor(column);
if (groovy != null && !groovy.trim().isEmpty()) {
add(column, new GroovyValidation(groovy));
}
List<String> valueOfRule = validationConfig.getValueOfRuleFor(column);
if (valueOfRule != null && !valueOfRule.isEmpty()) {
add(column, new ValueOfValidation(valueOfRule));
}
}
public ValidationError isHeaderValid(String[] headerNames) {
ValidationError result = null;
if (validationConfig != null) {
@@ -277,8 +228,4 @@ public class Validator {
}
return result;
}
public void clearScriptCache() {
scriptCache.clear();
}
}

View File

@@ -0,0 +1,55 @@
/*
The MIT License (MIT)
-----------------------------------------------------------------------------
Copyright (c) 2015 javafx.ninja <info@javafx.ninja>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package ninja.javafx.smartcsv.validation;
import java.util.List;
import static java.util.stream.Collectors.joining;
/**
* Checks if the value is part of a list of values
*/
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;
}
}

View File

@@ -1,16 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Hyperlink?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.ScrollPane?>
<?import javafx.scene.control.TextArea?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.layout.VBox?>
<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.text.Font?>
<VBox maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="600.0" prefWidth="600.0" spacing="4.0" xmlns="http://javafx.com/javafx/8.0.60" xmlns:fx="http://javafx.com/fxml/1">
<children>
<Label text="SmartCSV.fx">

View File

@@ -1,5 +1,5 @@
application.name = SmartCSV.fx
application.version = 0.5
application.version = 0.6
# fxml views
fxml.smartcvs.view = /ninja/javafx/smartcsv/fx/smartcsv.fxml

View File

@@ -1,10 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.*?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<GridPane hgap="8.0" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" vgap="8.0" xmlns="http://javafx.com/javafx/8.0.66" xmlns:fx="http://javafx.com/fxml/1">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" />

View File

@@ -1,27 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import de.jensd.fx.glyphs.GlyphsStack?>
<?import de.jensd.fx.glyphs.materialdesignicons.MaterialDesignIconView?>
<?import java.net.URL?>
<?import de.jensd.fx.glyphs.*?>
<?import de.jensd.fx.glyphs.materialdesignicons.*?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.Menu?>
<?import javafx.scene.control.MenuBar?>
<?import javafx.scene.control.MenuItem?>
<?import javafx.scene.control.SeparatorMenuItem?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.control.ToolBar?>
<?import javafx.scene.control.Tooltip?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.Region?>
<?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import java.net.URL?>
<BorderPane fx:id="applicationPane" maxHeight="-Infinity" maxWidth="1000.0" minHeight="700.0" minWidth="-Infinity" prefHeight="700.0" prefWidth="1000.0" xmlns="http://javafx.com/javafx/8.0.101" xmlns:fx="http://javafx.com/fxml/1">
<top>
<VBox id="background" prefWidth="100.0" BorderPane.alignment="CENTER">

View File

@@ -71,6 +71,7 @@ validation.rule.label.groovy = groovy:
validation.rules.active = active
validation.rules.name = rule
validation.rules.value = value
validation.rule.label.unique = Unique in column:
dialog.validation.rules.title = Validation rules
dialog.validation.rules.header = Validation rules of column "{0}"

View File

@@ -80,6 +80,7 @@ validation.rule.label.groovy = groovy:
validation.rules.active = Aktiv
validation.rules.name = Regel
validation.rules.value = Wert
validation.rule.label.unique = Einmalig in Spalte:
dialog.validation.rules.title = Pr\u00fcfregeln
dialog.validation.rules.header = Pr\u00fcfregeln f\u00fcr die Spalte "{0}"

View File

@@ -1,15 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.CheckBox?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.Spinner?>
<?import javafx.scene.control.TextArea?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import org.fxmisc.richtext.CodeArea?>
<?import java.net.URL?>
<GridPane hgap="10.0" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefWidth="600.0" vgap="10.0" xmlns="http://javafx.com/javafx/8.0.101" xmlns:fx="http://javafx.com/fxml/1">
@@ -31,41 +24,46 @@
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<Label text="%validation.rule.label.not_empty" GridPane.columnIndex="1" GridPane.rowIndex="1" />
<Label text="%validation.rule.label.integer" GridPane.columnIndex="1" GridPane.rowIndex="2" />
<Label text="%validation.rule.label.double" GridPane.columnIndex="1" GridPane.rowIndex="3" />
<Label text="%validation.rule.label.minlength" GridPane.columnIndex="1" GridPane.rowIndex="5" />
<Label text="%validation.rule.label.maxlength" GridPane.columnIndex="1" GridPane.rowIndex="6" />
<Label text="%validation.rule.label.dateformat" GridPane.columnIndex="1" GridPane.rowIndex="7" />
<Label text="%validation.rule.label.minlength" GridPane.columnIndex="1" GridPane.rowIndex="6" />
<Label text="%validation.rule.label.maxlength" GridPane.columnIndex="1" GridPane.rowIndex="7" />
<Label text="%validation.rule.label.dateformat" GridPane.columnIndex="1" GridPane.rowIndex="8" />
<Label text="%validation.rule.label.alphanumeric" GridPane.columnIndex="1" GridPane.rowIndex="4" />
<Label text="%validation.rule.label.regexp" GridPane.columnIndex="1" GridPane.rowIndex="8" />
<Label text="%validation.rule.label.value_of" GridPane.columnIndex="1" GridPane.rowIndex="9" />
<Label text="%validation.rule.label.groovy" GridPane.columnIndex="1" GridPane.rowIndex="10" />
<CheckBox fx:id="notEmptyRuleCheckBox" mnemonicParsing="false" GridPane.columnIndex="2" GridPane.rowIndex="1" />
<CheckBox fx:id="integerRuleCheckBox" mnemonicParsing="false" GridPane.columnIndex="2" GridPane.rowIndex="2" />
<CheckBox fx:id="doublerRuleCheckBox" mnemonicParsing="false" GridPane.columnIndex="2" GridPane.rowIndex="3" />
<CheckBox fx:id="alphanumericRuleCheckBox" mnemonicParsing="false" GridPane.columnIndex="2" GridPane.rowIndex="4" />
<Spinner fx:id="minLengthSpinner" GridPane.columnIndex="2" GridPane.rowIndex="5" />
<Spinner fx:id="maxLengthSpinner" GridPane.columnIndex="2" GridPane.rowIndex="6" />
<TextField fx:id="dateformatRuleTextField" GridPane.columnIndex="2" GridPane.rowIndex="7" />
<TextField fx:id="regexpRuleTextField" GridPane.columnIndex="2" GridPane.rowIndex="8" />
<TextField fx:id="valueOfRuleTextField" GridPane.columnIndex="2" GridPane.rowIndex="9" />
<CodeArea fx:id="groovyRuleTextArea" prefHeight="300.0" prefWidth="200.0" GridPane.columnIndex="2" GridPane.rowIndex="10" GridPane.rowSpan="2" />
<Label text="%validation.rule.label.regexp" GridPane.columnIndex="1" GridPane.rowIndex="9" />
<Label text="%validation.rule.label.value_of" GridPane.columnIndex="1" GridPane.rowIndex="10" />
<Label text="%validation.rule.label.groovy" GridPane.columnIndex="1" GridPane.rowIndex="11" />
<Label text="%validation.rule.label.unique" GridPane.columnIndex="1" GridPane.rowIndex="5" />
<CheckBox fx:id="enableNotEmptyRule" mnemonicParsing="false" GridPane.rowIndex="1" />
<CheckBox fx:id="notEmptyRuleCheckBox" mnemonicParsing="false" GridPane.columnIndex="2" GridPane.rowIndex="1" />
<CheckBox fx:id="enableIntegerRule" mnemonicParsing="false" GridPane.rowIndex="2" />
<CheckBox fx:id="integerRuleCheckBox" mnemonicParsing="false" GridPane.columnIndex="2" GridPane.rowIndex="2" />
<CheckBox fx:id="enableDoubleRule" mnemonicParsing="false" GridPane.rowIndex="3" />
<CheckBox fx:id="doublerRuleCheckBox" mnemonicParsing="false" GridPane.columnIndex="2" GridPane.rowIndex="3" />
<CheckBox fx:id="enableAlphanumericRule" mnemonicParsing="false" GridPane.rowIndex="4" />
<CheckBox fx:id="enableMinLengthRule" mnemonicParsing="false" GridPane.rowIndex="5" />
<CheckBox fx:id="enableMaxLengthRule" mnemonicParsing="false" GridPane.rowIndex="6" />
<CheckBox fx:id="enableDateRule" mnemonicParsing="false" GridPane.rowIndex="7" />
<CheckBox fx:id="enableRegexpRule" mnemonicParsing="false" GridPane.rowIndex="8" />
<CheckBox fx:id="enableValueOfRule" mnemonicParsing="false" GridPane.rowIndex="9" />
<CheckBox fx:id="enableGroovyRule" mnemonicParsing="false" GridPane.rowIndex="10" />
<CheckBox fx:id="alphanumericRuleCheckBox" mnemonicParsing="false" GridPane.columnIndex="2" GridPane.rowIndex="4" />
<CheckBox fx:id="enableUniqueRule" mnemonicParsing="false" GridPane.rowIndex="5" />
<CheckBox fx:id="uniqueRuleCheckBox" mnemonicParsing="false" GridPane.columnIndex="2" GridPane.rowIndex="5" />
<CheckBox fx:id="enableMinLengthRule" mnemonicParsing="false" GridPane.rowIndex="6" />
<Spinner fx:id="minLengthSpinner" GridPane.columnIndex="2" GridPane.rowIndex="6" />
<CheckBox fx:id="enableMaxLengthRule" mnemonicParsing="false" GridPane.rowIndex="7" />
<Spinner fx:id="maxLengthSpinner" GridPane.columnIndex="2" GridPane.rowIndex="7" />
<CheckBox fx:id="enableDateRule" mnemonicParsing="false" GridPane.rowIndex="8" />
<TextField fx:id="dateformatRuleTextField" GridPane.columnIndex="2" GridPane.rowIndex="8" />
<CheckBox fx:id="enableRegexpRule" mnemonicParsing="false" GridPane.rowIndex="9" />
<TextField fx:id="regexpRuleTextField" GridPane.columnIndex="2" GridPane.rowIndex="9" />
<CheckBox fx:id="enableValueOfRule" mnemonicParsing="false" GridPane.rowIndex="10" />
<TextField fx:id="valueOfRuleTextField" GridPane.columnIndex="2" GridPane.rowIndex="10" />
<CheckBox fx:id="enableGroovyRule" mnemonicParsing="false" GridPane.rowIndex="11" />
<CodeArea fx:id="groovyRuleTextArea" prefHeight="300.0" prefWidth="200.0" GridPane.columnIndex="2" GridPane.rowIndex="11" GridPane.rowSpan="2" />
<Label style="-fx-font-weight: bold;" text="%validation.rules.active" />
<Label style="-fx-font-weight: bold;" text="%validation.rules.name" GridPane.columnIndex="1" />
<Label style="-fx-font-weight: bold;" text="%validation.rules.value" GridPane.columnIndex="2" />
</children>
<padding>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />

View File

@@ -26,13 +26,10 @@
package ninja.javafx.smartcsv.fx.table.model;
import ninja.javafx.smartcsv.validation.ValidationConfiguration;
import ninja.javafx.smartcsv.validation.Validator;
import org.junit.Test;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import static org.junit.Assert.assertThat;
/**
* unit test for the csv model

View File

@@ -1,13 +1,10 @@
package ninja.javafx.smartcsv.fx.table.model;
import ninja.javafx.smartcsv.validation.Validator;
import org.hamcrest.Matchers;
import org.junit.Test;
import static org.hamcrest.Matchers.hasKey;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.*;
import static org.mockito.Mockito.mock;
import static org.junit.Assert.assertThat;
/**
* unit test for row class

View File

@@ -1,60 +0,0 @@
package ninja.javafx.smartcsv.fx.table.model;
import ninja.javafx.smartcsv.validation.Validator;
import org.junit.Before;
import org.junit.Test;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
/**
* unit test for the value class
*/
public class CSVValueTest {
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// constants
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static final String COLUMN = "COLUMN";
static final String VALUE = "VALUE";
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// mocks
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Validator validator = mock(Validator.class);
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// subject under test
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CSVValue sut;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// init
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@Before
public void initialize() {
sut = new CSVValue();
sut.setValidator(validator);
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// tests
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@Test
public void set_value_calls_validation() {
//setup
sut.setColumn(COLUMN);
// execution
sut.setValue(VALUE);
// assertion
verify(validator).isValid(eq(COLUMN), eq(VALUE), anyInt());
}
}

View File

@@ -70,8 +70,10 @@ public class ValidatorTest {
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@Test
public void validation() {
System.out.println(column + " " + value + " " + expectedResult + " " + expectedError);
// execution
ValidationError result = sut.isValid(column, value, 0);
ValidationError result = sut.isValid(0, column, value);
// assertion
assertThat(result == null, is(expectedResult));
@@ -112,7 +114,7 @@ public class ValidatorTest {
}
public static String json(String column, String rule, Object value) {
String json = "{\"columns\":{\"" + column + "\":{\"" + rule + "\":";
String json = "{\"headers\": { \"list\": [\""+column+"\"]},\"columns\":{\"" + column + "\":{\"" + rule + "\":";
if (value instanceof String) {
json += "\""+ value + "\"";
} else if (value instanceof List) {