diff --git a/build.gradle b/build.gradle index 2df93a1..acb875b 100644 --- a/build.gradle +++ b/build.gradle @@ -21,8 +21,8 @@ dependencies { compile group: 'org.codehaus.groovy', name: 'groovy-all', version: '2.4.5' compile group: 'org.springframework', name:'spring-context', version: '4.2.4.RELEASE' compile group: 'net.sf.supercsv', name: 'super-csv', version: '2.4.0' - compile group: 'com.typesafe', name: 'config', version: '1.3.0' compile group: 'commons-validator', name: 'commons-validator', version: '1.5.0' compile group: 'de.jensd', name: 'fontawesomefx', version: '8.8' compile group: 'org.controlsfx', name: 'controlsfx', version: '8.40.10' + compile group: 'com.google.code.gson', name: 'gson', version: '2.5' } diff --git a/src/main/java/ninja/javafx/smartcsv/fx/SmartCSVController.java b/src/main/java/ninja/javafx/smartcsv/fx/SmartCSVController.java index a11d6ce..7ccd1d2 100644 --- a/src/main/java/ninja/javafx/smartcsv/fx/SmartCSVController.java +++ b/src/main/java/ninja/javafx/smartcsv/fx/SmartCSVController.java @@ -30,6 +30,9 @@ import javafx.beans.property.BooleanProperty; import javafx.beans.property.ObjectProperty; import javafx.beans.property.SimpleBooleanProperty; import javafx.beans.property.SimpleObjectProperty; +import javafx.collections.ListChangeListener; +import javafx.collections.WeakListChangeListener; +import javafx.concurrent.WorkerStateEvent; import javafx.event.ActionEvent; import javafx.event.EventHandler; import javafx.fxml.FXML; @@ -52,10 +55,12 @@ import ninja.javafx.smartcsv.fx.table.model.CSVRow; import ninja.javafx.smartcsv.fx.table.model.CSVValue; import ninja.javafx.smartcsv.fx.util.LoadFileService; import ninja.javafx.smartcsv.fx.util.SaveFileService; +import ninja.javafx.smartcsv.fx.validation.ValidationEditorController; import ninja.javafx.smartcsv.preferences.PreferencesFileReader; import ninja.javafx.smartcsv.preferences.PreferencesFileWriter; import ninja.javafx.smartcsv.validation.ValidationError; import ninja.javafx.smartcsv.validation.ValidationFileReader; +import ninja.javafx.smartcsv.validation.ValidationFileWriter; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; @@ -68,6 +73,7 @@ import java.util.Optional; import java.util.ResourceBundle; import static java.lang.Math.max; +import static java.text.MessageFormat.format; import static javafx.application.Platform.exit; import static javafx.application.Platform.runLater; import static javafx.beans.binding.Bindings.*; @@ -88,6 +94,10 @@ public class SmartCSVController extends FXMLController { ".SmartCSV.fx" + File.separator + "" + "preferences.json"); + public static final String CSV_FILTER_TEXT = "CSV files (*.csv)"; + public static final String CSV_FILTER_EXTENSION = "*.csv"; + public static final String JSON_FILTER_TEXT = "JSON files (*.json)"; + public static final String JSON_FILTER_EXTENSION = "*.json"; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // injections @@ -108,12 +118,18 @@ public class SmartCSVController extends FXMLController { @Autowired private CSVFileWriter csvFileWriter; + @Autowired + private ValidationFileWriter validationFileWriter; + @Autowired private AboutController aboutController; @Autowired private PreferencesController preferencesController; + @Autowired + private ValidationEditorController validationEditorController; + @Autowired private LoadFileService loadFileService; @@ -141,6 +157,15 @@ public class SmartCSVController extends FXMLController { @FXML private MenuItem saveAsMenuItem; + @FXML + private MenuItem loadConfigMenuItem; + + @FXML + private MenuItem saveConfigMenuItem; + + @FXML + private MenuItem saveAsConfigMenuItem; + @FXML private MenuItem deleteRowMenuItem; @@ -153,14 +178,21 @@ public class SmartCSVController extends FXMLController { @FXML private Button saveAsButton; + @FXML + private Button loadConfigButton; + + @FXML + private Button saveConfigButton; + + @FXML + private Button saveAsConfigButton; + @FXML private Button deleteRowButton; @FXML private Button addRowButton; - private ErrorSideBar errorSideBar; - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // members //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -169,11 +201,14 @@ public class SmartCSVController extends FXMLController { private CSVModel model; private TableView tableView; + private ErrorSideBar errorSideBar; private BooleanProperty fileChanged = new SimpleBooleanProperty(true); private ResourceBundle resourceBundle; private ObjectProperty currentCsvFile = new SimpleObjectProperty<>(); private ObjectProperty currentConfigFile= new SimpleObjectProperty<>(); + private ListChangeListener errorListListener = c -> tableView.refresh(); + private WeakListChangeListener weakErrorListListener = new WeakListChangeListener<>(errorListListener); //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // init @@ -184,22 +219,28 @@ public class SmartCSVController extends FXMLController { this.resourceBundle = resourceBundle; setupTableCellFactory(); + setupErrorSideBar(resourceBundle); - errorSideBar = new ErrorSideBar(resourceBundle); + bindMenuItemsToFileExistence(currentCsvFile, saveMenuItem, saveAsMenuItem, addRowMenuItem, loadConfigMenuItem); + bindButtonsToFileExistence(currentCsvFile, saveButton, saveAsButton, addRowButton, loadConfigButton); - errorSideBar.selectedValidationErrorProperty().addListener((observable, oldValue, newValue) -> { - scrollToError(newValue); - }); - applicationPane.setRight(errorSideBar); + bindMenuItemsToFileExistence(currentConfigFile, saveConfigMenuItem, saveAsConfigMenuItem); + bindButtonsToFileExistence(currentConfigFile, saveAsConfigButton, saveConfigButton); - bindMenuItemsToCsvFileExtistence(saveMenuItem, saveAsMenuItem, addRowMenuItem); - bindButtonsToCsvFileExistence(saveButton, saveAsButton, addRowButton); bindCsvFileName(); bindConfigFileName(); loadCsvPreferencesFromFile(); } + private void setupErrorSideBar(ResourceBundle resourceBundle) { + errorSideBar = new ErrorSideBar(resourceBundle); + errorSideBar.selectedValidationErrorProperty().addListener((observable, oldValue, newValue) -> { + scrollToError(newValue); + }); + applicationPane.setRight(errorSideBar); + } + private void setupTableCellFactory() { cellFactory = new ValidationCellFactory(resourceBundle); } @@ -225,8 +266,8 @@ public class SmartCSVController extends FXMLController { currentCsvFile.setValue( loadFile( csvLoader, - "CSV files (*.csv)", - "*.csv", + CSV_FILTER_TEXT, + CSV_FILTER_EXTENSION, "Open CSV", currentCsvFile.getValue())); } @@ -236,8 +277,8 @@ public class SmartCSVController extends FXMLController { currentConfigFile.setValue( loadFile( validationLoader, - "JSON files (*.json)", - "*.json", + JSON_FILTER_TEXT, + JSON_FILTER_EXTENSION, "Open Validation Configuration", currentConfigFile.getValue())); } @@ -254,11 +295,28 @@ public class SmartCSVController extends FXMLController { currentCsvFile.setValue( saveFile( csvFileWriter, - "CSV files (*.csv)", - "*.csv", + CSV_FILTER_TEXT, + CSV_FILTER_EXTENSION, currentCsvFile.getValue())); } + @FXML + public void saveConfig(ActionEvent actionEvent) { + validationFileWriter.setValidationConfiguration(validationLoader.getValidationConfiguration()); + useSaveFileService(validationFileWriter, currentConfigFile.getValue()); + } + + @FXML + public void saveAsConfig(ActionEvent actionEvent) { + validationFileWriter.setValidationConfiguration(validationLoader.getValidationConfiguration()); + currentConfigFile.setValue( + saveFile( + validationFileWriter, + JSON_FILTER_TEXT, + JSON_FILTER_EXTENSION, + currentConfigFile.getValue())); + } + @FXML public void close(ActionEvent actionEvent) { if (canExit()) { @@ -333,6 +391,25 @@ public class SmartCSVController extends FXMLController { return canExit; } + public void showValidationEditor(String column) { + validationEditorController.setSelectedColumn(column); + + Alert alert = new Alert(Alert.AlertType.CONFIRMATION); + alert.setGraphic(null); + alert.setTitle(resourceBundle.getString("dialog.validation.rules.title")); + alert.setHeaderText(format(resourceBundle.getString("dialog.validation.rules.header"), column)); + alert.getDialogPane().setContent(validationEditorController.getView()); + Optional result = alert.showAndWait(); + + if (result.get() == ButtonType.OK){ + runLater(() -> { + validationEditorController.updateConfiguration(); + fileChanged.setValue(true); + model.revalidate(); + }); + } + } + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // private methods //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -344,15 +421,15 @@ public class SmartCSVController extends FXMLController { tableView.getSelectionModel().select(lastRow); } - private void bindMenuItemsToCsvFileExtistence(MenuItem... items) { + private void bindMenuItemsToFileExistence(ObjectProperty file, MenuItem... items) { for (MenuItem item: items) { - item.disableProperty().bind(isNull(currentCsvFile)); + item.disableProperty().bind(isNull(file)); } } - private void bindButtonsToCsvFileExistence(Button... items) { + private void bindButtonsToFileExistence(ObjectProperty file, Button... items) { for (Button item: items) { - item.disableProperty().bind(isNull(currentCsvFile)); + item.disableProperty().bind(isNull(file)); } } @@ -378,9 +455,9 @@ public class SmartCSVController extends FXMLController { private void loadCsvPreferencesFromFile() { if (PREFERENCES_FILE.exists()) { - useLoadFileService(preferencesLoader, PREFERENCES_FILE); + useLoadFileService(preferencesLoader, PREFERENCES_FILE, + event -> setCsvPreference(preferencesLoader.getCSVpreference())); } - setCsvPreference(preferencesLoader.getCSVpreference()); } private void saveCsvPreferences(CsvPreference csvPreference) { @@ -431,7 +508,10 @@ public class SmartCSVController extends FXMLController { //Show open file dialog File file = fileChooser.showOpenDialog(applicationPane.getScene().getWindow()); if (file != null) { - useLoadFileService(fileReader, file); + useLoadFileService(fileReader, file, event -> runLater(() -> { + resetContent(); + fileChanged.setValue(false); + })); return file; } else { return initChildFile; @@ -462,14 +542,11 @@ public class SmartCSVController extends FXMLController { return file; } - private void useLoadFileService(FileReader fileReader, File file) { + private void useLoadFileService(FileReader fileReader, File file, EventHandler value) { loadFileService.setFile(file); loadFileService.setFileReader(fileReader); loadFileService.restart(); - loadFileService.setOnSucceeded(event -> runLater(() -> { - resetContent(); - fileChanged.setValue(false); - })); + loadFileService.setOnSucceeded(value); } private void useSaveFileService(FileWriter writer, File file) { @@ -488,7 +565,9 @@ public class SmartCSVController extends FXMLController { private void resetContent() { model = csvLoader.getData(); if (model != null) { - model.setValidator(validationLoader.getValidator()); + model.getValidationError().addListener(weakErrorListListener); + model.setValidationConfiguration(validationLoader.getValidationConfiguration()); + validationEditorController.setValidationConfiguration(validationLoader.getValidationConfiguration()); tableView = new TableView<>(); bindMenuItemsToTableSelection(deleteRowMenuItem); @@ -520,6 +599,11 @@ public class SmartCSVController extends FXMLController { column.setCellValueFactory(new ObservableMapValueFactory(header)); column.setCellFactory(cellFactory); column.setEditable(true); + column.setSortable(false); + + ContextMenu contextMenu = contextMenuForColumn(header); + column.setContextMenu(contextMenu); + column.setOnEditCommit(new EventHandler>() { @Override public void handle(TableColumn.CellEditEvent event) { @@ -535,6 +619,15 @@ public class SmartCSVController extends FXMLController { tableView.getColumns().add(column); } + private ContextMenu contextMenuForColumn(String header) { + ContextMenu contextMenu = new ContextMenu(); + MenuItem editColumnRulesMenuItem = new MenuItem(resourceBundle.getString("context.menu.edit.column.rules")); + bindMenuItemsToFileExistence(currentConfigFile, editColumnRulesMenuItem); + editColumnRulesMenuItem.setOnAction(e -> showValidationEditor(header)); + contextMenu.getItems().addAll(editColumnRulesMenuItem); + return contextMenu; + } + private void scrollToError(ValidationError entry) { if (entry != null) { if (entry.getLineNumber() != null) { diff --git a/src/main/java/ninja/javafx/smartcsv/fx/preferences/PreferencesController.java b/src/main/java/ninja/javafx/smartcsv/fx/preferences/PreferencesController.java index 01ad86b..d5f6304 100644 --- a/src/main/java/ninja/javafx/smartcsv/fx/preferences/PreferencesController.java +++ b/src/main/java/ninja/javafx/smartcsv/fx/preferences/PreferencesController.java @@ -26,12 +26,8 @@ package ninja.javafx.smartcsv.fx.preferences; -import javafx.beans.InvalidationListener; -import javafx.beans.Observable; import javafx.beans.property.BooleanProperty; import javafx.beans.property.SimpleBooleanProperty; -import javafx.beans.value.ChangeListener; -import javafx.beans.value.ObservableValue; import javafx.fxml.FXML; import javafx.scene.control.CheckBox; import javafx.scene.control.ComboBox; diff --git a/src/main/java/ninja/javafx/smartcsv/fx/table/model/CSVModel.java b/src/main/java/ninja/javafx/smartcsv/fx/table/model/CSVModel.java index ba0d489..079609f 100644 --- a/src/main/java/ninja/javafx/smartcsv/fx/table/model/CSVModel.java +++ b/src/main/java/ninja/javafx/smartcsv/fx/table/model/CSVModel.java @@ -28,6 +28,7 @@ package ninja.javafx.smartcsv.fx.table.model; import javafx.collections.FXCollections; import javafx.collections.ObservableList; +import ninja.javafx.smartcsv.validation.ValidationConfiguration; import ninja.javafx.smartcsv.validation.ValidationError; import ninja.javafx.smartcsv.validation.Validator; @@ -43,11 +44,11 @@ public class CSVModel { private ObservableList validationError = FXCollections.observableArrayList(); /** - * sets the validator for the data revalidates - * @param validator the validator for this data + * sets the validator configuration for the data revalidates + * @param validationConfiguration the validator configuration for this data */ - public void setValidator(Validator validator) { - this.validator = validator; + public void setValidationConfiguration(ValidationConfiguration validationConfiguration) { + this.validator = new Validator(validationConfiguration); revalidate(); } diff --git a/src/main/java/ninja/javafx/smartcsv/fx/validation/ValidationEditorController.java b/src/main/java/ninja/javafx/smartcsv/fx/validation/ValidationEditorController.java new file mode 100644 index 0000000..9cbdbc7 --- /dev/null +++ b/src/main/java/ninja/javafx/smartcsv/fx/validation/ValidationEditorController.java @@ -0,0 +1,348 @@ +/* + The MIT License (MIT) + ----------------------------------------------------------------------------- + + Copyright (c) 2015 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.fx.validation; + +import javafx.beans.property.SimpleStringProperty; +import javafx.beans.property.StringProperty; +import javafx.fxml.FXML; +import javafx.scene.control.*; +import ninja.javafx.smartcsv.fx.FXMLController; +import ninja.javafx.smartcsv.validation.ValidationConfiguration; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +import java.net.URL; +import java.util.List; +import java.util.ResourceBundle; + +import static java.util.Arrays.asList; +import static java.util.stream.Collectors.joining; + +/** + * controller for editing column validations + */ +@Component +public class ValidationEditorController extends FXMLController { + + private StringProperty selectedColumn = new SimpleStringProperty(); + private ValidationConfiguration validationConfiguration; + + @FXML + private CheckBox notEmptyRuleCheckBox; + + @FXML + private CheckBox integerRuleCheckBox; + + @FXML + private CheckBox doublerRuleCheckBox; + + @FXML + private CheckBox alphanumericRuleCheckBox; + + @FXML + private Spinner minLengthSpinner; + + @FXML + private Spinner maxLengthSpinner; + + @FXML + private TextField dateformatRuleTextField; + + @FXML + private TextField regexpRuleTextField; + + @FXML + private TextField valueOfRuleTextField; + + @FXML + private TextArea groovyRuleTextArea; + + @FXML + private CheckBox enableNotEmptyRule; + + @FXML + private CheckBox enableIntegerRule; + + @FXML + private CheckBox enableDoubleRule; + + @FXML + private CheckBox enableAlphanumericRule; + + @FXML + private CheckBox enableMinLengthRule; + + @FXML + private CheckBox enableMaxLengthRule; + + @FXML + private CheckBox enableDateRule; + + @FXML + private CheckBox enableRegexpRule; + + @FXML + private CheckBox enableValueOfRule; + + @FXML + private CheckBox enableGroovyRule; + + + @Value("${fxml.smartcvs.validation.editor.view}") + @Override + public void setFxmlFilePath(String filePath) { + this.fxmlFilePath = filePath; + } + + @Override + public void initialize(URL location, ResourceBundle resources) { + + minLengthSpinner.setValueFactory(new SpinnerValueFactory.IntegerSpinnerValueFactory(0, Integer.MAX_VALUE, 0)); + maxLengthSpinner.setValueFactory(new SpinnerValueFactory.IntegerSpinnerValueFactory(0, Integer.MAX_VALUE, 0)); + + initCheckBox(notEmptyRuleCheckBox, enableNotEmptyRule); + initCheckBox(integerRuleCheckBox, enableIntegerRule); + initCheckBox(doublerRuleCheckBox, enableDoubleRule); + initCheckBox(alphanumericRuleCheckBox, enableAlphanumericRule); + initSpinner(minLengthSpinner, enableMinLengthRule); + initSpinner(maxLengthSpinner, enableMaxLengthRule); + initTextInputControl(dateformatRuleTextField, enableDateRule); + initTextInputControl(regexpRuleTextField, enableRegexpRule); + initTextInputControl(valueOfRuleTextField, enableValueOfRule); + initTextInputControl(groovyRuleTextArea, enableGroovyRule); + + selectedColumn.addListener(observable -> { + updateForm(); + }); + } + + public String getSelectedColumn() { + return selectedColumn.get(); + } + + public StringProperty selectedColumnProperty() { + return selectedColumn; + } + + public void setSelectedColumn(String selectedColumn) { + this.selectedColumn.set(selectedColumn); + } + + public void setValidationConfiguration(ValidationConfiguration validationConfiguration) { + this.validationConfiguration = validationConfiguration; + } + + public void updateConfiguration() { + + if (enableIntegerRule.isSelected()) { + validationConfiguration.setIntegerRuleFor(selectedColumn.getValue(), integerRuleCheckBox.isSelected()); + } else { + validationConfiguration.setIntegerRuleFor(selectedColumn.getValue(), null); + } + + if (enableNotEmptyRule.isSelected()) { + validationConfiguration.setNotEmptyRuleFor(selectedColumn.getValue(), notEmptyRuleCheckBox.isSelected()); + } else { + validationConfiguration.setNotEmptyRuleFor(selectedColumn.getValue(), null); + } + + if (enableDoubleRule.isSelected()) { + validationConfiguration.setDoubleRuleFor(selectedColumn.getValue(), doublerRuleCheckBox.isSelected()); + } else { + validationConfiguration.setDoubleRuleFor(selectedColumn.getValue(), null); + } + + if (enableAlphanumericRule.isSelected()) { + validationConfiguration.setAlphanumericRuleFor(selectedColumn.getValue(), alphanumericRuleCheckBox.isSelected()); + } else { + validationConfiguration.setAlphanumericRuleFor(selectedColumn.getValue(), null); + } + + if (enableDateRule.isSelected()) { + validationConfiguration.setDateRuleFor(selectedColumn.getValue(), dateformatRuleTextField.getText()); + } else { + validationConfiguration.setDateRuleFor(selectedColumn.getValue(), null); + } + + if (enableGroovyRule.isSelected()) { + validationConfiguration.setGroovyRuleFor(selectedColumn.getValue(), groovyRuleTextArea.getText()); + } else { + validationConfiguration.setGroovyRuleFor(selectedColumn.getValue(), null); + } + + if (enableMinLengthRule.isSelected()) { + validationConfiguration.setMinLengthRuleFor(selectedColumn.getValue(), minLengthSpinner.getValue()); + } else { + validationConfiguration.setMinLengthRuleFor(selectedColumn.getValue(), null); + } + + if (enableMaxLengthRule.isSelected()) { + validationConfiguration.setMaxLengthRuleFor(selectedColumn.getValue(), maxLengthSpinner.getValue()); + } else { + validationConfiguration.setMaxLengthRuleFor(selectedColumn.getValue(), null); + } + + if (enableRegexpRule.isSelected()) { + validationConfiguration.setRegexpRuleFor(selectedColumn.getValue(), regexpRuleTextField.getText()); + } else { + validationConfiguration.setRegexpRuleFor(selectedColumn.getValue(), null); + } + + if (enableValueOfRule.isSelected()) { + validationConfiguration.setValueOfRuleFor(selectedColumn.getValue(), asList(valueOfRuleTextField.getText().split(", "))); + } else { + validationConfiguration.setValueOfRuleFor(selectedColumn.getValue(), null); + } + } + + private void updateForm() { + + updateCheckBox( + notEmptyRuleCheckBox, + validationConfiguration.getNotEmptyRuleFor(getSelectedColumn()), + enableNotEmptyRule + ); + + updateCheckBox( + integerRuleCheckBox, + validationConfiguration.getIntegerRuleFor(getSelectedColumn()), + enableIntegerRule + ); + + updateCheckBox( + doublerRuleCheckBox, + validationConfiguration.getDoubleRuleFor(getSelectedColumn()), + enableDoubleRule + ); + + updateCheckBox( + alphanumericRuleCheckBox, + validationConfiguration.getAlphanumericRuleFor(getSelectedColumn()), + enableAlphanumericRule + ); + + updateSpinner( + minLengthSpinner, + validationConfiguration.getMinLengthRuleFor(getSelectedColumn()), + enableMinLengthRule + ); + + updateSpinner( + maxLengthSpinner, + validationConfiguration.getMaxLengthRuleFor(getSelectedColumn()), + enableMaxLengthRule + ); + + updateTextInputControl( + dateformatRuleTextField, + validationConfiguration.getDateRuleFor(getSelectedColumn()), + enableDateRule + ); + + updateTextInputControl( + regexpRuleTextField, + validationConfiguration.getRegexpRuleFor(getSelectedColumn()), + enableRegexpRule + ); + + updateTextInputControl( + valueOfRuleTextField, + validationConfiguration.getValueOfRuleFor(getSelectedColumn()), + enableValueOfRule + ); + + updateTextInputControl( + groovyRuleTextArea, + validationConfiguration.getGroovyRuleFor(getSelectedColumn()), + enableGroovyRule + ); + } + + private void updateCheckBox(CheckBox rule, Boolean value, CheckBox ruleEnabled) { + if (value == null) { + ruleEnabled.setSelected(false); + } else { + rule.setSelected(value); + ruleEnabled.setSelected(true); + } + } + + private void updateSpinner(Spinner rule, Integer value, CheckBox ruleEnabled) { + if (value == null) { + ruleEnabled.setSelected(false); + } else { + ruleEnabled.setSelected(true); + rule.getValueFactory().setValue(value); + } + } + + private void updateTextInputControl(TextInputControl rule, String value, CheckBox ruleEnabled) { + if (value == null) { + ruleEnabled.setSelected(false); + } else { + ruleEnabled.setSelected(true); + rule.setText(value); + } + } + + private void updateTextInputControl(TextInputControl rule, List values, CheckBox ruleEnabled) { + if (values == null || values.isEmpty()) { + ruleEnabled.setSelected(false); + } else { + ruleEnabled.setSelected(true); + rule.setText(values.stream().collect(joining(", "))); + } + } + + private void initCheckBox(CheckBox rule, CheckBox ruleEnabled) { + rule.disableProperty().bind(ruleEnabled.selectedProperty().not()); + ruleEnabled.selectedProperty().addListener((observable, oldValue, newValue) -> { + if (!newValue) { + rule.setSelected(false); + } + }); + } + + private void initSpinner(Spinner rule, CheckBox ruleEnabled) { + rule.disableProperty().bind(ruleEnabled.selectedProperty().not()); + ruleEnabled.selectedProperty().addListener((observable, oldValue, newValue) -> { + if (!newValue) { + rule.getValueFactory().setValue(0); + } + }); + } + + private void initTextInputControl(TextInputControl rule, CheckBox ruleEnabled) { + rule.disableProperty().bind(ruleEnabled.selectedProperty().not()); + ruleEnabled.selectedProperty().addListener((observable, oldValue, newValue) -> { + if (!newValue) { + rule.setText(""); + } + }); + } + +} diff --git a/src/main/java/ninja/javafx/smartcsv/preferences/PreferencesFileReader.java b/src/main/java/ninja/javafx/smartcsv/preferences/PreferencesFileReader.java index bae0290..a5b32d6 100644 --- a/src/main/java/ninja/javafx/smartcsv/preferences/PreferencesFileReader.java +++ b/src/main/java/ninja/javafx/smartcsv/preferences/PreferencesFileReader.java @@ -26,8 +26,7 @@ package ninja.javafx.smartcsv.preferences; -import com.typesafe.config.Config; -import com.typesafe.config.ConfigFactory; +import com.google.gson.GsonBuilder; import ninja.javafx.smartcsv.FileReader; import org.springframework.stereotype.Service; import org.supercsv.prefs.CsvPreference; @@ -35,6 +34,8 @@ import org.supercsv.quote.AlwaysQuoteMode; import java.io.File; import java.io.IOException; +import java.util.HashMap; +import java.util.Map; import static ninja.javafx.smartcsv.preferences.QuoteModeHelper.getQuoteMode; @@ -44,7 +45,7 @@ import static ninja.javafx.smartcsv.preferences.QuoteModeHelper.getQuoteMode; @Service public class PreferencesFileReader implements FileReader { - private Config config; + private Map config; private CsvPreference csvPreference; public PreferencesFileReader() { @@ -55,15 +56,15 @@ public class PreferencesFileReader implements FileReader { @Override public void read(File filename) throws IOException { - config = ConfigFactory.parseFile(filename); + config = new GsonBuilder().create().fromJson(new java.io.FileReader(filename), HashMap.class); if (config != null) { - char quoteChar = config.getString("quoteChar").charAt(0); - char delimiterChar = config.getString("delimiterChar").charAt(0); - String endOfLineSymbols = config.getString("endOfLineSymbols"); - boolean surroundingSpacesNeedQuotes = config.getBoolean("surroundingSpacesNeedQuotes"); - boolean ignoreEmptyLines = config.getBoolean("ignoreEmptyLines"); - String quoteMode = config.getString("quoteMode"); + char quoteChar = config.get("quoteChar").toString().charAt(0); + char delimiterChar = config.get("delimiterChar").toString().charAt(0); + String endOfLineSymbols = config.get("endOfLineSymbols").toString(); + boolean surroundingSpacesNeedQuotes = (Boolean)config.get("surroundingSpacesNeedQuotes"); + boolean ignoreEmptyLines = (Boolean)config.get("ignoreEmptyLines"); + String quoteMode = config.get("quoteMode").toString(); csvPreference = new CsvPreference.Builder(quoteChar, delimiterChar, endOfLineSymbols) .useQuoteMode(getQuoteMode(quoteMode)) diff --git a/src/main/java/ninja/javafx/smartcsv/preferences/PreferencesFileWriter.java b/src/main/java/ninja/javafx/smartcsv/preferences/PreferencesFileWriter.java index c295855..53d383f 100644 --- a/src/main/java/ninja/javafx/smartcsv/preferences/PreferencesFileWriter.java +++ b/src/main/java/ninja/javafx/smartcsv/preferences/PreferencesFileWriter.java @@ -26,9 +26,8 @@ package ninja.javafx.smartcsv.preferences; -import com.typesafe.config.Config; -import com.typesafe.config.ConfigFactory; -import com.typesafe.config.ConfigRenderOptions; +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; @@ -60,8 +59,8 @@ public class PreferencesFileWriter implements FileWriter { preferences.put("ignoreEmptyLines", csvPreference.isIgnoreEmptyLines()); preferences.put("quoteMode", QuoteModeHelper.getQuoteModeName(csvPreference.getQuoteMode())); - Config config = ConfigFactory.parseMap(preferences); - Files.write(file.toPath(), config.root().render(ConfigRenderOptions.concise()).getBytes()); + Gson gson = new GsonBuilder().setPrettyPrinting().create(); + Files.write(file.toPath(), gson.toJson(preferences).getBytes()); } } diff --git a/src/main/java/ninja/javafx/smartcsv/validation/HeaderConfiguration.java b/src/main/java/ninja/javafx/smartcsv/validation/HeaderConfiguration.java new file mode 100644 index 0000000..f5d1256 --- /dev/null +++ b/src/main/java/ninja/javafx/smartcsv/validation/HeaderConfiguration.java @@ -0,0 +1,42 @@ +/* + The MIT License (MIT) + ----------------------------------------------------------------------------- + + Copyright (c) 2015 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 com.google.gson.annotations.SerializedName; + +/** + * header configuration for the validation + */ +public class HeaderConfiguration { + + @SerializedName("list") + private String[] names ; + + public String[] getNames() { + return names; + } +} diff --git a/src/main/java/ninja/javafx/smartcsv/validation/ValidationConfiguration.java b/src/main/java/ninja/javafx/smartcsv/validation/ValidationConfiguration.java new file mode 100644 index 0000000..029144d --- /dev/null +++ b/src/main/java/ninja/javafx/smartcsv/validation/ValidationConfiguration.java @@ -0,0 +1,169 @@ +/* + The MIT License (MIT) + ----------------------------------------------------------------------------- + + Copyright (c) 2015 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 com.google.gson.annotations.SerializedName; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static java.lang.Boolean.FALSE; + +/** + * validation configuration + */ +public class ValidationConfiguration { + + @SerializedName("headers") + private HeaderConfiguration headerConfiguration = new HeaderConfiguration(); + + @SerializedName("columns") + private Map> columnConfigurations = new HashMap<>(); + + public String[] headerNames() { + if (noHeader()) return null; + return headerConfiguration.getNames(); + } + + public Boolean getIntegerRuleFor(String column) { + return (Boolean)getValue(column, "integer"); + } + + public Boolean getDoubleRuleFor(String column) { + return (Boolean)getValue(column, "double"); + } + + public Boolean getNotEmptyRuleFor(String column) { + return (Boolean)getValue(column, "not empty"); + } + + public Integer getMinLengthRuleFor(String column) { + return doubleToInteger((Double)getValue(column, "minlength")); + } + + public Integer getMaxLengthRuleFor(String column) { + if (noRulesFor(column)) return null; + return doubleToInteger((Double)getValue(column, "maxlength")); + } + + 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 getValueOfRuleFor(String column) { + if (noRulesFor(column)) return null; + return (List)getValue(column, "value of"); + } + + public String getGroovyRuleFor(String column) { + if (noRulesFor(column)) return null; + return (String)getValue(column, "groovy"); + } + + public void setIntegerRuleFor(String column, Boolean value) { + setValue(column, value, "integer"); + } + + public void setDoubleRuleFor(String column, Boolean value) { + setValue(column, value, "double"); + } + + public void setNotEmptyRuleFor(String column, Boolean value) { + setValue(column, value, "not empty"); + } + + public void setMinLengthRuleFor(String column, Integer value) { + setValue(column, value == null ? null : value.doubleValue(), "minlength"); + } + + public void setMaxLengthRuleFor(String column, Integer value) { + setValue(column, value == null ? null : value.doubleValue(), "maxlength"); + } + + public void setDateRuleFor(String column, String value) { + setValue(column, value, "date"); + } + + public void setAlphanumericRuleFor(String column, Boolean value) { + setValue(column, value, "alphanumeric"); + } + + public void setRegexpRuleFor(String column, String value) { + setValue(column, value, "regexp"); + } + + public void setValueOfRuleFor(String column, List value) { + setValue(column, value, "value of"); + } + + public void setGroovyRuleFor(String column, String value) { + setValue(column, value, "groovy"); + } + + private void setValue(String column, Object value, String key) { + if (!columnConfigurations.containsKey(column)) { + columnConfigurations.put(column, new HashMap<>()); + } + + if (value == null && columnConfigurations.get(column).containsKey(key)) { + columnConfigurations.get(column).remove(key); + } else { + columnConfigurations.get(column).put(key, value); + } + } + + private Object getValue(String column, String key) { + if (noRulesFor(column)) return null; + return columnConfigurations.get(column).get(key); + } + + 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); + } + +} diff --git a/src/main/java/ninja/javafx/smartcsv/validation/ValidationFileReader.java b/src/main/java/ninja/javafx/smartcsv/validation/ValidationFileReader.java index 82a29a9..fdd1acd 100644 --- a/src/main/java/ninja/javafx/smartcsv/validation/ValidationFileReader.java +++ b/src/main/java/ninja/javafx/smartcsv/validation/ValidationFileReader.java @@ -26,8 +26,7 @@ package ninja.javafx.smartcsv.validation; -import com.typesafe.config.Config; -import com.typesafe.config.ConfigFactory; +import com.google.gson.GsonBuilder; import ninja.javafx.smartcsv.FileReader; import org.springframework.stereotype.Service; @@ -40,14 +39,14 @@ import java.io.IOException; @Service public class ValidationFileReader implements FileReader { - private Config config; + private ValidationConfiguration config; @Override public void read(File file) throws IOException { - config = ConfigFactory.parseFile(file); + config = new GsonBuilder().create().fromJson(new java.io.FileReader(file), ValidationConfiguration.class); } - public Validator getValidator() { - return new Validator(config); + public ValidationConfiguration getValidationConfiguration() { + return config; } } diff --git a/src/main/java/ninja/javafx/smartcsv/validation/ValidationFileWriter.java b/src/main/java/ninja/javafx/smartcsv/validation/ValidationFileWriter.java new file mode 100644 index 0000000..7bcdf6d --- /dev/null +++ b/src/main/java/ninja/javafx/smartcsv/validation/ValidationFileWriter.java @@ -0,0 +1,55 @@ +/* + The MIT License (MIT) + ----------------------------------------------------------------------------- + + Copyright (c) 2015 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 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; +import java.nio.file.Files; + +/** + * file writer for the validation configuration + */ +@Service +public class ValidationFileWriter implements FileWriter { + + private ValidationConfiguration validationConfiguration; + + public void setValidationConfiguration(ValidationConfiguration validationConfiguration) { + this.validationConfiguration = validationConfiguration; + } + + @Override + public void write(File file) throws IOException { + Gson gson = new GsonBuilder().setPrettyPrinting().create(); + Files.write(file.toPath(), gson.toJson(validationConfiguration).getBytes()); + } +} diff --git a/src/main/java/ninja/javafx/smartcsv/validation/Validator.java b/src/main/java/ninja/javafx/smartcsv/validation/Validator.java index 1446aaf..bdb466a 100644 --- a/src/main/java/ninja/javafx/smartcsv/validation/Validator.java +++ b/src/main/java/ninja/javafx/smartcsv/validation/Validator.java @@ -26,7 +26,6 @@ package ninja.javafx.smartcsv.validation; -import com.typesafe.config.Config; import groovy.lang.Binding; import groovy.lang.GroovyShell; import groovy.lang.Script; @@ -49,7 +48,7 @@ public class Validator { // member variables //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - private Config validationConfig; + private ValidationConfiguration validationConfig; private GroovyShell shell = new GroovyShell(); private Map scriptCache = new HashMap<>(); @@ -62,7 +61,7 @@ public class Validator { * JSON configuration for this validator * @param validationConfig */ - public Validator(Config validationConfig) { + public Validator(ValidationConfiguration validationConfig) { this.validationConfig = validationConfig; } @@ -80,29 +79,23 @@ public class Validator { public ValidationError isValid(String column, String value, Integer lineNumber) { ValidationError result = null; if (validationConfig != null) { - Config columnSectionConfig = getColumnSectionConfig(); - if (columnSectionConfig != null) { - Config columnConfig = getColumnConfig(columnSectionConfig, column); - if (columnConfig != null) { - ValidationError error = ValidationError.withLineNumber(lineNumber); - checkBlankOrNull(columnConfig, value, error); - if (value != null && !value.isEmpty()) { - checkRegularExpression(columnConfig, value, error); - checkAlphaNumeric(columnConfig, value, error); - checkDate(columnConfig, value, error); - checkMaxLength(columnConfig, value, error); - checkMinLength(columnConfig, value, error); - checkInteger(columnConfig, value, error); - checkGroovy(column, columnConfig, value, error); - checkValueOf(columnConfig, value, error); - checkDouble(columnConfig, value, error); - } + 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); + } - if (!error.isEmpty()) { - result = error; - } - } + if (!error.isEmpty()) { + result = error; } } return result; @@ -113,8 +106,8 @@ public class Validator { // private methods //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - private void checkGroovy(String column, Config columnConfig, String value, ValidationError error) { - String groovyScript = getString(columnConfig, "groovy"); + private void checkGroovy(String column, String value, ValidationError error) { + String groovyScript = validationConfig.getGroovyRuleFor(column); if (groovyScript != null) { Script script = scriptCache.get(column); @@ -149,43 +142,42 @@ public class Validator { return groovyResult.equals(true) || groovyResult.toString().trim().toLowerCase().equals("true"); } - private void checkValueOf(Config columnConfig, String value, ValidationError error) { - List stringList = getStringList(columnConfig, "value of"); - if (stringList != null) { - if (!stringList.contains(value)) { - String commaSeparated = stringList.stream().collect(joining(", ")); + private void checkValueOf(String column, String value, ValidationError error) { + List 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(Config columnConfig, String value, ValidationError error) { - if (getBoolean(columnConfig, "not empty")) { + 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(Config columnConfig, String value, ValidationError error) { - if (getBoolean(columnConfig, "integer")) { + 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(Config columnConfig, String value, ValidationError error) { - if (getBoolean(columnConfig, "double")) { + 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(Config columnConfig, String value, ValidationError error) { - Integer minLength = getInteger(columnConfig, "minlength"); + 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()); @@ -193,8 +185,8 @@ public class Validator { } } - private void checkMaxLength(Config columnConfig, String value, ValidationError error) { - Integer maxLength = getInteger(columnConfig, "maxlength"); + 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()); @@ -202,8 +194,8 @@ public class Validator { } } - private void checkDate(Config columnConfig, String value, ValidationError error) { - String dateformat = getString(columnConfig, "date"); + 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); @@ -211,16 +203,16 @@ public class Validator { } } - private void checkAlphaNumeric(Config columnConfig, String value, ValidationError error) { - if (getBoolean(columnConfig, "alphanumeric")) { + 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(Config columnConfig, String value, ValidationError error) { - String regexp = getString(columnConfig, "regexp"); + 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); @@ -228,60 +220,31 @@ public class Validator { } } - private Config getColumnSectionConfig() { - return validationConfig.hasPath("columns") ? validationConfig.getConfig("columns") : null; - } - - private Config getColumnConfig(Config columnSectionConfig, String column) { - return columnSectionConfig.hasPath(column) ? columnSectionConfig.getConfig(column) : null; - } - - - private String getString(Config columnConfig, String path) { - return columnConfig.hasPath(path) ? columnConfig.getString(path) : null; - } - - private Integer getInteger(Config columnConfig, String path) { - return columnConfig.hasPath(path) ? columnConfig.getInt(path) : null; - } - - private boolean getBoolean(Config columnConfig, String path) { - return columnConfig.hasPath(path) && columnConfig.getBoolean(path); - } - - private List getStringList(Config columnConfig, String path) { - return columnConfig.hasPath(path) ? columnConfig.getStringList(path) : null; - } - public ValidationError isHeaderValid(String[] headerNames) { ValidationError result = null; if (validationConfig != null) { - if (validationConfig.hasPath("headers")) { - Config headerSectionConfig = validationConfig.getConfig("headers"); - List headerConfig = getStringList(headerSectionConfig, "list"); - if (headerConfig != null) { - if (headerNames.length != headerConfig.size()) { - result = ValidationError.withoutLineNumber().add("validation.message.header.length", - Integer.toString(headerNames.length), - Integer.toString(headerConfig.size())); - return result; - } + String[] headerNamesConfig = validationConfig.headerNames(); + if (headerNamesConfig != null) { + if (headerNames.length != headerNamesConfig.length) { + result = ValidationError.withoutLineNumber().add("validation.message.header.length", + Integer.toString(headerNames.length), + Integer.toString(headerNamesConfig.length)); + return result; + } - ValidationError error = ValidationError.withoutLineNumber(); + ValidationError error = ValidationError.withoutLineNumber(); - for(int i=0; i