Initial commit

This commit is contained in:
Andreas Billmann
2015-11-28 23:06:14 +01:00
commit 07084bd18e
31 changed files with 2342 additions and 0 deletions

27
build.gradle Normal file
View File

@@ -0,0 +1,27 @@
group 'ninja.javafx'
version '1.0-SNAPSHOT'
apply plugin: 'java'
apply plugin: 'groovy'
apply plugin:'application'
apply plugin: 'idea'
sourceCompatibility = 1.8
mainClassName = 'ninja.javafx.smartcsv.fx.SmartCSV'
repositories {
mavenCentral()
jcenter()
}
dependencies {
testCompile group: 'junit', name: 'junit', version: '4.12'
testCompile group: 'org.testfx', name: 'testfx-core', version: '4.0.+'
testCompile group: 'org.testfx', name: 'testfx-junit', version: '4.0.+'
testCompile group: 'org.mockito', name: 'mockito-all', version: '1.10.19'
compile group: 'org.codehaus.groovy', name: 'groovy-all', version: '2.4.5'
compile group: 'org.springframework', name:'spring-context', version: '4.2.3.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.4.1'
}

BIN
gradle/wrapper/gradle-wrapper.jar vendored Normal file

Binary file not shown.

View File

@@ -0,0 +1,6 @@
#Thu Oct 01 19:02:27 CEST 2015
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-2.2-all.zip

164
gradlew vendored Normal file
View File

