--- /dev/null
+/nbproject/
+/manifest.mf
+/build/
+/dist/
+/*.properties
--- /dev/null
+<?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>
--- /dev/null
+libs.CopyLibs.classpath=\
+ ${base}/CopyLibs/org-netbeans-modules-java-j2seproject-copylibstask.jar
+libs.CopyLibs.displayName=CopyLibs Task
+libs.CopyLibs.prop-version=2.0
--- /dev/null
+/*
+ * 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;
+ }
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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 ();
+}
--- /dev/null
+/*
+ * 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;
+ }
+}
--- /dev/null
+/*
+ * 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 ();
+}
--- /dev/null
+/*
+ * 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
+ }
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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;
+ }
+}
--- /dev/null
+/*
+ * 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.
+ }
+}
--- /dev/null
+/*
+ * 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
+ }
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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 {
+}
--- /dev/null
+/*
+ * 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 ();
+}
--- /dev/null
+/*
+ * 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));
+ }
+
+}
--- /dev/null
+/*
+ * 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 () {
+ }
+
+}
--- /dev/null
+/*
+ * 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);
+ }
+}
--- /dev/null
+/*
+ * 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
+ }
+
+}
--- /dev/null
+/*
+ * 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));
+ }
+
+}
--- /dev/null
+/*
+ * 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 () {
+ }
+}
--- /dev/null
+/*
+ * 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 ();
+}
--- /dev/null
+/*
+ * 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
+ }
+}
--- /dev/null
+/*
+ * 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 ();
+}
--- /dev/null
+/*
+ * 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
+ }
+}