]> git.mxchange.org Git - jcore.git/commitdiff
Initial import, mostly from Addressbook project
authorRoland Haeder <roland@mxchange.org>
Thu, 6 Aug 2015 06:30:04 +0000 (08:30 +0200)
committerRoland Haeder <roland@mxchange.org>
Thu, 6 Aug 2015 06:30:04 +0000 (08:30 +0200)
Signed-off-by: Roland Häder <roland@mxchange.org>
29 files changed:
.gitignore [new file with mode: 0644]
build.xml [new file with mode: 0644]
lib/CopyLibs/org-netbeans-modules-java-j2seproject-copylibstask.jar [new file with mode: 0644]
lib/log4j-api-2.3.jar [new file with mode: 0644]
lib/log4j-core-2.3.jar [new file with mode: 0644]
lib/nblibraries.properties [new file with mode: 0644]
src/org/mxchange/jcore/BaseFrameworkSystem.java [new file with mode: 0644]
src/org/mxchange/jcore/FrameworkInterface.java [new file with mode: 0644]
src/org/mxchange/jcore/application/Application.java [new file with mode: 0644]
src/org/mxchange/jcore/client/BaseClient.java [new file with mode: 0644]
src/org/mxchange/jcore/client/Client.java [new file with mode: 0644]
src/org/mxchange/jcore/database/backend/BaseDatabaseBackend.java [new file with mode: 0644]
src/org/mxchange/jcore/database/backend/DatabaseBackend.java [new file with mode: 0644]
src/org/mxchange/jcore/database/backend/base64/Base64CsvDatabaseBackend.java [new file with mode: 0644]
src/org/mxchange/jcore/database/backend/mysql/MySqlDatabaseBackend.java [new file with mode: 0644]
src/org/mxchange/jcore/database/frontend/BaseDatabaseFrontend.java [new file with mode: 0644]
src/org/mxchange/jcore/database/frontend/DatabaseFrontend.java [new file with mode: 0644]
src/org/mxchange/jcore/database/storage/Storeable.java [new file with mode: 0644]
src/org/mxchange/jcore/database/storage/csv/StoreableCsv.java [new file with mode: 0644]
src/org/mxchange/jcore/exceptions/BadTokenException.java [new file with mode: 0644]
src/org/mxchange/jcore/exceptions/FrameAlreadyInitializedException.java [new file with mode: 0644]
src/org/mxchange/jcore/exceptions/UnhandledUserChoiceException.java [new file with mode: 0644]
src/org/mxchange/jcore/exceptions/UnsupportedDatabaseBackendException.java [new file with mode: 0644]
src/org/mxchange/jcore/exceptions/UnsupportedDatabaseDriverException.java [new file with mode: 0644]
src/org/mxchange/jcore/manager/BaseManager.java [new file with mode: 0644]
src/org/mxchange/jcore/manager/Manageable.java [new file with mode: 0644]
src/org/mxchange/jcore/manager/application/ApplicationManager.java [new file with mode: 0644]
src/org/mxchange/jcore/manager/application/ManageableApplication.java [new file with mode: 0644]
src/org/mxchange/jcore/model/BaseModel.java [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..f91a00b
--- /dev/null
@@ -0,0 +1,5 @@
+/nbproject/
+/manifest.mf
+/build/
+/dist/
+/*.properties
diff --git a/build.xml b/build.xml
new file mode 100644 (file)
index 0000000..e4320c2
--- /dev/null
+++ b/build.xml
@@ -0,0 +1,73 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- You may freely edit this file. See commented blocks below for -->
+<!-- some examples of how to customize the build. -->
+<!-- (If you delete it and reopen the project it will be recreated.) -->
+<!-- By default, only the Clean and Build commands use this build script. -->
+<!-- Commands such as Run, Debug, and Test only use this build script if -->
+<!-- the Compile on Save feature is turned off for the project. -->
+<!-- You can turn off the Compile on Save (or Deploy on Save) setting -->
+<!-- in the project's Project Properties dialog box.-->
+<project name="jcore" default="default" basedir=".">
+    <description>Builds, tests, and runs the project jcore.</description>
+    <import file="nbproject/build-impl.xml"/>
+    <!--
+
+    There exist several targets which are by default empty and which can be 
+    used for execution of your tasks. These targets are usually executed 
+    before and after some main targets. They are: 
+
+      -pre-init:                 called before initialization of project properties
+      -post-init:                called after initialization of project properties
+      -pre-compile:              called before javac compilation
+      -post-compile:             called after javac compilation
+      -pre-compile-single:       called before javac compilation of single file
+      -post-compile-single:      called after javac compilation of single file
+      -pre-compile-test:         called before javac compilation of JUnit tests
+      -post-compile-test:        called after javac compilation of JUnit tests
+      -pre-compile-test-single:  called before javac compilation of single JUnit test
+      -post-compile-test-single: called after javac compilation of single JUunit test
+      -pre-jar:                  called before JAR building
+      -post-jar:                 called after JAR building
+      -post-clean:               called after cleaning build products
+
+    (Targets beginning with '-' are not intended to be called on their own.)
+
+    Example of inserting an obfuscator after compilation could look like this:
+
+        <target name="-post-compile">
+            <obfuscate>
+                <fileset dir="${build.classes.dir}"/>
+            </obfuscate>
+        </target>
+
+    For list of available properties check the imported 
+    nbproject/build-impl.xml file. 
+
+
+    Another way to customize the build is by overriding existing main targets.
+    The targets of interest are: 
+
+      -init-macrodef-javac:     defines macro for javac compilation
+      -init-macrodef-junit:     defines macro for junit execution
+      -init-macrodef-debug:     defines macro for class debugging
+      -init-macrodef-java:      defines macro for class execution
+      -do-jar:                  JAR building
+      run:                      execution of project 
+      -javadoc-build:           Javadoc generation
+      test-report:              JUnit report generation
+
+    An example of overriding the target for project execution could look like this:
+
+        <target name="run" depends="jcore-impl.jar">
+            <exec dir="bin" executable="launcher.exe">
+                <arg file="${dist.jar}"/>
+            </exec>
+        </target>
+
+    Notice that the overridden target depends on the jar target and not only on 
+    the compile target as the regular run target does. Again, for a list of available 
+    properties which you can use, check the target you are overriding in the
+    nbproject/build-impl.xml file. 
+
+    -->
+</project>
diff --git a/lib/CopyLibs/org-netbeans-modules-java-j2seproject-copylibstask.jar b/lib/CopyLibs/org-netbeans-modules-java-j2seproject-copylibstask.jar
new file mode 100644 (file)
index 0000000..eaf6790
Binary files /dev/null and b/lib/CopyLibs/org-netbeans-modules-java-j2seproject-copylibstask.jar differ
diff --git a/lib/log4j-api-2.3.jar b/lib/log4j-api-2.3.jar
new file mode 100644 (file)
index 0000000..2a61bbe
Binary files /dev/null and b/lib/log4j-api-2.3.jar differ
diff --git a/lib/log4j-core-2.3.jar b/lib/log4j-core-2.3.jar
new file mode 100644 (file)
index 0000000..5438b0b
Binary files /dev/null and b/lib/log4j-core-2.3.jar differ
diff --git a/lib/nblibraries.properties b/lib/nblibraries.properties
new file mode 100644 (file)
index 0000000..6d0afb5
--- /dev/null
@@ -0,0 +1,4 @@
+libs.CopyLibs.classpath=\
+    ${base}/CopyLibs/org-netbeans-modules-java-j2seproject-copylibstask.jar
+libs.CopyLibs.displayName=CopyLibs Task
+libs.CopyLibs.prop-version=2.0
diff --git a/src/org/mxchange/jcore/BaseFrameworkSystem.java b/src/org/mxchange/jcore/BaseFrameworkSystem.java
new file mode 100644 (file)
index 0000000..6c5267e
--- /dev/null
@@ -0,0 +1,685 @@
+/*
+ * Copyright (C) 2015 Roland Haeder
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.mxchange.jcore;
+
+import java.io.BufferedReader;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.text.MessageFormat;
+import java.util.Arrays;
+import java.util.Properties;
+import java.util.ResourceBundle;
+import java.util.StringTokenizer;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.mxchange.jcore.application.Application;
+import org.mxchange.jcore.client.Client;
+import org.mxchange.jcore.database.frontend.DatabaseFrontend;
+import org.mxchange.jcore.manager.Manageable;
+
+/**
+ * General class
+ *
+ * @author Roland Haeder
+ */
+public class BaseFrameworkSystem implements FrameworkInterface {
+
+       /**
+        * Instance for own properties
+        */
+       private static final Properties properties = new Properties(System.getProperties());
+
+       /**
+        * Class' logger
+        */
+       private final Logger LOG;
+
+       /**
+        * Application instance
+        */
+       private Application application;
+
+       /**
+        * Bundle instance
+        */
+       private final ResourceBundle bundle;
+
+       /**
+        * Client instance
+        */
+       private Client client;
+
+       /**
+        * Manager instance
+        */
+       private Manageable manager;
+
+       /**
+        * Name of used database table, handled over to backend
+        */
+       private String tableName;
+
+       /**
+        * DatabaseFrontend instance
+        */
+       private DatabaseFrontend wrapper;
+
+       /**
+        * Initialize object
+        */
+       {
+               LOG = LogManager.getLogger(this);
+               bundle = ResourceBundle.getBundle(FrameworkInterface.I18N_BUNDLE_FILE); // NOI18N
+       }
+
+       /**
+        * No instances can be created of this class
+        */
+       protected BaseFrameworkSystem () {
+               // Init properties file
+               this.initProperties();
+       }
+
+       /**
+        * Application instance
+        *
+        * @return the application
+        */
+       @Override
+       public final Application getApplication () {
+               return this.application;
+       }
+
+       /**
+        * Client instance
+        *
+        * @return the client
+        */
+       @Override
+       public final Client getClient () {
+               return this.client;
+       }
+
+       /**
+        * Checks if given boolean field is available and set to same value
+        *
+        * @param columnName Column name to check
+        * @param bool Boolean value
+        * @return Whether all conditions are met
+        */
+       @Override
+       public boolean isValueEqual (final String columnName, final boolean bool) {
+               // Not implemented
+               throw new UnsupportedOperationException(MessageFormat.format("Not implemented. columnName={0},bool={1}", columnName, bool)); //NOI18N
+       }
+
+       /**
+        * Log exception
+        *
+        * @param exception Exception to log
+        */
+       @Override
+       public final void logException (final Throwable exception) {
+               // Log this exception
+               this.getLogger().catching(exception);
+       }
+
+       /**
+        * Prepares all properties, the file is written if it is not found
+        */
+       private void initProperties () {
+               // Trace message
+               this.getLogger().trace("CALLED!"); //NOI18N
+
+               // Debug message
+               this.getLogger().debug(MessageFormat.format("{0} properties are loaded already.", BaseFrameworkSystem.properties.size())); //NOI18N
+
+               // Are some properties loaded?
+               if (!BaseFrameworkSystem.properties.isEmpty()) {
+                       // Some are already loaded, abort here
+                       return;
+               }
+
+               try {
+                       // Try to read it
+                       BaseFrameworkSystem.properties.load(new BufferedReader(new InputStreamReader(new FileInputStream(FrameworkInterface.PROPERTIES_CONFIG_FILE))));
+
+                       // Debug message
+                       this.getLogger().debug(MessageFormat.format("{0} properties has been loaded.", BaseFrameworkSystem.properties.size())); //NOI18N
+               } catch (final FileNotFoundException ex) {
+                       // Debug message
+                       this.getLogger().debug(MessageFormat.format("Properties file {0} not found: {1}", FrameworkInterface.PROPERTIES_CONFIG_FILE, ex)); //NOI18N
+
+                       /*
+                        * The file is not found which is normal for first run, so
+                        * initialize default values.
+                        */
+                       this.initPropertiesWithDefault();
+
+                       // Write file
+                       this.writePropertiesFile();
+               } catch (final IOException ex) {
+                       // Something else didn't work
+                       this.abortProgramWithException(ex);
+               }
+
+               // Trace message
+               this.getLogger().trace("EXIT!"); //NOI18N
+       }
+
+       /**
+        * Initializes properties with default values
+        */
+       private void initPropertiesWithDefault () {
+               // Trace message
+               this.getLogger().trace("CALLED!"); //NOI18N
+
+               // Init default values:
+               // Default database backend
+               BaseFrameworkSystem.properties.put("org.mxchange.database.backendType", "base64csv"); //NOI18N
+
+               // For MySQL backend
+               BaseFrameworkSystem.properties.put("org.mxchange.database.mysql.host", "localhost"); //NOI18N
+               BaseFrameworkSystem.properties.put("org.mxchange.database.mysql.dbname", "test"); //NOI18N
+               BaseFrameworkSystem.properties.put("org.mxchange.database.mysql.login", ""); //NOI18N
+               BaseFrameworkSystem.properties.put("org.mxchange.database.mysql.password", ""); //NOI18N
+
+               // Trace message
+               this.getLogger().trace("EXIT!"); //NOI18N
+       }
+
+       /**
+        * Writes the properties file to disk
+        */
+       private void writePropertiesFile () {
+               // Trace message
+               this.getLogger().trace("CALLED!"); //NOI18N
+
+               try {
+                       // Write it
+                       BaseFrameworkSystem.properties.store(new PrintWriter(FrameworkInterface.PROPERTIES_CONFIG_FILE), "This file is automatically generated. You may wish to alter it."); //NOI18N
+               } catch (final IOException ex) {
+                       this.abortProgramWithException(ex);
+               }
+
+               // Trace message
+               this.getLogger().trace("EXIT!"); //NOI18N
+       }
+
+       /**
+        * Converts a column name like "foo_bar" to an attribute name like "fooBar"
+        *
+        * @param columnName Column name to convert
+        * @return Attribute name
+        */
+       protected String convertColumnNameToAttribute (final String columnName) {
+               // Trace message
+               this.getLogger().trace(MessageFormat.format("columnName={0} - CALLED!", columnName)); //NOI18N
+
+               // First all lower case
+               String lower = columnName.toLowerCase();
+
+               // Then split on "_"
+               StringTokenizer tokenizer = new StringTokenizer(lower, "_"); //NOI18N
+
+               // Resulting string
+               StringBuilder builder = new StringBuilder(tokenizer.countTokens());
+
+               // Init counter
+               int count = 0;
+
+               // Walk through all
+               while (tokenizer.hasMoreTokens()) {
+                       // Get token
+                       String token = tokenizer.nextToken();
+
+                       // Is later than first element?
+                       if (count > 0) {
+                               // Make first character upper-case
+                               char c = token.charAt(0);
+                               token = String.valueOf(c).toUpperCase() + token.substring(1);
+                       }
+
+                       // Add token
+                       builder.append(token);
+
+                       // Increment counter
+                       count++;
+               }
+
+               // Trace message
+               this.getLogger().trace(MessageFormat.format("builder={0} - EXIT!", builder)); //NOI18N
+
+               // Return result
+               return builder.toString();
+       }
+
+       /**
+        * Converts a column name like "foo_bar" to a method name like "getFooBar"
+        * for non-booleans and to "isFooBar" for boolean fields.
+        *
+        * @param columnName Column name to convert
+        * @param isBool Whether the parameter is boolean
+        * @return Attribute name
+        */
+       protected String convertColumnNameToGetterMethod (final String columnName, boolean isBool) {
+               // Trace message
+               this.getLogger().trace(MessageFormat.format("columnName={0} - CALLED!", columnName)); //NOI18N
+
+               // Then split on "_"
+               StringTokenizer tokenizer = new StringTokenizer(columnName, "_"); //NOI18N
+
+               // Resulting string
+               StringBuilder builder = new StringBuilder(tokenizer.countTokens());
+
+               // Is it boolean?
+               if (isBool) {
+                       // Append "is"
+                       builder.append("is"); //NOI18N
+               } else {
+                       // Append "get"
+                       builder.append("get"); //NOI18N
+               }
+
+               // Walk through all
+               while (tokenizer.hasMoreTokens()) {
+                       // Get token
+                       String token = tokenizer.nextToken();
+
+                       // Debug message
+                       this.getLogger().debug(MessageFormat.format("token={0}", token)); //NOI18N
+
+                       // Make it upper-case
+                       char c = token.charAt(0);
+                       token = String.valueOf(c).toUpperCase() + token.substring(1);
+
+                       // Add token
+                       builder.append(token);
+               }
+
+               // Trace message
+               this.getLogger().trace(MessageFormat.format("builder={0} - EXIT!", builder)); //NOI18N
+
+               // Return result
+               return builder.toString();
+       }
+
+       /**
+        * Some "getter" for an array from given string and tokenizer
+        *
+        * @param str String to tokenize and get array from
+        * @param delimiter Delimiter
+        * @param size Size of array
+        * @return Array from tokenized string
+        */
+       protected String[] getArrayFromString (final String str, final String delimiter, final int size) {
+               // Trace message
+               this.getLogger().trace(MessageFormat.format("str={0},delimiter={1},size={2} - CALLED!", str, delimiter, size)); //NOI18N
+               
+               // Get tokenizer
+               StringTokenizer tokenizer = new StringTokenizer(str, delimiter);
+               
+               // Init array and index
+               String[] tokens = new String[size];
+               int index = 0;
+               
+               // Run through all tokens
+               while (tokenizer.hasMoreTokens()) {
+                       // Get current token and add it
+                       tokens[index] = tokenizer.nextToken();
+                       
+                       // Debug message
+                       this.getLogger().debug(MessageFormat.format("Token at index{0}: {1}", index, tokens[1])); //NOI18N
+                       
+                       // Increment index
+                       index++;
+               }
+               
+               // Trace message
+               this.getLogger().trace(MessageFormat.format("tokens({0})={1} - EXIT!", tokens.length, Arrays.toString(tokens))); //NOI18N
+
+               // Return it
+               return tokens;
+       }
+
+       /**
+        * Returns boolean field value from given method call
+        *
+        * @param instance The instance to call
+        * @param targetClass Target class to look in
+        * @param methodName Method name to look for
+        * @return Boolean value from field
+        */
+       protected boolean getBooleanField (final FrameworkInterface instance, final String targetClass, final String methodName) {
+               // Trace messahe
+               this.getLogger().trace(MessageFormat.format("targetClass={0},methodName={1}", targetClass, methodName)); //NOI18N
+
+               // Get method instance
+               Method method = this.getMethodFromName(instance, targetClass, methodName);
+
+               // Get value from field
+               Boolean value = false;
+
+               try {
+                       value = (Boolean) method.invoke(instance);
+               } catch (final IllegalArgumentException ex) {
+                       // Other problem
+                       this.abortProgramWithException(ex);
+               } catch (final IllegalAccessException ex) {
+                       // Other problem
+                       this.abortProgramWithException(ex);
+               } catch (final InvocationTargetException ex) {
+                       // Other problem
+                       this.abortProgramWithException(ex);
+               }
+
+               // Return value
+               return value;
+       }
+
+       /**
+        * Client instance
+        *
+        * @param client the client to set
+        */
+       protected final void setClient (final Client client) {
+               this.client = client;
+       }
+
+       /**
+        * Application instance
+        *
+        * @param application the application to set
+        */
+       protected final void setApplication (final Application application) {
+               this.application = application;
+       }
+
+       /**
+        * Manager instance
+        *
+        * @return the contactManager
+        */
+       @Override
+       public final Manageable getManager () {
+               return this.manager;
+       }
+
+       /**
+        * Getter for human-readable string from given key
+        *
+        * @param key Key to return
+        * @return Human-readable message
+        */
+       @Override
+       public final String getMessageStringFromKey (final String key) {
+               // Return message
+               return this.getBundle().getString(key);
+       }
+
+       /**
+        * Some "getter for a value from given column name. This name will be
+        * translated into a method name and then this method is called.
+        *
+        * @param columnName Column name
+        * @return Value from field
+        */
+       @Override
+       public Object getValueFromColumn (final String columnName) {
+               throw new UnsupportedOperationException(MessageFormat.format("Not implemented. columnName={0}", columnName)); //NOI18N
+       }
+
+       /**
+        * Some "getter" for target class instance from given name.
+        *
+        * @param instance Instance to iterate on
+        * @param targetClass Class name to look for
+        * @return Class instance
+        */
+       @SuppressWarnings ("unchecked")
+       private Class<? extends FrameworkInterface> getClassFromTarget (final FrameworkInterface instance, final String targetClass) {
+               // Trace message
+               this.getLogger().debug(MessageFormat.format("instance={0},targetClass={1}", instance, targetClass)); //NOI18N
+               
+               // Instance reflaction of this class
+               Class<? extends FrameworkInterface> c = instance.getClass();
+               
+               // Analyze class
+               while (!targetClass.equals(c.getSimpleName())) {
+                       // Debug message
+                       this.getLogger().debug(MessageFormat.format("c={0}", c.getSimpleName())); //NOI18N
+                       
+                       // Get super class (causes unchecked warning)
+                       c = (Class<? extends FrameworkInterface>) c.getSuperclass();
+               }
+               
+               // Trace message
+               this.getLogger().trace(MessageFormat.format("c={0} - EXIT!", c)); //NOI18N
+               
+               // Return it
+               return c;
+       }
+
+       /**
+        * Some "getter" for a Method instance from given method name
+        *
+        * @param instance Actual instance to call
+        * @param targetClass Target class name
+        * @param methodName Method name
+        * @return A Method instance
+        */
+       private Method getMethodFromName (final FrameworkInterface instance, final String targetClass, final String methodName) {
+               // Trace messahe
+               this.getLogger().trace(MessageFormat.format("targetClass={0},methodName={1}", targetClass, methodName)); //NOI18N
+               
+               // Get target class instance
+               Class<? extends FrameworkInterface> c = this.getClassFromTarget(instance, targetClass);
+               
+               // Init field instance
+               Method method = null;
+               
+               // Use reflection to get all attributes
+               try {
+                       method = c.getDeclaredMethod(methodName, new Class<?>[0]);
+               } catch (final SecurityException ex) {
+                       // Security problem
+                       this.abortProgramWithException(ex);
+               } catch (final NoSuchMethodException ex) {
+                       // Method not found
+                       this.abortProgramWithException(ex);
+               }
+               
+               // Assert on field
+               assert (method instanceof Method) : "method is not a Method instance"; //NOI18N
+               
+               // Trace message
+               this.getLogger().trace(MessageFormat.format("method={0} - EXIT!", method)); //NOI18N
+               
+               // Return it
+               return method;
+       }
+
+       /**
+        * Aborts program with given exception
+        *
+        * @param       throwable Any type of Throwable
+        */
+       protected final void abortProgramWithException (final Throwable throwable) {
+               // Log exception ...
+               this.getLogger().catching(throwable);
+               
+               // .. and exit
+               System.exit(1);
+
+       }
+
+       /**
+        * Getter for bundle instance
+        *
+        * @return Resource bundle
+        */
+       protected final ResourceBundle getBundle () {
+               return this.bundle;
+       }
+
+       /**
+        * Manager instance
+        *
+        * @param manager the manager instance to set
+        */
+       protected final void setContactManager (final Manageable manager) {
+               this.manager = manager;
+       }
+
+       /**
+        * Returns any field value from given method call
+        *
+        * @param instance The instance to call
+        * @param targetClass Target class to look in
+        * @param methodName Method name to look for
+        * @return Any value from field
+        */
+       protected Object getField (final FrameworkInterface instance, final String targetClass, final String methodName) {
+               // Trace messahe
+               this.getLogger().trace(MessageFormat.format("targetClass={0},methodName={1}", targetClass, methodName)); //NOI18N
+
+               // Get method to call
+               Method method = this.getMethodFromName(instance, targetClass, methodName);
+
+               // Get value from field
+               Object object = null;
+
+               try {
+                       object = method.invoke(instance);
+               } catch (final IllegalArgumentException ex) {
+                       // Other problem
+                       this.abortProgramWithException(ex);
+               } catch (final IllegalAccessException ex) {
+                       // Other problem
+                       this.abortProgramWithException(ex);
+               } catch (final InvocationTargetException ex) {
+                       // Other problem
+                       this.abortProgramWithException(ex);
+               }
+
+               // Return value
+               return object;
+       }
+
+       /**
+        * Getter for logger
+        *
+        * @return Logger
+        */
+       @Override
+       public final Logger getLogger () {
+               return this.LOG;
+       }
+
+       /**
+        * Getter for property which must exist
+        *
+        * @param key Key to get
+        * @return Propety value
+        */
+       protected final String getProperty (final String key) {
+               return BaseFrameworkSystem.properties.getProperty(String.format("org.mxchange.addressbook.%s", key)); //NOI18N
+       }
+
+       /**
+        * Name of used database table, handled over to backend
+        *
+        * @return the tableName
+        */
+       protected final String getTableName () {
+               return this.tableName;
+       }
+
+       /**
+        * Name of used database table, handled over to backend
+        *
+        * @param tableName the tableName to set
+        */
+       protected final void setTableName (final String tableName) {
+               this.tableName = tableName;
+       }
+
+       /**
+        * Getter for DatabaseFrontend instance
+        *
+        * @return DatabaseFrontend instance
+        */
+       protected DatabaseFrontend getWrapper () {
+               return this.wrapper;
+       }
+
+       /**
+        * Setter for wrapper instance
+        *
+        * @param wrapper A DatabaseFrontend instance
+        */
+       protected void setWrapper (final DatabaseFrontend wrapper) {
+               this.wrapper = wrapper;
+       }
+
+       /**
+        * Checks whether the given field is a boolean field by probing it.
+        * 
+        * @param instance Instance to call
+        * @param targetClass Target class
+        * @param columnName Column name to check
+        * @return Whether the given column name represents a boolean field
+        */
+       protected boolean isBooleanField (final FrameworkInterface instance, final String targetClass, final String columnName) {
+               // Trace message
+               this.getLogger().trace(MessageFormat.format("instance={0},targetCLass={1},columnName={2} - CALLED!", instance, targetClass, columnName)); //NOI18N
+
+               // Convert column name to getter name (boolean)
+               String methodName = this.convertColumnNameToGetterMethod(columnName, true);
+
+               // Get class instance
+               Class<? extends FrameworkInterface> c = this.getClassFromTarget(instance, targetClass);
+
+               // Defauzlt is boolean
+               boolean isBool = true;
+
+               try {
+                       // Now try to instance the method
+                       Method method = c.getDeclaredMethod(methodName, new Class<?>[0]);
+               } catch (final NoSuchMethodException ex) {
+                       // Debug message
+                       this.getLogger().debug(MessageFormat.format("Method {0} does not exist, field {1} cannot be boolean: {2}", methodName, columnName, ex)); //NOI18N
+
+                       // Not found
+                       isBool = false;
+               } catch (final SecurityException ex) {
+                       // Really bad?
+                       this.abortProgramWithException(ex);
+               }
+
+               // Trace message
+               this.getLogger().trace(MessageFormat.format("isBool={0} - EXIT!", isBool)); //NOI18N
+
+               // Return result
+               return isBool;
+       }
+}
diff --git a/src/org/mxchange/jcore/FrameworkInterface.java b/src/org/mxchange/jcore/FrameworkInterface.java
new file mode 100644 (file)
index 0000000..71ddb00
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2015 Roland Haeder
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.mxchange.jcore;
+
+import org.apache.logging.log4j.Logger;
+import org.mxchange.jcore.application.Application;
+import org.mxchange.jcore.client.Client;
+import org.mxchange.jcore.manager.Manageable;
+
+/**
+ * A general interface which should be always expanded
+ *
+ * @author Roland Haeder
+ */
+public interface FrameworkInterface {
+       /**
+        * File name (and path) for internalization bundle
+        */
+       public static final String I18N_BUNDLE_FILE = "org/mxchange/localization/bundle";
+
+       /*
+        * Properties file name
+        */
+       public static final String PROPERTIES_CONFIG_FILE = "config.properties";
+
+       /**
+        * Getter for manager
+        *
+        * @return Manager instance
+        */
+       public Manageable getManager ();
+
+       /**
+        * Client instance
+        *
+        * @return the client
+        */
+       public Client getClient ();
+
+       /**
+        * Getter for logger
+        *
+        * @return Logger
+        */
+       public Logger getLogger ();
+
+       /**
+        * Application instance
+        *
+        * @return the application
+        */
+       public Application getApplication ();
+
+       /**
+        * Getter for human-readable string from given key
+        *
+        * @param key Key to return
+        * @return Human-readable message
+        */
+       public String getMessageStringFromKey (final String key);
+
+       /**
+        * Logs given exception
+        *
+        * @param exception Exception to log
+        */
+       public void logException (final Throwable exception);
+
+       /**
+        * Checks if given boolean field is available and set to same value
+        *
+        * @param columnName Column name to check
+        * @param bool Boolean value
+        * @return Whether all conditions are met
+        */
+       public boolean isValueEqual (final String columnName, final boolean bool);
+
+       /**
+        * Some "getter for a value from given column name. This name will be
+        * translated into a method name and then this method is called.
+        *
+        * @param columnName Column name
+        * @return Value from field
+        */
+       public Object getValueFromColumn (final String columnName);
+}
diff --git a/src/org/mxchange/jcore/application/Application.java b/src/org/mxchange/jcore/application/Application.java
new file mode 100644 (file)
index 0000000..1de9965
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2015 Roland Haeder
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.mxchange.jcore.application;
+
+import org.mxchange.jcore.FrameworkInterface;
+
+/**
+ *
+ * @author Roland Haeder
+ */
+public interface Application extends FrameworkInterface {
+
+       /**
+        * Bootstraps the application
+        */
+       public void doBootstrap ();
+
+       /**
+        * Run the main loop
+        */
+       public void doMainLoop ();
+
+       /**
+        * Shutdown the application
+        */
+       public void doShutdown ();
+}
diff --git a/src/org/mxchange/jcore/client/BaseClient.java b/src/org/mxchange/jcore/client/BaseClient.java
new file mode 100644 (file)
index 0000000..dedc3fa
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2015 Roland Haeder
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.mxchange.jcore.client;
+
+import org.mxchange.jcore.BaseFrameworkSystem;
+
+/**
+ * A general client
+ *
+ * @author Roland Haeder
+ */
+public abstract class BaseClient extends BaseFrameworkSystem {
+
+       /**
+        * Application is not running by default
+        */
+       private boolean isRunning;
+
+       /**
+        * No instances can be created of this class
+        */
+       protected BaseClient () {
+       }
+
+       /**
+        * Shutdown method for all clients
+        */
+       public void doShutdown () {
+               // Trace message
+               this.getLogger().trace("CALLED!"); //NOI18N
+
+               // Disable client
+               this.disableIsRunning();
+
+               // Shuts down contact manager
+               this.getManager().doShutdown();
+
+               // Trace message
+               this.getLogger().trace("EXIT!"); //NOI18N
+       }
+
+       /**
+        * Enables the client
+        */
+       public final void enableIsRunning () {
+               this.isRunning = true;
+       }
+
+       /**
+        * Determines whether the application is still active by checking some
+        * conditions
+        *
+        * @return Whether the application is still active
+        */
+       public final boolean isRunning () {
+               // In console client, 0 may have been used
+               return this.isRunning;
+       }
+
+       /**
+        * Disables the client
+        */
+       protected final void disableIsRunning () {
+               this.isRunning = false;
+       }
+}
diff --git a/src/org/mxchange/jcore/client/Client.java b/src/org/mxchange/jcore/client/Client.java
new file mode 100644 (file)
index 0000000..7a917d0
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2015 Roland Haeder
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.mxchange.jcore.client;
+
+import org.mxchange.jcore.FrameworkInterface;
+
+/**
+ * An interface for application clients
+ *
+ * @author Roland Haeder
+ */
+public interface Client extends FrameworkInterface {
+
+       /**
+        * Shuts down the client and therefore whole application
+        */
+       public void doShutdown ();
+
+       /**
+        * Displays a message to the user
+        *
+        * @param message Message to show to the user
+        */
+       public void outputMessage (final String message);
+
+       /**
+        * Enables isRunning attribute which singals that the client is running
+        */
+       public void enableIsRunning ();
+
+       /**
+        * Determines whether the client is still active by checking some conditions
+        *
+        * @return Whether the client is still active
+        */
+       public boolean isRunning ();
+
+       /**
+        * Shows introduction to user
+        */
+       public void showWelcome ();
+
+       /**
+        * Inizializes this client
+        */
+       public void init ();
+}
diff --git a/src/org/mxchange/jcore/database/backend/BaseDatabaseBackend.java b/src/org/mxchange/jcore/database/backend/BaseDatabaseBackend.java
new file mode 100644 (file)
index 0000000..5ef2506
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2015 Roland Haeder
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.mxchange.jcore.database.backend;
+
+import java.sql.Driver;
+import java.sql.DriverManager;
+import java.text.MessageFormat;
+import java.util.Enumeration;
+import org.mxchange.jcore.exceptions.UnsupportedDatabaseDriverException;
+import org.mxchange.jcore.BaseFrameworkSystem;
+
+/**
+ * Generall database backend
+ *
+ * @author Roland Haeder
+ */
+public class BaseDatabaseBackend extends BaseFrameworkSystem {
+
+       /**
+        * No instances from this class
+        */
+       protected BaseDatabaseBackend () {
+       }
+
+       /**
+        * Validates driver name and throws an exception if the driver is not valid
+        *
+        * @param driverName Driver name (e.g. "mysql")
+        * @throws org.mxchange.addressbook.exceptions.UnsupportedDatabaseDriverException If the given driver name cannot be solved into a driver instance
+        */
+       protected void validateDriver (final String driverName) throws UnsupportedDatabaseDriverException {
+               // Trace message
+               this.getLogger().trace(MessageFormat.format("driverName={0} - CALLED!", driverName)); //NOI18N
+
+               // Try to find the driver in driver list
+               Enumeration<Driver> drivers = DriverManager.getDrivers();
+
+               // Default is not found
+               boolean isFound = false;
+
+               // Search for it
+               while (drivers.hasMoreElements()) {
+                       // Get element
+                       Driver driver = drivers.nextElement();
+
+                       // Debug message
+                       this.getLogger().debug(MessageFormat.format("Driver {0} is installed.", driver)); //NOI18N
+
+                       // Get class name
+                       String className = driver.getClass().getName();
+
+                       // Is this wanted?
+                       if (className.contains(driverName)) {
+                               // Debug message
+                               this.getLogger().debug("Found driver!"); //NOI18N
+
+                               // Found it
+                               isFound = true;
+                               break;
+                       }
+               }
+
+               // Is it found?
+               if (!isFound) {
+                       // Throw exception
+                       throw new UnsupportedDatabaseDriverException(driverName);
+               }
+
+               // Trace message
+               this.getLogger().trace("EXIT!"); //NOI18N
+       }
+}
diff --git a/src/org/mxchange/jcore/database/backend/DatabaseBackend.java b/src/org/mxchange/jcore/database/backend/DatabaseBackend.java
new file mode 100644 (file)
index 0000000..c7fa70e
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2015 Roland Haeder
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.mxchange.jcore.database.backend;
+
+import java.io.IOException;
+import java.sql.SQLException;
+import java.util.Iterator;
+import org.mxchange.jcore.FrameworkInterface;
+import org.mxchange.jcore.database.storage.Storeable;
+import org.mxchange.jcore.exceptions.BadTokenException;
+
+/**
+ * A generic interface for database frontends
+ *
+ * @author Roland Haeder
+ */
+public interface DatabaseBackend extends FrameworkInterface {
+
+       /**
+        * Tries a connection to the database
+        * 
+        * @throws java.sql.SQLException If the connection attempt fails
+        */
+       public void connectToDatabase () throws SQLException;
+
+       /**
+        * Shuts down this backend
+        */
+       public void doShutdown ();
+
+       /**
+        * Some "getter" for row index from given boolean row value
+        *
+        * @param columnName Name of column
+        * @param bool Boolean value to look for
+        * @return Row index
+        */
+       public int getRowIndexFromColumn (final String columnName, final boolean bool);
+
+       /**
+        * Some "getter" for total table row count
+        * 
+        * @return Total row count
+        * @throws java.sql.SQLException If an SQL error occurs
+        */
+       public int getTotalCount () throws SQLException;
+
+       /**
+        * Checks whether at least one row is found with given boolean value.
+        *
+        * @param columnName Column to check for boolean value
+        * @param bool Boolean value to check
+        * @return Whether boolean value is found and returns at least one row
+        * @throws java.sql.SQLException If an SQL error occurs
+        */
+       public boolean isRowFound (final String columnName, final boolean bool) throws SQLException;
+
+       /**
+        * Rewinds backend
+        */
+       public void rewind ();
+
+       /**
+        * Get length of underlaying file
+        *
+        * @return Length of underlaying file
+        */
+       public long length ();
+
+       /**
+        * Stores an object in the database.
+        *
+        * @param object Object to store in database
+        * @throws java.io.IOException From inner class
+        */
+       public void store (final Storeable object) throws IOException;
+
+       /**
+        * Gets an iterator for contacts
+        *
+        * @return Iterator for contacts
+        * @throws org.mxchange.addressbook.exceptions.BadTokenException If the CSV token is badly formulated
+        */
+       public Iterator<? extends Storeable> iterator () throws BadTokenException;
+
+       /**
+        * Reads a single row from database.
+        * 
+        * @param rowIndex Row index (or how much to skip)
+        * @return A Storeable instance
+        * @throws org.mxchange.addressbook.exceptions.BadTokenException If a token was badly formatted
+        */
+       public Storeable readRow (final int rowIndex) throws BadTokenException;
+}
diff --git a/src/org/mxchange/jcore/database/backend/base64/Base64CsvDatabaseBackend.java b/src/org/mxchange/jcore/database/backend/base64/Base64CsvDatabaseBackend.java
new file mode 100644 (file)
index 0000000..fb46eda
--- /dev/null
@@ -0,0 +1,561 @@
+/*
+ * Copyright (C) 2015 Roland Haeder
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.mxchange.jcore.database.backend.base64;
+
+import java.io.DataOutput;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.sql.SQLException;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import javax.xml.bind.DatatypeConverter;
+import org.mxchange.jcore.FrameworkInterface;
+import org.mxchange.jcore.database.backend.BaseDatabaseBackend;
+import org.mxchange.jcore.database.backend.DatabaseBackend;
+import org.mxchange.jcore.database.frontend.DatabaseFrontend;
+import org.mxchange.jcore.database.storage.Storeable;
+import org.mxchange.jcore.database.storage.csv.StoreableCsv;
+import org.mxchange.jcore.exceptions.BadTokenException;
+
+/**
+ * A database backend with CSV file as storage implementation
+ *
+ * @author Roland Haeder
+ */
+public class Base64CsvDatabaseBackend extends BaseDatabaseBackend implements DatabaseBackend {
+
+       /**
+        * Output stream for this storage engine
+        */
+       private RandomAccessFile storageFile;
+
+       /**
+        * Constructor with table name
+        *
+        * @param tableName Name of "table"
+        * @param wrapper Wrapper instance to call back
+        */
+       public Base64CsvDatabaseBackend (final String tableName, final DatabaseFrontend wrapper) {
+               // Trace message
+               this.getLogger().trace(MessageFormat.format("tableName={0},wrapper={1}", tableName, wrapper)); //NOI18N
+
+               // Debug message
+               this.getLogger().debug(MessageFormat.format("Trying to initialize table {0} ...", tableName)); //NOI18N
+
+               // Set table name here, too
+               this.setTableName(tableName);
+
+               // Set wrapper here
+               this.setWrapper(wrapper);
+
+               // Construct file name
+               String fileName = String.format("data/table_%s.b64", tableName); //NOI18N
+
+               // Debug message
+               this.getLogger().debug(MessageFormat.format("Trying to open file {0} ...", fileName)); //NOI18N
+
+               try {
+                       // Try to initialize the storage (file instance)
+                       this.storageFile = new RandomAccessFile(fileName, "rw"); //NOI18N
+               } catch (final FileNotFoundException ex) {
+                       // Did not work
+                       this.getLogger().error(MessageFormat.format("File {0} cannot be opened: {1}", fileName, ex.toString())); //NOI18N
+                       System.exit(1);
+               }
+
+               // Output message
+               this.getLogger().debug(MessageFormat.format("Database for {0} has been initialized.", tableName)); //NOI18N
+       }
+
+       /**
+        * This database backend does not need to connect
+        */
+       @Override
+       public void connectToDatabase () throws SQLException {
+               // Empty body
+       }
+
+       /**
+        * Shuts down this backend
+        */
+       @Override
+       public void doShutdown () {
+               // Trace message
+               this.getLogger().trace("CALLED!"); //NOI18N
+
+               try {
+                       // Close file
+                       this.getStorageFile().close();
+               } catch (final IOException ex) {
+                       // Abort program
+                       this.abortProgramWithException(ex);
+               }
+
+               // Trace message
+               this.getLogger().trace("EXIT!"); //NOI18N
+       }
+
+       /**
+        * Some "getter" for row index from given boolean row value
+        *
+        * @param columnName Name of column
+        * @param bool Boolean value to look for
+        * @return Row index
+        */
+       @Override
+       public int getRowIndexFromColumn (final String columnName, final boolean bool) {
+               // Trace message
+               this.getLogger().trace(MessageFormat.format("columnName={0},bool={1} - CALLED!", columnName, bool)); //NOI18N
+
+               // Row indexes start with zero
+               int rowIndex = 0;
+
+               // First rewind
+               this.rewind();
+
+               // Try to find the proper row
+               while (!this.isEndOfFile()) {
+                       // Read line
+                       String line = this.readLine();
+
+                       // Debug message
+                       this.getLogger().debug(MessageFormat.format("line={0}", line)); //NOI18N
+
+                       // Callback the wrapper to handle parsing
+                       try {
+                               Storeable storeable = this.getWrapper().parseLineToStoreable(line);
+
+                               // Debug message
+                               this.getLogger().debug(MessageFormat.format("storeable={0}", storeable)); //NOI18N
+
+                               // Is the value qual
+                               if (storeable.isValueEqual(columnName, bool)) {
+                                       // Debug message
+                                       this.getLogger().debug(MessageFormat.format("Found storeable={0} for columnName={1} and bool={2}", storeable, columnName, bool)); //NOI18N
+
+                                       // Found it
+                                       break;
+                               }
+                       } catch (final BadTokenException ex) {
+                               // Bad token found
+                               this.abortProgramWithException(ex);
+                       }
+
+                       // Count up
+                       rowIndex++;
+               }
+
+               // Return it
+               return rowIndex;
+       }
+
+       /**
+        * Some "getter" for total row count
+        *
+        * @return Total row count
+        */
+       @Override
+       public int getTotalCount () {
+               // Trace message
+               this.getLogger().trace("CALLED!"); //NOI18N
+
+               try {
+                       // Do a deprecated call
+                       // @todo this needs rewrite!
+                       return this.readList().size();
+               } catch (final BadTokenException ex) {
+                       this.abortProgramWithException(ex);
+               }
+
+               // Invalid return
+               this.getLogger().trace("Returning -1 ... : EXIT!"); //NOI18N
+               return -1;
+       }
+
+       /**
+        * Checks whether at least one row is found with given boolean value.
+        *
+        * @param columnName Column to check for boolean value
+        * @param bool Boolean value to check
+        * @return Whether boolean value is found and returns at least one row
+        */
+       @Override
+       public boolean isRowFound (final String columnName, final boolean bool) {
+               // Trace message
+               this.getLogger().trace(MessageFormat.format("columnName={0},bool={1} - CALLED!", columnName, bool)); //NOI18N
+
+               // Is at least one entry found?
+               if (this.getTotalCount() == 0) {
+                       // No entry found at all
+                       return false;
+               }
+
+               // Default is not found
+               boolean isFound = false;
+
+               // Firsr rewind
+               this.rewind();
+
+               // Then loop through all lines
+               while (!this.isEndOfFile()) {
+                       // Read line
+                       String line = this.readLine();
+
+                       // Debug message
+                       this.getLogger().debug(MessageFormat.format("line={0}", line)); //NOI18N
+
+                       try {
+                               // And parse it to a Contact instance
+                               Storeable storeable = this.getWrapper().parseLineToStoreable(line);
+
+                               // Debug message
+                               this.getLogger().debug(MessageFormat.format("storeable={0}", storeable)); //NOI18N
+
+                               // This should not be null
+                               if (storeable == null) {
+                                       // Throw exception
+                                       throw new NullPointerException("storeable is null"); //NOI18N
+                               }
+
+                               // Now let the contact object check if it has such attribute
+                               if (storeable.isValueEqual(columnName, bool)) {
+                                       // Yes, it is set
+                                       isFound = true;
+                                       break;
+                               }
+                       } catch (final BadTokenException ex) {
+                               // Don't continue with bad data
+                               this.abortProgramWithException(ex);
+                       }
+               }
+
+               // Trace message
+               this.getLogger().trace(MessageFormat.format("isFound={0} - EXIT!", isFound)); //NOI18N
+
+               // Return result
+               return isFound;
+       }
+
+       /**
+        * Gets an iterator for contacts
+        *
+        * @return Iterator for contacts
+        * @throws org.mxchange.addressbook.exceptions.BadTokenException If the
+        * underlaying method has found an invalid token
+        */
+       @Override
+       public Iterator<? extends Storeable> iterator () throws BadTokenException {
+               // Trace message
+               this.getLogger().trace("CALLED!"); //NOI18N
+
+               /*
+                * Then read the file into RAM (yes, not perfect for >1000 entries ...)
+                * and get a List back.
+                */
+               List<? extends Storeable> list = this.readList();
+
+               // List must be set
+               assert (list instanceof List) : "list has not been set."; //NOI18N
+
+               // Trace message
+               this.getLogger().trace(MessageFormat.format("list.iterator()={0} - EXIT!", list.iterator())); //NOI18N
+
+               // Get iterator from list and return it
+               return list.iterator();
+       }
+
+       /**
+        * Get length of underlaying file
+        *
+        * @return Length of underlaying file
+        */
+       @Override
+       public long length () {
+               long length = 0;
+
+               try {
+                       length = this.getStorageFile().length();
+                       this.getLogger().debug(MessageFormat.format("length={0}", length)); //NOI18N
+               } catch (final IOException ex) {
+                       // Length cannot be determined
+                       // Abort program
+                       this.abortProgramWithException(ex);
+               }
+
+               // Return result
+               this.getLogger().trace(MessageFormat.format("length={0} : EXIT!", length)); //NOI18N
+               return length;
+       }
+
+       /**
+        * Reads a single row from database.
+        *
+        * @param rowIndex Row index (or how much to skip)
+        * @return A Storeable instance
+        * @throws org.mxchange.addressbook.exceptions.BadTokenException If a token
+        * was badly formatted
+        */
+       @Override
+       public Storeable readRow (final int rowIndex) throws BadTokenException {
+               // First rewind
+               this.rewind();
+
+               // Intialize variables
+               int count = -1;
+               Storeable storeable = null;
+
+               // Read all rows
+               while (!this.isEndOfFile() || (count < rowIndex)) {
+                       // Read row
+                       String line = this.readLine();
+
+                       // Debug message
+                       this.getLogger().debug(MessageFormat.format("line={0}", line)); //NOI18N
+
+                       // Callback the wrapper to handle parsing
+                       storeable = this.getWrapper().parseLineToStoreable(line);
+
+                       // Debug message
+                       this.getLogger().debug(MessageFormat.format("storeable={0}", storeable)); //NOI18N
+
+                       // Increment counter
+                       count++;
+               }
+
+               // Trace message
+               this.getLogger().trace(MessageFormat.format("storeable={0} - EXIT!", storeable)); //NOI18N
+               // Return found element
+               return storeable;
+       }
+
+       /**
+        * Rewinds backend
+        */
+       @Override
+       public void rewind () {
+               // Trace message
+               this.getLogger().trace("CALLED!"); //NOI18N
+
+               try {
+                       // Rewind underlaying database file
+                       this.getStorageFile().seek(0);
+               } catch (final IOException ex) {
+                       // Abort program
+                       this.abortProgramWithException(ex);
+               }
+
+               // Trace message
+               this.getLogger().trace("EXIT!"); //NOI18N
+       }
+
+       /**
+        * Stores given object by "visiting" it
+        *
+        * @param object An object implementing Storeable
+        * @throws java.io.IOException From "inner" class
+        */
+       @Override
+       public void store (final Storeable object) throws IOException {
+               // Trace message
+               this.getLogger().trace(MessageFormat.format("object={0} - CALLED!", object)); //NOI18N
+
+               // Object must not be null
+               if (object == null) {
+                       // Abort here
+                       throw new NullPointerException("object is null"); //NOI18N
+               }
+
+               // Make sure the instance is there (DataOutput flawor)
+               assert (this.storageFile instanceof DataOutput);
+
+               // Try to cast it, this will fail if the interface is not implemented
+               StoreableCsv csv = (StoreableCsv) object;
+
+               // Now get a string from the object that needs to be stored
+               String str = csv.getCsvStringFromStoreableObject();
+
+               // Debug message
+               this.getLogger().debug(MessageFormat.format("str({0})={1}", str.length(), str)); //NOI18N
+
+               // Encode line in BASE-64
+               String encoded = DatatypeConverter.printBase64Binary(str.getBytes());
+
+               // The string is now a valid CSV string
+               this.getStorageFile().write(encoded.getBytes());
+
+               // Trace message
+               this.getLogger().trace("EXIT!"); //NOI18N
+       }
+
+       /**
+        * Adds given contact to list
+        *
+        * @param instance An instance of FrameworkInterface to add
+        * @param list List instance
+        */
+       private void addToList (final Storeable instance, final List<Storeable> list) {
+               // Trace message
+               this.getLogger().trace(MessageFormat.format("contact={0} - CALLED!", instance)); //NOI18N
+
+               // No null here
+               if (instance == null) {
+                       // Throw exception
+                       throw new NullPointerException("contact is null"); //NOI18N
+               } else if (list == null) {
+                       // Throw exception
+                       throw new NullPointerException("list is null"); //NOI18N
+               }
+
+               // Debug message
+               this.getLogger().debug(MessageFormat.format("contact={0}", instance)); //NOI18N
+
+               // Is the contact read?
+               if (instance instanceof FrameworkInterface) {
+                       // Then add it
+                       boolean added = list.add(instance);
+
+                       // Debug message
+                       this.getLogger().debug(MessageFormat.format("contact={0} added={1}", instance, added)); //NOI18N
+
+                       // Has it been added?
+                       if (!added) {
+                               // Not added
+                               this.getLogger().warn("Contact object has not been added."); //NOI18N
+                       }
+               }
+
+               // Trace message
+               this.getLogger().trace("EXIT!"); //NOI18N
+       }
+
+       /**
+        * Returns storage file
+        *
+        * @return Storage file instance
+        */
+       private RandomAccessFile getStorageFile () {
+               return this.storageFile;
+       }
+
+       /**
+        * Checks whether end of file has been reached
+        *
+        * @return Whether lines are left to read
+        */
+       private boolean isEndOfFile () {
+               // Default is EOF
+               boolean isEof = true;
+
+               try {
+                       isEof = (this.getStorageFile().getFilePointer() >= this.length());
+               } catch (final IOException ex) {
+                       // Length cannot be determined
+                       this.getLogger().catching(ex);
+               }
+
+               // Return status
+               this.getLogger().trace(MessageFormat.format("isEof={0} : EXIT!", isEof)); //NOI18N
+               return isEof;
+       }
+
+       /**
+        * Reads a line from file base
+        *
+        * @return Read line from file
+        */
+       private String readLine () {
+               // Trace message
+               this.getLogger().trace("CALLED!"); //NOI18N
+
+               // Init input
+               String input = null;
+
+               try {
+                       // Read single line
+                       String base64 = this.getStorageFile().readLine();
+
+                       // Is the line null?
+                       if (base64 == null) {
+                               // Then throw NPE here
+                               throw new NullPointerException("base64 is null"); //NOI18N
+                       }
+
+                       // Decode BASE-64
+                       byte[] decoded = DatatypeConverter.parseBase64Binary(base64);
+
+                       // Convert to string
+                       input = new String(decoded);
+               } catch (final IOException ex) {
+                       this.getLogger().catching(ex);
+               }
+
+               // Trace message
+               this.getLogger().trace(MessageFormat.format("input={0} - EXIT!", input)); //NOI18N
+
+               // Return read string or null
+               return input;
+       }
+
+       /**
+        * Reads the database file, if available, and adds all read lines into the
+        * list.
+        *
+        * @return A list with Contact instances
+        */
+       private List<? extends Storeable> readList () throws BadTokenException {
+               this.getLogger().trace("CALLED!"); //NOI18N
+
+               // First rewind
+               this.rewind();
+
+               // Get file size and divide it by 140 (possible average length of one line)
+               int lines = Math.round(this.length() / 140 + 0.5f);
+
+               // Debug message
+               this.getLogger().debug(MessageFormat.format("lines={0}", lines)); //NOI18N
+
+               // Instance list
+               // @TODO The maximum length could be guessed from file size?
+               List<Storeable> list = new ArrayList<>(lines);
+
+               // Init variables
+               String line;
+               Storeable instance = null;
+
+               // Read all lines
+               while (!this.isEndOfFile()) {
+                       // Then read a line
+                       line = this.readLine();
+
+                       // Parse line
+                       instance = this.getWrapper().parseLineToStoreable(line);
+
+                       // The contact instance should be there now
+                       assert (instance instanceof FrameworkInterface) : MessageFormat.format("instance is not set: {0}", instance); //NOI18N
+
+                       // Add contact
+                       this.addToList(instance, list);
+               }
+
+               // Return finished list
+               this.getLogger().trace(MessageFormat.format("list.size()={0} : EXIT!", list.size())); //NOI18N
+               return list;
+       }
+}
diff --git a/src/org/mxchange/jcore/database/backend/mysql/MySqlDatabaseBackend.java b/src/org/mxchange/jcore/database/backend/mysql/MySqlDatabaseBackend.java
new file mode 100644 (file)
index 0000000..4fe807c
--- /dev/null
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) 2015 Roland Haeder
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.mxchange.jcore.database.backend.mysql;
+
+import java.io.IOException;
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.text.MessageFormat;
+import java.util.Iterator;
+import org.mxchange.jcore.database.backend.BaseDatabaseBackend;
+import org.mxchange.jcore.database.backend.DatabaseBackend;
+import org.mxchange.jcore.database.storage.Storeable;
+import org.mxchange.jcore.exceptions.BadTokenException;
+import org.mxchange.jcore.exceptions.UnsupportedDatabaseDriverException;
+
+/**
+ * A backend class for MySQL connections
+ *
+ * @author Roland Haeder
+ */
+public class MySqlDatabaseBackend extends BaseDatabaseBackend implements DatabaseBackend {
+       /**
+        * An instance of a datbase connection
+        */
+       private static Connection connection;
+
+       /**
+        * Prepared statement for full row count
+        */
+       private PreparedStatement totalRowCount;
+
+       /**
+        * Constructor with table name
+        * 
+        * @param tableName Table to access
+        * @throws org.mxchange.addressbook.exceptions.UnsupportedDatabaseDriverException
+        */
+       public MySqlDatabaseBackend (final String tableName) throws UnsupportedDatabaseDriverException {
+               // Validate driver
+               this.validateDriver("mysql"); //NOI18N
+
+               // Now that the driver is there, set the table name
+               this.setTableName(tableName);
+       }
+
+       @Override
+       public void connectToDatabase () throws SQLException {
+               // Trace message
+               this.getLogger().trace("CALLED!"); //NOI18N
+
+               // Is the connection already there?
+               if (MySqlDatabaseBackend.connection instanceof Connection) {
+                       // Already connected
+                       this.getLogger().debug("Connection is already established."); //NOI18N
+
+                       // No need to connect
+                       return;
+               }
+
+               // Generate connection string
+               String connect = String.format("jdbc:mysql://%s/%s", //NOI18N
+                               this.getProperty("database.mysql.host"), //NOI18N
+                               this.getProperty("database.mysql.dbname") //NOI18N
+               );
+
+               // Debug message
+               this.getLogger().debug(MessageFormat.format("Attempting to connect to {0} ...", connect)); //NOI18N
+
+               // Now get a connection instance back
+               MySqlDatabaseBackend.connection = DriverManager.getConnection(
+                               connect,
+                               this.getProperty("database.mysql.login"), //NOI18N
+                               this.getProperty("database.mysql.password") //NOI18N
+               );
+
+               // Is the connection really up?
+               if (MySqlDatabaseBackend.connection.isClosed()) {
+                       // Connection is closed again
+                       throw new SQLException("Connection is closed."); //NOI18N
+               }
+
+               // Debug message
+               this.getLogger().debug("Connection is up, preparing some statements ..."); //NOI18N
+
+               // Here, the connection is established, so prepare some statements
+               this.totalRowCount = MySqlDatabaseBackend.connection.prepareStatement(String.format("SELECT COUNT(`id`) AS `cnt` FROM `%s` LIMIT 1", this.getTableName())); //NOI18N
+
+               // Trace message
+               this.getLogger().trace("EXIT!"); //NOI18N
+       }
+
+       @Override
+       public void doShutdown () {
+               // This should not happen:
+               assert(MySqlDatabaseBackend.connection instanceof Connection) : MessageFormat.format("connection is not valid: {0}", MySqlDatabaseBackend.connection); //NOI18N
+
+               try {
+                       // Close down database connection
+                       MySqlDatabaseBackend.connection.close();
+               } catch (final SQLException ex) {
+                       // Something happened during close()
+                       this.abortProgramWithException(ex);
+               }
+       }
+
+       /**
+        * Some "getter" for row index from given boolean row value
+        *
+        * @param columnName Name of column
+        * @param bool Boolean value to look for
+        * @return Row index
+        */
+       @Override
+       public int getRowIndexFromColumn (final String columnName, final boolean bool) {
+               throw new UnsupportedOperationException(MessageFormat.format("columnName={0},bool={1}", columnName, bool));
+       }
+
+       @Override
+       public int getTotalCount () throws SQLException {
+               // Trace message
+               this.getLogger().trace(MessageFormat.format("tableName={0} - CALLED!", this.getTableName())); //NOI18N
+
+               // Nothing counted by default
+               int count = 0;
+
+               // Prepared statements are cool ...
+               if (this.totalRowCount.execute()) {
+                       // Did fully work, so get result set
+                       ResultSet set = this.totalRowCount.getResultSet();
+
+                       // First rewind it
+                       assert(set.last()) : ": last() failed"; //NOI18N
+
+                       // Get integer from 'cnt' alias (see statement)
+                       count = set.getInt("cnt"); //NOI18N
+
+                       // Debug message
+                       this.getLogger().debug(MessageFormat.format("count={0}", count)); //NOI18N
+
+                       // Go back to beginning
+                       set.beforeFirst();
+               } else {
+                       // Empty result
+                       this.getLogger().warn(MessageFormat.format("COUNT() query didn't return any result on table {0}.", this.getTableName())); //NOI18N
+               }
+
+               // Trace message
+               this.getLogger().trace(MessageFormat.format("count={0} - EXIT!", count)); //NOI18N
+
+               // Return result
+               return count;
+       }
+
+       /**
+        * Checks whether at least one row is found with given boolean value.
+        *
+        * @param columnName Column to check for boolean value
+        * @param bool Boolean value to check
+        * @return Whether boolean value is found and returns at least one row
+        */
+       @Override
+       public boolean isRowFound (final String columnName, final boolean bool) throws SQLException {
+               // Is at least one entry found?
+               if (this.getTotalCount() == 0) {
+                       // No entry found at all
+                       return false;
+               }
+               throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+       }
+       
+       @Override
+       public Iterator<? extends Storeable> iterator () throws BadTokenException {
+               throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+       }
+
+       @Override
+       public long length () {
+               throw new UnsupportedOperationException("Not implemented for this backend."); //NOI18N
+       }
+
+       @Override
+       public Storeable readRow (final int rowIndex) {
+               throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+       }
+
+       @Override
+       public void rewind () {
+               throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+       }
+
+       @Override
+       public void store (final Storeable object) throws IOException {
+               throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+       }
+}
diff --git a/src/org/mxchange/jcore/database/frontend/BaseDatabaseFrontend.java b/src/org/mxchange/jcore/database/frontend/BaseDatabaseFrontend.java
new file mode 100644 (file)
index 0000000..a4ab83b
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2015 Roland Haeder
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.mxchange.jcore.database.frontend;
+
+import java.sql.SQLException;
+import org.mxchange.jcore.BaseFrameworkSystem;
+import org.mxchange.jcore.database.backend.DatabaseBackend;
+import org.mxchange.jcore.database.backend.base64.Base64CsvDatabaseBackend;
+import org.mxchange.jcore.database.backend.mysql.MySqlDatabaseBackend;
+import org.mxchange.jcore.exceptions.UnsupportedDatabaseBackendException;
+import org.mxchange.jcore.exceptions.UnsupportedDatabaseDriverException;
+
+/**
+ * General database frontend class
+ *
+ * @author Roland Haeder
+ */
+public abstract class BaseDatabaseFrontend extends BaseFrameworkSystem implements DatabaseFrontend {
+
+       /**
+        * Instance for database backend
+        */
+       private DatabaseBackend backend;
+
+       /**
+        * No instances from this class
+        */
+       protected BaseDatabaseFrontend () {
+       }
+
+       /**
+        * Instance for database backend
+        *
+        * @return the backend
+        */
+       protected final DatabaseBackend getBackend () {
+               return this.backend;
+       }
+
+       /**
+        * Instance for database backend
+        *
+        * @param backend the backend to set
+        */
+       protected final void setBackend (final DatabaseBackend backend) {
+               this.backend = backend;
+       }
+
+       /**
+        * Initialize backend
+        * 
+        * @throws org.mxchange.addressbook.exceptions.UnsupportedDatabaseBackendException If the backend is not supported
+        * @throws java.sql.SQLException If a SQL database backend fails to connect
+        */
+       protected void initBackend () throws UnsupportedDatabaseBackendException, SQLException {
+               // Trace message
+               this.getLogger().trace("CALLED!"); //NOI18N
+
+               // Read property
+               // @TODO rewrite this to own properties file
+               String backendType = this.getProperty("database.backendType"); //NOI18N
+
+               // Try it
+               try {
+                       // Switch on backend type
+                       switch (backendType) {
+                               case "mysql": // MySQL backend, this requires more information //NOI18N
+                                       this.backend = new MySqlDatabaseBackend(this.getTableName());
+                                       break;
+
+                               case "base64csv": // BASE64-encoded CSV rows //NOI18N
+                                       this.backend = new Base64CsvDatabaseBackend(this.getTableName(), this);
+                                       break;
+
+                               default: // Unsupported
+                                       throw new UnsupportedDatabaseBackendException(backendType);
+                       }
+
+                       // Try to run a connect on it
+                       this.backend.connectToDatabase();
+               } catch (final UnsupportedDatabaseDriverException ex) {
+                       // Continue to throw
+                       throw new UnsupportedDatabaseBackendException(backendType, ex);
+               }
+
+               // Trace message
+               this.getLogger().trace("EXIT!"); //NOI18N
+       }
+}
diff --git a/src/org/mxchange/jcore/database/frontend/DatabaseFrontend.java b/src/org/mxchange/jcore/database/frontend/DatabaseFrontend.java
new file mode 100644 (file)
index 0000000..fa779e5
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2015 Roland Haeder
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.mxchange.jcore.database.frontend;
+
+import org.mxchange.jcore.FrameworkInterface;
+import org.mxchange.jcore.database.storage.Storeable;
+import org.mxchange.jcore.exceptions.BadTokenException;
+
+/**
+ * A generic interface for database frontends
+ *
+ * @author Roland Haeder
+ */
+public interface DatabaseFrontend extends FrameworkInterface {
+       /**
+        * Parses given line from database backend into a Storeable instance. Please
+        * note that not all backends need this.
+        *
+        * @param line Line from database backend
+        * @return A Storeable instance
+        * @throws org.mxchange.jcore.exceptions.BadTokenException If a token was badly formatted
+        */
+       public Storeable parseLineToStoreable (final String line) throws BadTokenException;
+}
diff --git a/src/org/mxchange/jcore/database/storage/Storeable.java b/src/org/mxchange/jcore/database/storage/Storeable.java
new file mode 100644 (file)
index 0000000..1e95d8e
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2015 Roland Haeder
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.mxchange.jcore.database.storage;
+
+import org.mxchange.jcore.FrameworkInterface;
+
+/**
+ * An interface for objects being stored in databases
+ *
+ * @author Roland Haeder
+ */
+public interface Storeable extends FrameworkInterface {
+}
diff --git a/src/org/mxchange/jcore/database/storage/csv/StoreableCsv.java b/src/org/mxchange/jcore/database/storage/csv/StoreableCsv.java
new file mode 100644 (file)
index 0000000..431fa79
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2015 Roland Haeder
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.mxchange.jcore.database.storage.csv;
+
+import org.mxchange.jcore.database.storage.Storeable;
+
+/**
+ * An interface for classes which should be storeable as a CSV string
+ *
+ * @author Roland Haeder
+ * @deprecated This method was for an old way of storing data into
+ * comma-separated value files. Now that there is BASE64-encoding, this formating
+ * is no longer needed.
+ */
+@Deprecated
+public interface StoreableCsv extends Storeable {
+
+       /**
+        * Getter for a CSV-formated string from object
+        *
+        * @return
+        * @deprecated See interface deprecation
+        */
+       @Deprecated
+       public String getCsvStringFromStoreableObject ();
+}
diff --git a/src/org/mxchange/jcore/exceptions/BadTokenException.java b/src/org/mxchange/jcore/exceptions/BadTokenException.java
new file mode 100644 (file)
index 0000000..8425c9b
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2015 Roland Haeder
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.mxchange.jcore.exceptions;
+
+import java.text.MessageFormat;
+
+/**
+ * This exception is thrown when a token has been badly formated. This may
+ * happen when a CSV file is broken.
+ *
+ * @author Roland Haeder
+ */
+public class BadTokenException extends Exception {
+
+       /**
+        * Constructor with token and count
+        * @param token Token that is not valid
+        * @param count Count
+        */
+       public BadTokenException (final String token, final int count) {
+               super(MessageFormat.format("Token {0} at position {1} has not double-quotes on both ends.", token, count));
+       }
+
+}
diff --git a/src/org/mxchange/jcore/exceptions/FrameAlreadyInitializedException.java b/src/org/mxchange/jcore/exceptions/FrameAlreadyInitializedException.java
new file mode 100644 (file)
index 0000000..83a3dd0
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2015 Roland Haeder
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.mxchange.jcore.exceptions;
+
+/**
+ * This exception is thrown when initFrame() is called twice.
+ *
+ * @author Roland Haeder
+ */
+public class FrameAlreadyInitializedException extends Exception {
+
+       /**
+        * Default constructor
+        */
+       public FrameAlreadyInitializedException () {
+       }
+
+}
diff --git a/src/org/mxchange/jcore/exceptions/UnhandledUserChoiceException.java b/src/org/mxchange/jcore/exceptions/UnhandledUserChoiceException.java
new file mode 100644 (file)
index 0000000..70300f2
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2015 Roland Haeder
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.mxchange.jcore.exceptions;
+
+/**
+ * This exception is thrown when the user made a valid choice but it was not
+ * handled by the program.
+ *
+ * @author Roland Haeder
+ */
+public class UnhandledUserChoiceException extends Exception {
+
+       /**
+        *
+        * @param message
+        */
+       public UnhandledUserChoiceException (final String message) {
+               super(message);
+       }
+}
diff --git a/src/org/mxchange/jcore/exceptions/UnsupportedDatabaseBackendException.java b/src/org/mxchange/jcore/exceptions/UnsupportedDatabaseBackendException.java
new file mode 100644 (file)
index 0000000..daceeb4
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2015 Roland Haeder
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.mxchange.jcore.exceptions;
+
+import java.text.MessageFormat;
+
+/**
+ * An exception thrown when the given backend type is not valid
+ * 
+ * @author Roland Haeder
+ */
+public class UnsupportedDatabaseBackendException extends Exception {
+
+       /**
+        *
+        * @param backendType
+        */
+       public UnsupportedDatabaseBackendException (final String backendType) {
+               // Call super constructor
+               super(MessageFormat.format("Backend {0} is not supported.", backendType)); //NOI18N
+       }
+
+       /**
+        * Constructor with backend type and cause
+        *
+        * @param backendType Backend type
+        * @param cause 
+        */
+       public UnsupportedDatabaseBackendException (final String backendType, final Throwable cause) {
+               // Call super constructor
+               super(MessageFormat.format("Backend {0} is not supported.", backendType), cause); //NOI18N
+       }
+       
+}
diff --git a/src/org/mxchange/jcore/exceptions/UnsupportedDatabaseDriverException.java b/src/org/mxchange/jcore/exceptions/UnsupportedDatabaseDriverException.java
new file mode 100644 (file)
index 0000000..3cc925d
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2015 Roland Haeder
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.mxchange.jcore.exceptions;
+
+import java.text.MessageFormat;
+
+/**
+ * Thrown when the given driver is not found
+ *
+ * @author Roland Haeder
+ */
+public class UnsupportedDatabaseDriverException extends Exception {
+
+       /**
+        * Default constructor with driver name
+        * @param driverName 
+        */
+       public UnsupportedDatabaseDriverException (final String driverName) {
+               // Call super method
+               super(MessageFormat.format("Database driver {0} is not found.", driverName));
+       }
+       
+}
diff --git a/src/org/mxchange/jcore/manager/BaseManager.java b/src/org/mxchange/jcore/manager/BaseManager.java
new file mode 100644 (file)
index 0000000..19dc182
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2015 Roland Haeder
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.mxchange.jcore.manager;
+
+import org.mxchange.jcore.BaseFrameworkSystem;
+
+/**
+ * A general manager
+ *
+ * @author Roland Haeder
+ * @version 0.0
+ */
+public abstract class BaseManager extends BaseFrameworkSystem implements Manageable {
+
+       /**
+        * No instances can be created of this class
+        */
+       protected BaseManager () {
+       }
+}
diff --git a/src/org/mxchange/jcore/manager/Manageable.java b/src/org/mxchange/jcore/manager/Manageable.java
new file mode 100644 (file)
index 0000000..5e7fa1b
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2015 Roland Haeder
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.mxchange.jcore.manager;
+
+import org.mxchange.jcore.FrameworkInterface;
+
+/**
+ *
+ * @author Roland Haeder
+ */
+public interface Manageable extends FrameworkInterface {
+
+       /**
+        * Shuts down this contact manager
+        */
+       public void doShutdown ();
+}
diff --git a/src/org/mxchange/jcore/manager/application/ApplicationManager.java b/src/org/mxchange/jcore/manager/application/ApplicationManager.java
new file mode 100644 (file)
index 0000000..ecbfff7
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2015 Roland Haeder
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.mxchange.jcore.manager.application;
+
+import org.mxchange.jcore.application.Application;
+import org.mxchange.jcore.manager.BaseManager;
+
+/**
+ * Application manager
+ * 
+ * @author Roland Haeder
+ */
+public class ApplicationManager extends BaseManager implements ManageableApplication {
+
+       /**
+        * Getter for application manager
+        *
+        * @param application An instance of a Application class
+        * @return
+        */
+       public static final ManageableApplication getManager (final Application application) {
+               // Application instance must be set
+               if (application == null) {
+                       // Abort here
+                       throw new NullPointerException("application is null"); //NOI18N
+               }
+
+               // Get manager
+               ManageableApplication manager = new ApplicationManager(application);
+
+               // Return manager
+               return manager;
+       }
+
+       /**
+        * Constructor for this manager
+        *
+        * @param application An instance of an Application class
+        */
+       private ApplicationManager (final Application application) {
+               // Application instance must be set
+               if (application == null) {
+                       // Abort here
+                       throw new NullPointerException("application is null"); //NOI18N
+               }
+
+               // Trace message
+               this.getLogger().trace("CALLED!"); //NOI18N
+
+               // Set application instance
+               this.setApplication(application);
+       }
+
+       @Override
+       public void doShutdown () {
+               // Shutdown this manager, for now nothing
+               // @TODO Maybe add something here?
+       }
+
+       @Override
+       public void start () {
+               // Trace message
+               this.getLogger().trace("CALLED!"); //NOI18N
+
+               // Bootstrap application
+               this.getApplication().doBootstrap();
+
+               // Run the main loop
+               this.getApplication().doMainLoop();
+
+               // Trace message
+               this.getLogger().trace("EXIT!"); //NOI18N
+       }
+}
diff --git a/src/org/mxchange/jcore/manager/application/ManageableApplication.java b/src/org/mxchange/jcore/manager/application/ManageableApplication.java
new file mode 100644 (file)
index 0000000..5a3460e
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2015 Roland Haeder
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.mxchange.jcore.manager.application;
+
+import org.mxchange.jcore.manager.Manageable;
+
+/**
+ *
+ * @author Roland Haeder
+ */
+public interface ManageableApplication extends Manageable {
+
+       /**
+        * Launches application
+        */
+       public void start ();
+}
diff --git a/src/org/mxchange/jcore/model/BaseModel.java b/src/org/mxchange/jcore/model/BaseModel.java
new file mode 100644 (file)
index 0000000..821d57c
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2015 Roland Haeder
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.mxchange.jcore.model;
+
+import java.text.MessageFormat;
+import javax.swing.event.EventListenerList;
+import javax.swing.event.ListDataListener;
+import javax.swing.event.TableModelListener;
+import org.mxchange.jcore.BaseFrameworkSystem;
+
+/**
+ *
+ * @author Roland Haeder
+ */
+public class BaseModel extends BaseFrameworkSystem {
+
+       /**
+        * List of event listeners
+        */
+       private final EventListenerList eventListenerList;
+
+       /**
+        * Protected constructor
+        */
+       protected BaseModel () {
+               // Trace message
+               this.getLogger().trace("CALLED!"); //NOI18N
+
+               // Init listener list
+               this.eventListenerList = new EventListenerList();
+       }
+
+       /**
+        * Adds a lister of this type to the list
+        *
+        * @param listener Listener instance
+        */
+       public void addListDataListener (final ListDataListener listener) {
+               // Trace message
+               this.getLogger().trace("listener=" + listener + " - CALLED!"); //NOI18N
+
+               // Listener must not be null
+               if (listener == null) {
+                       // Abort here
+                       throw new NullPointerException("listener is null");
+               }
+
+               // Debug message
+               this.getLogger().debug(MessageFormat.format("Adding listener {0} ...", listener.getClass()));
+
+               // Remove listener
+               this.eventListenerList.add(ListDataListener.class, listener);
+
+               // Trace message
+               this.getLogger().trace("EXIT!"); //NOI18N
+       }
+
+       /**
+        * Adds a TableModel listener instance to the event list.
+        *
+        * @param listener Lister instance
+        */
+       public void addTableModelListener (final TableModelListener listener) {
+               // Trace message
+               this.getLogger().trace("listener=" + listener + " - CALLED!"); //NOI18N
+
+               // Listener must not be null
+               if (listener == null) {
+                       // Abort here
+                       throw new NullPointerException("listener is null");
+               }
+
+               // Debug message
+               this.getLogger().debug(MessageFormat.format("Adding listener {0} ...", listener.getClass()));
+
+               // Add listener
+               this.eventListenerList.add(TableModelListener.class, listener);
+
+               // Trace message
+               this.getLogger().trace("EXIT!"); //NOI18N
+       }
+
+       /**
+        * Removes given listener
+        *
+        * @param listener Listener instance
+        */
+       public void removeListDataListener (final ListDataListener listener) {
+               // Trace message
+               this.getLogger().trace("listener=" + listener + " - CALLED!"); //NOI18N
+
+               // Listener must not be null
+               if (listener == null) {
+                       // Abort here
+                       throw new NullPointerException("listener is null");
+               }
+
+               // Debug message
+               this.getLogger().debug(MessageFormat.format("Removing listener {0} ...", listener.getClass()));
+
+               // Remove listener
+               this.eventListenerList.remove(ListDataListener.class, listener);
+
+               // Trace message
+               this.getLogger().trace("EXIT!"); //NOI18N
+       }
+
+       /**
+        * Removes a TableModel listener instance from the event list.
+        *
+        * @param listener Listener instance
+        */
+       public void removeTableModelListener (final TableModelListener listener) {
+               // Trace message
+               this.getLogger().trace("listener=" + listener + " - CALLED!"); //NOI18N
+
+               // Listener must not be null
+               if (listener == null) {
+                       // Abort here
+                       throw new NullPointerException("listener is null");
+               }
+
+               // Debug message
+               this.getLogger().debug(MessageFormat.format("Removing listener {0} ...", listener.getClass()));
+
+               // Remove listener
+               this.eventListenerList.remove(TableModelListener.class, listener);
+
+               // Trace message
+               this.getLogger().trace("EXIT!"); //NOI18N
+       }
+}