@@ -0,0 +1,164 @@
#!/usr/bin/env bash
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn ( ) {
echo "$*"
}
die ( ) {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
esac
# For Cygwin, ensure paths are in UNIX format before anything is touched.
if $cygwin ; then
[ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
fi
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >&-
APP_HOME="`pwd -P`"
cd "$SAVED" >&-
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
function splitJvmOpts() {
JVM_OPTS=("$@")
}
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"

90
gradlew.bat vendored Normal file
View File

@@ -0,0 +1,90 @@
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windowz variants
if not "%OS%" == "Windows_NT" goto win9xME_args
if "%@eval[2+2]" == "4" goto 4NT_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
goto execute
:4NT_args
@rem Get arguments from the 4NT Shell from JP Software
set CMD_LINE_ARGS=%$
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

28
license Normal file
View File

@@ -0,0 +1,28 @@
The MIT License (MIT)
------------------------------------------------------------------------------------------------------------------------
Copyright (c) 2015 Andreas Billmann <andreas.billmann@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.

2
settings.gradle Normal file
View File

@@ -0,0 +1,2 @@
rootProject.name = 'SmartCSV.ninja.javafx.smartcsv.fx'

View File

@@ -0,0 +1,37 @@
/*
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;
import java.io.File;
import java.io.IOException;
/**
* Created by Andreas on 19.11.2015.
*/
public interface FileReader {
void read(File filename) throws IOException;
}

View File

@@ -0,0 +1,80 @@
/*
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.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;
import org.supercsv.prefs.CsvPreference;
import java.io.File;
import java.io.IOException;
import java.util.Map;
/**
* Created by Andreas on 18.11.2015.
*/
@Service
public class CSVFileReader implements FileReader {
private CSVModel model;
@Override
public void read(File file) throws IOException {
ICsvMapReader mapReader = null;
try {
mapReader = new CsvMapReader(new java.io.FileReader(file.getAbsoluteFile()), CsvPreference.EXCEL_NORTH_EUROPE_PREFERENCE);
model = new CSVModel(file.getAbsolutePath());
// the header columns are used as the keys to the Map
String[] header = mapReader.getHeader(true);
model.setHeader(header);
Map<String, String> customerMap;
while ((customerMap = mapReader.read(header)) != null) {
CSVRow row = model.addRow();
for (String column : header) {
row.addValue(column, customerMap.get(column));
}
}
} finally {
if (mapReader != null) {
mapReader.close();
}
}
}
public CSVModel getData() {
return model;
}
}

View File

@@ -0,0 +1,80 @@
/*
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.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;
import org.supercsv.prefs.CsvPreference;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Map;
import static java.util.stream.Collectors.toMap;
/**
* filewriter for the csv
*/
@Service
public class CSVFileWriter {
public void saveFile(CSVModel model) throws IOException {
ICsvMapWriter mapWriter = null;
try {
mapWriter = new CsvMapWriter(new FileWriter(model.getFilepath()), CsvPreference.EXCEL_NORTH_EUROPE_PREFERENCE);
mapWriter.writeHeader(model.getHeader());
for(CSVRow row: model.getRows()) {
Map<String, String> columns = convertMapFromModel(row);
mapWriter.write(columns, model.getHeader());
}
}
finally {
if( mapWriter != null ) {
mapWriter.close();
}
}
}
/**
* transforms the column map from CSVValue to a simple Map<String,String>
* @param row the row to convert
* @return a simple map for the supercvs writer
*/
private Map<String, String> convertMapFromModel(CSVRow row) {
return row.getColumns().entrySet().stream()
.collect(
toMap(
Map.Entry::getKey,
e -> e.getValue().getValue().getValue() != null ? e.getValue().getValue().getValue() : ""
)
);
}
}

View File

@@ -0,0 +1,72 @@
/*
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.fx;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Node;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import java.io.IOException;
import java.io.InputStream;
import java.util.ResourceBundle;
public abstract class FXMLController implements InitializingBean, Initializable {
protected Node view;
protected String fxmlFilePath;
protected String resourcePath;
public abstract void setFxmlFilePath(String filePath);
@Value("${resource.main}")
public void setResourceBundle(String resourcePath) {
this.resourcePath = resourcePath;
}
@Override
public void afterPropertiesSet() throws Exception {
loadFXML();
}
protected final void loadFXML() throws IOException {
try (InputStream fxmlStream = getClass().getResourceAsStream(fxmlFilePath)) {
FXMLLoader loader = new FXMLLoader();
loader.setResources(ResourceBundle.getBundle(this.resourcePath));
loader.setController(this);
this.view = (loader.load(fxmlStream));
} catch (Throwable t) {
t.printStackTrace();
}
}
public Node getView() {
return view;
}
}

View File

@@ -0,0 +1,84 @@
/*
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.fx;
import javafx.application.Application;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
import org.springframework.context.annotation.*;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
@Configuration
@ComponentScan("ninja.javafx")
@PropertySource(value = "classpath:/ninja/javafx/smartcsv/fx/application.properties")
public class SmartCSV extends Application {
private AnnotationConfigApplicationContext appContext;
@Override
public void start(Stage primaryStage) throws Exception {
appContext = new AnnotationConfigApplicationContext(SmartCSV.class);
String name = appContext.getEnvironment().getProperty("application.name");
String version = appContext.getEnvironment().getProperty("application.version");
try {
showUI(primaryStage, name, version);
} catch (Exception e) {
e.printStackTrace();
}
}
@Bean
public static PropertySourcesPlaceholderConfigurer placeholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
@Override
public void stop() throws Exception {
if (appContext != null) {
appContext.close();
}
super.stop();
}
public static void main(String[] args) {
launch(args);
}
private void showUI(Stage primaryStage, String name, String version) {
SmartCSVController smartCVSController = appContext.getBean(SmartCSVController.class);
Scene scene = new Scene((Parent) smartCVSController.getView());
primaryStage.setScene(scene);
primaryStage.setTitle(String.format("%s %s", name, version));
primaryStage.show();
}
}

View File

@@ -0,0 +1,290 @@
/*
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.fx;
import javafx.application.Platform;
import javafx.concurrent.Service;
import javafx.concurrent.Task;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.scene.control.Label;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.layout.BorderPane;
import javafx.stage.FileChooser;
import ninja.javafx.smartcsv.FileReader;
import ninja.javafx.smartcsv.csv.CSVFileReader;
import ninja.javafx.smartcsv.csv.CSVFileWriter;
import ninja.javafx.smartcsv.fx.table.ObservableMapValueFactory;
import ninja.javafx.smartcsv.fx.table.ValidationCellFactory;
import ninja.javafx.smartcsv.fx.table.model.CSVModel;
import ninja.javafx.smartcsv.fx.table.model.CSVValue;
import ninja.javafx.smartcsv.fx.table.model.CSVRow;
import ninja.javafx.smartcsv.validation.ValidationFileReader;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
import static javafx.application.Platform.runLater;
/**
* main controller of the application
*/
@Component
public class SmartCSVController extends FXMLController {
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// injections
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@Autowired
private CSVFileReader csvLoader;
@Autowired
private ValidationFileReader validationLoader;
@Autowired
private CSVFileWriter csvFileWriter;
@FXML
private BorderPane applicationPane;
@FXML
private Label stateline;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// injections
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
private ValidationCellFactory cellFactory = new ValidationCellFactory();
private final LoadCSVService loadCSVService = new LoadCSVService();
private final SaveCSVService saveCSVService = new SaveCSVService();
private CSVModel model;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// init
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@Override
public void initialize(URL location, ResourceBundle resources) {
stateline.setVisible(false);
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// setter
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@Value("${fxml.smartcvs.view}")
@Override
public void setFxmlFilePath(String filePath) {
this.fxmlFilePath = filePath;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// actions
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@FXML
public void openCsv(ActionEvent actionEvent) {
loadFile(csvLoader, "CSV files (*.csv)", "*.csv", "Open CSV");
}
@FXML
public void openConfig(ActionEvent actionEvent) {
loadFile(validationLoader, "JSON files (*.json)", "*.json", "Open Validation Configuration");
}
@FXML
public void saveCsv(ActionEvent actionEvent) {
saveCSVService.restart();
}
@FXML
public void saveAsCsv(ActionEvent actionEvent) {
saveFile(csvFileWriter, "CSV files (*.csv)", "*.csv");
}
@FXML
public void close(ActionEvent actionEvent) {
Platform.exit();
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// private methods
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
private void loadFile(FileReader fileReader, String filterText, String filter, String title) {
final FileChooser fileChooser = new FileChooser();
//Set extension filter
final FileChooser.ExtensionFilter extFilter = new FileChooser.ExtensionFilter(filterText, filter);
fileChooser.getExtensionFilters().add(extFilter);
fileChooser.setTitle(title);
//Show open file dialog
final File file = fileChooser.showOpenDialog(applicationPane.getScene().getWindow());
if (file != null) {
loadCSVService.setFile(file);
loadCSVService.setFileReader(fileReader);
loadCSVService.restart();
}
}
private void saveFile(CSVFileWriter writer, String filterText, String filter) {
if (model != null) {
final FileChooser fileChooser = new FileChooser();
//Set extension filter
final FileChooser.ExtensionFilter extFilter = new FileChooser.ExtensionFilter(filterText, filter);
fileChooser.getExtensionFilters().add(extFilter);
File initfile = new File(model.getFilepath());
fileChooser.setInitialDirectory(initfile.getParentFile());
fileChooser.setInitialFileName(initfile.getName());
fileChooser.setTitle("Save File");
//Show open file dialog
final File file = fileChooser.showOpenDialog(applicationPane.getScene().getWindow());
if (file != null) {
model.setFilepath(file.getAbsolutePath());
saveCSVService.restart();
}
}
}
/**
* Creates new table view and add the new content
*/
private void resetContent() {
model = csvLoader.getData();
model.setValidator(validationLoader.getValidator());
TableView<CSVRow> tableView = new TableView<>();
for (String column: model.getHeader()) {
addColumn(column, tableView);
}
tableView.getItems().setAll(model.getRows());
tableView.setEditable(true);
applicationPane.setCenter(tableView);
}
/**
* Adds a column with the given name to the tableview
* @param header name of the column header
* @param tableView the tableview
*/
private void addColumn(String header, TableView tableView) {
TableColumn column = new TableColumn(header);
column.setCellValueFactory(new ObservableMapValueFactory(header));
column.setCellFactory(cellFactory);
column.setEditable(true);
column.setOnEditCommit(new EventHandler<TableColumn.CellEditEvent<CSVRow, CSVValue>>() {
@Override
public void handle(TableColumn.CellEditEvent<CSVRow, CSVValue> event) {
event.getTableView().getItems().get(event.getTablePosition().getRow()).
getColumns().get(header).
setValue(event.getNewValue());
}
});
tableView.getColumns().add(column);
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// inner class
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Service class for async load of a csv file
*/
private class LoadCSVService extends Service {
private File file = null;
private FileReader fileReader;
public void setFile(File value) {
file = value;
}
public void setFileReader(FileReader fileReader) {
this.fileReader = fileReader;
}
@Override
protected Task createTask() {
return new Task() {
@Override
protected Void call() throws Exception {
if (file != null) {
try {
fileReader.read(file);
runLater(SmartCSVController.this::resetContent);
} catch (IOException ex) {
ex.printStackTrace();
}
}
return null;
}
};
}
}
/**
* Service class for async load of a csv file
*/
private class SaveCSVService extends Service {
@Override
protected Task createTask() {
return new Task() {
@Override
protected Void call() throws Exception {
try {
csvFileWriter.saveFile(model);
runLater(SmartCSVController.this::resetContent);
} catch (IOException ex) {
ex.printStackTrace();
}
return null;
}
};
}
}
}

View File

@@ -0,0 +1,136 @@
/*
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.fx.table;
import javafx.scene.control.ContentDisplay;
import javafx.scene.control.TableCell;
import javafx.scene.control.TextField;
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 static javafx.application.Platform.runLater;
/**
* Created by Andreas on 27.11.2015.
*/
public class EditableValidationCell extends TableCell<CSVRow, CSVValue> {
private ValueTextField textField;
@Override
public void startEdit() {
super.startEdit();
setTextField();
runLater(() -> {
textField.requestFocus();
textField.selectAll();
});
}
@Override
public void cancelEdit() {
super.cancelEdit();
setText(getItem().getValue());
setContentDisplay(ContentDisplay.TEXT_ONLY);
}
@Override
protected void updateItem(CSVValue item, boolean empty) {
super.updateItem(item, empty);
if (item == null || item.getValid().isValid() || isEditing()) {
setStyle("");
setTooltip(null);
} else if (!item.getValid().isValid()) {
setStyle("-fx-background-color: #ff8888");
setTooltip(new Tooltip(item.getValid().error()));
}
if (item == null || empty) {
setTextInCell(null);
} else {
if (isEditing()) {
setTextField();
textField.setValue(item);
} else {
setTextInCell(item.getValue());
}
}
}
private void setTextField() {
if (textField == null) {
createTextField();
}
setGraphic(textField);
setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
}
private void setTextInCell(String text) {
setGraphic(null);
setText(text);
setContentDisplay(ContentDisplay.TEXT_ONLY);
}
private void createTextField() {
textField = new ValueTextField(getItem());
textField.setMinWidth(this.getWidth() - this.getGraphicTextGap() * 2);
textField.setOnKeyPressed(t -> {
if (t.getCode() == KeyCode.ENTER) {
commitEdit(textField.getValue());
} else if (t.getCode() == KeyCode.ESCAPE) {
cancelEdit();
}
});
textField.focusedProperty().addListener((observable, oldValue, newValue) -> {
if (!newValue && textField != null) {
commitEdit(textField.getValue());
}
});
}
private class ValueTextField extends TextField {
private CSVValue value;
public ValueTextField(CSVValue value) {
setValue(value);
}
public void setValue(CSVValue value) {
this.value = value;
setText(value.getValue());
}
public CSVValue getValue() {
value.setValue(getText());
return value;
}
}
}

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.fx.table;
import javafx.beans.property.ObjectProperty;
import javafx.scene.control.TableColumn;
import javafx.util.Callback;
import ninja.javafx.smartcsv.fx.table.model.CSVRow;
import ninja.javafx.smartcsv.fx.table.model.CSVValue;
/**
* Created by Andreas on 18.11.2015.
*/
public class ObservableMapValueFactory implements
Callback<TableColumn.CellDataFeatures<CSVRow, CSVValue>, ObjectProperty<CSVValue>> {
private final Object key;
public ObservableMapValueFactory(Object key) {
this.key = key;
}
@Override
public ObjectProperty<CSVValue> call(TableColumn.CellDataFeatures<CSVRow, CSVValue> features) {
CSVRow row = features.getValue();
ObjectProperty<CSVValue> value = row.getColumns().get(key);
return value;
}
}

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.fx.table;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.util.Callback;
import ninja.javafx.smartcsv.fx.table.model.CSVModel;
import ninja.javafx.smartcsv.fx.table.model.CSVRow;
import ninja.javafx.smartcsv.fx.table.model.CSVValue;
/**
* Created by Andreas on 18.11.2015.
*/
public class ValidationCellFactory implements Callback<TableColumn<CSVRow, CSVValue>, TableCell<CSVRow, CSVValue>> {
@Override
public TableCell<CSVRow, CSVValue> call(TableColumn<CSVRow, CSVValue> param) {
return new EditableValidationCell();
}
}

View File

@@ -0,0 +1,121 @@
/*
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.fx.table.model;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import ninja.javafx.smartcsv.validation.ValidationState;
import ninja.javafx.smartcsv.validation.Validator;
/**
* 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 {
private Validator validator;
private ObservableList<CSVRow> rows = FXCollections.observableArrayList();
private String[] header;
private String filepath;
public CSVModel(String filepath) {
this.filepath = filepath;
}
public String getFilepath() {
return this.filepath;
}
public void setFilepath(String filepath) {
this.filepath = filepath;
}
/**
* sets the validator for the data revalidates
* @param validator the validator for this data
*/
public void setValidator(Validator validator) {
this.validator = validator;
revalidate();
}
/**
* returns the data as a list of rows of the
* @return list of rows
*/
public ObservableList<CSVRow> getRows() {
return rows;
}
/**
* 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;
}
/**
* sets the column headers as string array
* @param header the headers of the columns
*/
public void setHeader(String[] header) {
this.header = header;
}
/**
* returns the column headers
* @return the column headers
*/
public String[] getHeader() {
return header;
}
/**
* walks through the data and validates each value
*/
private void revalidate() {
for (CSVRow row: rows) {
row.setValidator(validator);
for (String column: row.getColumns().keySet()) {
CSVValue value = row.getColumns().get(column).getValue();
value.setValidator(validator);
if (validator != null) {
value.setValid(validator.isValid(column, value.getValue()));
} else {
value.setValid(new ValidationState());
}
}
}
}
}

View File

@@ -0,0 +1,90 @@
/*
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.fx.table.model;
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
*/
public void setRowNumber(int rowNumber) {
this.rowNumber = rowNumber;
}
/**
* return the row number
* @return row number
*/
public int getRowNumber() {
return rowNumber;
}
/**
* returns the columns with data as Map
* @return columns with data
*/
public ObservableMap<String, ObjectProperty<CSVValue>> getColumns() {
return columns;
}
/**
* stores the given value in the given column of this row
* @param column column name
* @param value the value to store
*/
public void addValue(String column, String value) {
CSVValue v = new CSVValue();
v.setValidator(validator);
v.setValue(value);
v.setColumn(column);
v.setRowNumber(rowNumber);
columns.put(column, new SimpleObjectProperty<>(v));
}
}

View File

@@ -0,0 +1,112 @@
/*
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.fx.table.model;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import ninja.javafx.smartcsv.validation.ValidationState;
import ninja.javafx.smartcsv.validation.Validator;
/**
* The csv value represents the value of a single cell.
* It also knows about the position (row and column)
* 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 ValidationState valid = new ValidationState();
/**
* 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
*/
public String getValue() {
return value.get();
}
/**
* JavaFX property representation of the real value
* @return property of real value
*/
public StringProperty valueProperty() {
return value;
}
/**
* sets the real value
* @param value the real value
*/
public void setValue(String value) {
if (validator != null) {
valid = validator.isValid(column, value);
}
this.value.set(value);
}
/**
* returns if the value is valid to the rules of the validator
* @return
*/
public ValidationState getValid() {
return valid;
}
/**
* sets the state if a value is valid or not
* @param valid the validation state
*/
protected void setValid(ValidationState valid) {
this.valid = valid;
}
}

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 com.typesafe.config.Config;
import com.typesafe.config.ConfigFactory;
import ninja.javafx.smartcsv.FileReader;
import org.springframework.stereotype.Service;
import java.io.File;
import java.io.IOException;
/**
* This class loads the constraints as json config
*/
@Service
public class ValidationFileReader implements FileReader {
private Config config;
@Override
public void read(File file) throws IOException {
config = ConfigFactory.parseFile(file);
}
public Validator getValidator() {
return new Validator(config);
}
}

View File

@@ -0,0 +1,51 @@
/*
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.io.StringWriter;
/**
* Created by Andreas on 28.11.2015.
*/
public class ValidationState {
private boolean valid = true;
private StringWriter messages = new StringWriter();
public void invalidate(String message) {
valid = false;
messages.append(message).append('\n');
}
public boolean isValid() {
return valid;
}
public String error() {
return messages.toString();
}
}

View File

@@ -0,0 +1,216 @@
/*
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 com.typesafe.config.Config;
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.Map;
import static org.apache.commons.validator.GenericValidator.*;
/**
* This class checks all the validations defined in the
* Config against a given value
*/
public class Validator {
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// member variables
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
private Config validationConfig;
private GroovyShell shell = new GroovyShell();
private Map<String, Script> scriptCache = new HashMap<>();
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// constructors
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* JSON configuration for this validator
* @param validationConfig
*/
public Validator(Config validationConfig) {
this.validationConfig = validationConfig;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// oublic methods
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* checks if the value is valid for the column configuration
* @param column the column name
* @param value the value to check
* @return ValidationState with information if valid and if not which error happened
*/
public ValidationState isValid(String column, String value) {
ValidationState result = new ValidationState();
if (validationConfig != null) {
Config columnConfig = getColumnConfig(column);
if (columnConfig != null) {
checkBlankOrNull(columnConfig, value, result);
if (value != null) {
checkRegularExpression(columnConfig, value, result);
checkAlphaNumeric(columnConfig, value, result);
checkDate(columnConfig, value, result);
checkMaxLength(columnConfig, value, result);
checkMinLength(columnConfig, value, result);
checkInteger(columnConfig, value, result);
checkGroovy(column, columnConfig, value, result);
}
}
}
return result;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// private methods
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
private void checkGroovy(String column, Config columnConfig, String value, ValidationState result) {
String groovyScript = getString(columnConfig, "groovy");
if (groovyScript != null) {
Script script = scriptCache.get(column);
if (script == null) {
script = shell.parse(groovyScript);
scriptCache.put(column, script);
}
Binding binding = new Binding();
binding.setVariable("value", value);
script.setBinding(binding);
Object groovyResult = null;
try {
groovyResult = script.run();
} catch (CompilationFailedException e) {
result.invalidate("groovy script '"+groovyScript+"' throws exception: "+e.getMessage());
e.printStackTrace();
}
if (groovyResult == null) {
result.invalidate("groovy script '"+groovyScript+"' returns null");
}
if (!isScriptResultTrue(groovyResult)) {
result.invalidate(groovyResult.toString());
}
}
}
private boolean isScriptResultTrue(Object groovyResult) {
return groovyResult.equals(true) || groovyResult.toString().trim().toLowerCase().equals("true");
}
private void checkBlankOrNull(Config columnConfig, String value, ValidationState result) {
if (getBoolean(columnConfig, "not empty")) {
if (isBlankOrNull(value)) {
result.invalidate("should not be empty");
}
}
}
private void checkInteger(Config columnConfig, String value, ValidationState result) {
if (getBoolean(columnConfig, "integer")) {
if (!isInt(value)) {
result.invalidate("should be an integer");
}
}
}
private void checkMinLength(Config columnConfig, String value, ValidationState result) {
Integer minLength = getInteger(columnConfig, "minlength");
if (minLength != null) {
if (!minLength(value, minLength)) {
result.invalidate("has not min length of " + minLength);
}
}
}
private void checkMaxLength(Config columnConfig, String value, ValidationState result) {
Integer maxLength = getInteger(columnConfig, "maxlength");
if (maxLength != null) {
if (!maxLength(value, maxLength)) {
result.invalidate("has not max length of " + maxLength);
}
}
}
private void checkDate(Config columnConfig, String value, ValidationState result) {
String dateformat = getString(columnConfig, "date");
if (dateformat != null && !dateformat.trim().isEmpty()) {
if (!isDate(value, dateformat, true)) {
result.invalidate("is not a date of format " + dateformat);
}
}
}
private void checkAlphaNumeric(Config columnConfig, String value, ValidationState result) {
if (getBoolean(columnConfig, "alphanumeric")) {
if (!matchRegexp(value, "[0-9a-zA-Z]*")) {
result.invalidate("should not be alphanumeric");
}
}
}
private void checkRegularExpression(Config columnConfig, String value, ValidationState result) {
String regexp = getString(columnConfig, "regexp");
if (regexp != null && !regexp.trim().isEmpty()) {
if (!matchRegexp(value, regexp)) {
result.invalidate("does not match " + regexp);
}
}
}
private Config getColumnConfig(String column) {
return validationConfig.hasPath(column) ? validationConfig.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);
}
}

View File

@@ -0,0 +1,8 @@
application.name = SmartCSV.fx
application.version = 0.1
# fxml views
fxml.smartcvs.view = /ninja/javafx/smartcsv/fx/smartcsv.fxml
# resources
resource.main = ninja.javafx.smartcsv.fx.smartcsv

View File

@@ -0,0 +1,57 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import java.net.URL?>
<BorderPane fx:id="applicationPane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="700.0" prefWidth="1000.0" xmlns="http://javafx.com/javafx/8.0.66" xmlns:fx="http://javafx.com/fxml/1">
<top>
<VBox prefWidth="100.0" BorderPane.alignment="CENTER">
<children>
<MenuBar>
<menus>
<Menu mnemonicParsing="false" text="File">
<items>
<MenuItem mnemonicParsing="false" onAction="#openCsv" text="Open CSV" />
<MenuItem mnemonicParsing="false" onAction="#openConfig" text="Open Validation Config" />
<SeparatorMenuItem mnemonicParsing="false" />
<MenuItem mnemonicParsing="false" onAction="#saveCsv" text="Save" />
<MenuItem mnemonicParsing="false" onAction="#saveAsCsv" text="Save As" />
<SeparatorMenuItem mnemonicParsing="false" />
<MenuItem mnemonicParsing="false" onAction="#close" text="Close" />
</items>
</Menu>
<Menu mnemonicParsing="false" text="Edit">
<items>
<MenuItem mnemonicParsing="false" text="Delete" />
</items>
</Menu>
<Menu mnemonicParsing="false" text="Help">
<items>
<MenuItem mnemonicParsing="false" text="About" />
</items>
</Menu>
</menus>
</MenuBar>
</children>
</VBox>
</top>
<center>
<TableView fx:id="tableView" prefHeight="200.0" prefWidth="200.0" BorderPane.alignment="CENTER">
<columns>
</columns>
</TableView>
</center>
<bottom>
<HBox spacing="8.0" BorderPane.alignment="CENTER">
<children>
<Label fx:id="stateline" text="Status" HBox.hgrow="ALWAYS" />
</children>
<BorderPane.margin>
<Insets bottom="4.0" left="4.0" right="4.0" top="4.0" />
</BorderPane.margin>
</HBox>
</bottom>
</BorderPane>

View File

@@ -0,0 +1,52 @@
menu.title.import.gpx = Importiere GPX
menu.title.file = Datei
menu.title.quit = Beenden
menu.title.help = Hilfe
menu.title.settings = Einstellungen
menu.title.about = \u00dcber GeoFroggerFX
menu.title.plugins = Plugins
menu.title.list = Listen
menu.title.list.new = Liste anlegen
menu.title.list.delete = Liste l\u00F6schen
menu.title.sort = Sortieren
menu.title.filter = Filtern
label.text.cache.list=Liste:
label.text.cache.list.count=Anzahl:
label.text.name=Name:
label.text.difficulty=Schwierigkeit:
label.text.terrain=Gel\u00E4nde
label.text.placedBy=Platziert von:
label.text.owner=Betreut von:
label.text.date=Datum:
label.text.type=Typ:
label.text.container=Gr\u00F6\u00dfe:
label.text.shortdescription=Kurze Beschreibung:
label.text.htmldescription=HTML Beschreibung
label.text.longdescription=Lange Beschreibung:
tab.text.descriptions=Beschreibungen
tab.text.general=Allgemein
sort.cache.name = GC Code
sort.cache.type = Art
sort.cache.difficulty = Schwierigkeitsgrad
sort.cache.terrain = Gel\u00E4nde
sort.cache.placedBy = Platziert von
sort.cache.owner = Betreut von
dialog.title.about = &#220;ber
dialog.title.new_list = Neue Liste
dialog.label.listname = Name der Liste:
dialog.msg.list.does.exist = Diese Liste existiert schon!
dialog.title.delete_list = Liste l&#246;schen
all.caches = Alle Caches
status.load.all.caches.from.db = Lade alle Caches von der Datenbank.
status.all.cache.lists.loaded = Alle Listen geladen.
status.load.caches.from.db = Lade Caches von der Datenbank.
status.all.caches.loaded = Alle Caches geladen.
status.store.all.caches = Speichere Caches in Datenbank.
status.all.caches.stored = Alle Caches in der Datenbank gespeichert.

View File

@@ -0,0 +1,53 @@
menu.title.import.gpx = Import GPX
menu.title.file = File
menu.title.quit = Quit
menu.title.help = Help
menu.title.settings = Settings
menu.title.about = About GeoFroggerFX
menu.title.plugins = Plugins
menu.title.list = Lists
menu.title.list.new = New list
menu.title.list.delete = Delete list
menu.title.sort = Sort
menu.title.filter = Filter
label.text.cache.list=List:
label.text.cache.list.count=Number:
label.text.name=Name:
label.text.difficulty=Difficulty:
label.text.terrain=Terrain:
label.text.placedBy=Placed By:
label.text.owner=Owner:
label.text.date=Date:
label.text.type=Type:
label.text.container=Container:
label.text.shortdescription=Short description:
label.text.htmldescription=HTML Description
label.text.longdescription=Long description:
tab.text.descriptions=Descriptions
tab.text.general=General
sort.cache.name = GC Code
sort.cache.type = Type
sort.cache.difficulty = Difficulty
sort.cache.terrain = Terrain
sort.cache.placedBy = Placed by
sort.cache.owner = Owner
dialog.title.about = About
dialog.title.new_list = New list
dialog.label.listname = Name of list:
dialog.msg.list.does.exist = List does already exist!
dialog.title.delete_list = Delete list
all.caches = All caches
status.load.all.caches.from.db = Load cache lists from database.
status.all.cache.lists.loaded = All cache lists loaded.
status.load.caches.from.db = Load caches from database.
status.all.caches.loaded = All caches loaded.
status.store.all.caches = Store caches in database.
status.all.caches.stored = All caches are stored in database.

View File

@@ -0,0 +1,103 @@
/*
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.fx.table.model;
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.*;
/**
* unit test for the csv model
*/
public class CSVModelTest {
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// constants
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static final String TESTHEADER = "TESTHEADER";
static final String TESTVALUE = "TESTVALUE";
static final String FILEPATH = "filepath";
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// subject under test
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CSVModel sut = new CSVModel(FILEPATH);
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// tests
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@Test
public void fresh_model_has_empty_rows() {
// assertion
assertThat(sut.getRows(), empty());
}
@Test
public void adds_a_new_row_into_row_list() {
// execution
CSVRow newRow = sut.addRow();
// assertion
assertThat(sut.getRows(), contains(newRow));
}
@Test
public void new_row_has_last_index_of_list_as_rownumber() {
// execution
CSVRow newRow = sut.addRow();
// assertion
assertThat(sut.getRows().indexOf(newRow), is(newRow.getRowNumber()));
}
@Test
public void set_validator_calls_when_model_has_data() {
// setup
Validator validator = mock(Validator.class);
setup_model_with_one_row_one_column_and_value();
// execution
sut.setValidator(validator);
// assertion
verify(validator).isValid(TESTHEADER, TESTVALUE);
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// private methods
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
private void setup_model_with_one_row_one_column_and_value() {
sut.setHeader(new String[] {TESTHEADER});
sut.addRow().addValue(TESTHEADER, TESTVALUE);
}
}

View File

@@ -0,0 +1,43 @@
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;
/**
* unit test for row class
*/
public class CSVRowTest {
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// constants
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static final String COLUMN = "COLUMN";
static final String VALUE = "VALUE";
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// subject under test
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CSVRow sut = new CSVRow();
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// tests
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@Test
public void adds_column_and_value_to_row() {
// execution
sut.addValue(COLUMN, VALUE);
// assertion
assertThat(sut.getColumns(), hasKey(COLUMN));
assertThat(sut.getColumns().get(COLUMN).get().getValue(), is(VALUE));
}
}

View File

@@ -0,0 +1,58 @@
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.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(COLUMN, VALUE);
}
}

View File

@@ -0,0 +1,131 @@
package ninja.javafx.smartcsv.validation;
import com.typesafe.config.Config;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import java.util.Collection;
import static java.util.Arrays.asList;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
/**
* unit test for validator
*/
@RunWith(Parameterized.class)
public class ValidatorTest {
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// parameters
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
private Config config;
private String column;
private String value;
private Boolean expectedResult;
private String expectedError;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// subject under test
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
private Validator sut;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// parameterized constructor
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public ValidatorTest(String configcolumn,
String configValidation,
Object configValue,
String column,
String value,
Boolean expectedResult,
String expectedError) {
this.config = config(configcolumn, configValidation, configValue);
this.column = column;
this.value = value;
this.expectedResult = expectedResult;
this.expectedError = expectedError;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// init
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@Before
public void initialize() {
sut = new Validator(config);
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// tests
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@Test
public void validation() {
// execution
ValidationState result = sut.isValid(column, value);
// assertion
assertThat(result.isValid(), is(expectedResult));
if (!expectedResult) {
assertThat(result.error(), is(expectedError));
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// mocks
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
private Config config(String column, String validation, Object value) {
Config columnConfig = mock(Config.class);
Config validatorConfig = mock(Config.class);
when(columnConfig.hasPath(column)).thenReturn(true);
when(columnConfig.getConfig(column)).thenReturn(validatorConfig);
when(validatorConfig.hasPath(validation)).thenReturn(true);
if (value instanceof Boolean) {
when(validatorConfig.getBoolean(validation)).thenReturn((Boolean) value);
} else if (value instanceof String) {
when(validatorConfig.getString(validation)).thenReturn((String) value);
} else if (value instanceof Integer) {
when(validatorConfig.getInt(validation)).thenReturn((Integer)value);
}
return columnConfig;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// parameters for tests
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@Parameterized.Parameters
public static Collection validationConfigurations() {
return asList(new Object[][] {
{ "column", "not empty", true, "column", "value", true, null },
{ "column", "not empty", true, "column", "", false, "should not be empty\n" },
{ "column", "not empty", true, "column", null, false, "should not be empty\n" },
{ "column", "integer", true, "column", "999", true, null },
{ "column", "integer", true, "column", "a", false, "should be an integer\n" },
{ "column", "minlength", 2, "column", "12", true, null },
{ "column", "minlength", 2, "column", "1", false, "has not min length of 2\n" },
{ "column", "maxlength", 2, "column", "12", true, null },
{ "column", "maxlength", 2, "column", "123", false, "has not max length of 2\n" },
{ "column", "date", "yyyyMMdd", "column", "20151127", true, null },
{ "column", "date", "yyyyMMdd", "column", "27.11.2015", false, "is not a date of format yyyyMMdd\n" },
{ "column", "alphanumeric", true, "column", "abcABC123", true, null },
{ "column", "alphanumeric", true, "column", "-abcABC123", false, "should not be alphanumeric\n" },
{ "column", "regexp", "[a-z]*", "column", "abc", true, null },
{ "column", "regexp", "[a-z]*", "column", "abcA", false, "does not match [a-z]*\n" },
{ "column", "groovy", "value.contains('a')? 'true' : 'no a inside'", "column", "abcdef", true, null },
{ "column", "groovy", "value.contains('a')? 'true' : 'no a inside'", "column", "bcdefg", false, "no a inside\n" },
});
}
}