From: Roland Haeder Date: Thu, 6 Aug 2015 06:30:04 +0000 (+0200) Subject: Initial import, mostly from Addressbook project X-Git-Url: https://git.mxchange.org/?a=commitdiff_plain;h=2f76d009395cf2c9603b981f8331a1f1761b1f8f;p=jcore.git Initial import, mostly from Addressbook project Signed-off-by: Roland Häder --- 2f76d009395cf2c9603b981f8331a1f1761b1f8f diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f91a00b --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +/nbproject/ +/manifest.mf +/build/ +/dist/ +/*.properties diff --git a/build.xml b/build.xml new file mode 100644 index 0000000..e4320c2 --- /dev/null +++ b/build.xml @@ -0,0 +1,73 @@ + + + + + + + + + + + Builds, tests, and runs the project jcore. + + + 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 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 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 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 index 0000000..6d0afb5 --- /dev/null +++ b/lib/nblibraries.properties @@ -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 index 0000000..6c5267e --- /dev/null +++ b/src/org/mxchange/jcore/BaseFrameworkSystem.java @@ -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 . + */ +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 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 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) 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 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 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 index 0000000..71ddb00 --- /dev/null +++ b/src/org/mxchange/jcore/FrameworkInterface.java @@ -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 . + */ +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 index 0000000..1de9965 --- /dev/null +++ b/src/org/mxchange/jcore/application/Application.java @@ -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 . + */ +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 index 0000000..dedc3fa --- /dev/null +++ b/src/org/mxchange/jcore/client/BaseClient.java @@ -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 . + */ +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 index 0000000..7a917d0 --- /dev/null +++ b/src/org/mxchange/jcore/client/Client.java @@ -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 . + */ +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 index 0000000..5ef2506 --- /dev/null +++ b/src/org/mxchange/jcore/database/backend/BaseDatabaseBackend.java @@ -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 . + */ +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 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 index 0000000..c7fa70e --- /dev/null +++ b/src/org/mxchange/jcore/database/backend/DatabaseBackend.java @@ -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 . + */ +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 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 index 0000000..fb46eda --- /dev/null +++ b/src/org/mxchange/jcore/database/backend/base64/Base64CsvDatabaseBackend.java @@ -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 . + */ +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 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 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 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 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 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 index 0000000..4fe807c --- /dev/null +++ b/src/org/mxchange/jcore/database/backend/mysql/MySqlDatabaseBackend.java @@ -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 . + */ +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 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 index 0000000..a4ab83b --- /dev/null +++ b/src/org/mxchange/jcore/database/frontend/BaseDatabaseFrontend.java @@ -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 . + */ +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 index 0000000..fa779e5 --- /dev/null +++ b/src/org/mxchange/jcore/database/frontend/DatabaseFrontend.java @@ -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 . + */ +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 index 0000000..1e95d8e --- /dev/null +++ b/src/org/mxchange/jcore/database/storage/Storeable.java @@ -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 . + */ +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 index 0000000..431fa79 --- /dev/null +++ b/src/org/mxchange/jcore/database/storage/csv/StoreableCsv.java @@ -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 . + */ +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 index 0000000..8425c9b --- /dev/null +++ b/src/org/mxchange/jcore/exceptions/BadTokenException.java @@ -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 . + */ +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 index 0000000..83a3dd0 --- /dev/null +++ b/src/org/mxchange/jcore/exceptions/FrameAlreadyInitializedException.java @@ -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 . + */ +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 index 0000000..70300f2 --- /dev/null +++ b/src/org/mxchange/jcore/exceptions/UnhandledUserChoiceException.java @@ -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 . + */ +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 index 0000000..daceeb4 --- /dev/null +++ b/src/org/mxchange/jcore/exceptions/UnsupportedDatabaseBackendException.java @@ -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 . + */ +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 index 0000000..3cc925d --- /dev/null +++ b/src/org/mxchange/jcore/exceptions/UnsupportedDatabaseDriverException.java @@ -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 . + */ +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 index 0000000..19dc182 --- /dev/null +++ b/src/org/mxchange/jcore/manager/BaseManager.java @@ -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 . + */ +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 index 0000000..5e7fa1b --- /dev/null +++ b/src/org/mxchange/jcore/manager/Manageable.java @@ -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 . + */ +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 index 0000000..ecbfff7 --- /dev/null +++ b/src/org/mxchange/jcore/manager/application/ApplicationManager.java @@ -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 . + */ +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 index 0000000..5a3460e --- /dev/null +++ b/src/org/mxchange/jcore/manager/application/ManageableApplication.java @@ -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 . + */ +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 index 0000000..821d57c --- /dev/null +++ b/src/org/mxchange/jcore/model/BaseModel.java @@ -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 . + */ +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 + } +}